Module core::core_simd::intrinsics

source ·
🔬This is a nightly-only experimental API. (portable_simd #86656)
Expand description

This module contains the LLVM intrinsics bindings that provide the functionality for this crate.

The LLVM assembly language is documented here: https://llvm.org/docs/LangRef.html

A quick glossary of jargon that may appear in this module, mostly paraphrasing LLVM’s LangRef:

  • poison: “undefined behavior as a value”. specifically, it is like uninit memory (such as padding bytes). it is “safe” to create poison, BUT poison MUST NOT be observed from safe code, as operations on poison return poison, like NaN. unlike NaN, which has defined comparisons, poison is neither true nor false, and LLVM may also convert it to undef (at which point it is both). so, it can’t be conditioned on, either.
  • undef: “a value that is every value”. functionally like poison, insofar as Rust is concerned. poison may become this. note: this means that division by poison or undef is like division by zero, which means it inflicts…
  • “UB”: poison and undef cover most of what people call “UB”. “UB” means this operation immediately invalidates the program: LLVM is allowed to lower it to ud2 or other opcodes that may cause an illegal instruction exception, and this is the “good end”. The “bad end” is that LLVM may reverse time to the moment control flow diverged on a path towards undefined behavior, and destroy the other branch, potentially deleting safe code and violating Rust’s unsafe contract.

Note that according to LLVM, vectors are not arrays, but they are equivalent when stored to and loaded from memory.

Unless stated otherwise, all intrinsics for binary operations require SIMD vectors of equal types and lengths.

Functions

  • simd_add 🔒 Experimental
    add/fadd
  • simd_and 🔒 Experimental
    and
  • simd_arith_offset 🔒 Experimental
    getelementptr (without inbounds) equivalent to wrapping_offset
  • simd_as 🔒 Experimental
    follows Rust’s T as U semantics, including saturating float casts which amounts to the same as simd_cast for many cases
  • simd_bitmask 🔒 Experimental
  • simd_cast 🔒 Experimental
    fptoui/fptosi/uitofp/sitofp casting floats to integers is truncating, so it is safe to convert values like e.g. 1.5 but the truncated value must fit in the target type or the result is poison. use simd_as instead for a cast that performs a saturating conversion.
  • simd_cast_ptr 🔒 Experimental
    equivalent to T as U semantics, specifically for pointers
  • simd_div 🔒 Experimental
    udiv/sdiv/fdiv ints and uints: {s,u}div incur UB if division by zero occurs. ints: sdiv is UB for int::MIN / -1. floats: fdiv is never UB, but may create NaNs or infinities.
  • simd_eq 🔒 Experimental
  • simd_expose_addr 🔒 Experimental
    expose a pointer as an address
  • simd_fabs 🔒 Experimental
    fabs
  • simd_fmax 🔒 Experimental
  • simd_fmin 🔒 Experimental
  • simd_from_exposed_addr 🔒 Experimental
    convert an exposed address back to a pointer
  • simd_gather 🔒 Experimental
    llvm.masked.gather like a loop of pointer reads val: vector of values to select if a lane is masked ptr: vector of pointers to read from mask: a “wide” mask of integers, selects as if simd_select(mask, read(ptr), val) note, the LLVM intrinsic accepts a mask vector of <N x i1> FIXME: review this if/when we fix up our mask story in general?
  • simd_ge 🔒 Experimental
  • simd_gt 🔒 Experimental
  • simd_le 🔒 Experimental
  • simd_lt 🔒 Experimental
  • simd_mul 🔒 Experimental
    mul/fmul
  • simd_ne 🔒 Experimental
  • simd_neg 🔒 Experimental
    neg/fneg ints: ultimately becomes a call to cg_ssa’s BuilderMethods::neg. cg_llvm equates this to simd_sub(Simd::splat(0), x). floats: LLVM’s fneg, which changes the floating point sign bit. Some arches have instructions for it. Rust panics for Neg::neg(int::MIN) due to overflow, but it is not UB in LLVM without nsw.
  • simd_or 🔒 Experimental
    or
  • simd_reduce_add_ordered 🔒 Experimental
  • simd_reduce_all 🔒 Experimental
  • simd_reduce_and 🔒 Experimental
  • simd_reduce_any 🔒 Experimental
  • simd_reduce_max 🔒 Experimental
  • simd_reduce_min 🔒 Experimental
  • simd_reduce_mul_ordered 🔒 Experimental
  • simd_reduce_or 🔒 Experimental
  • simd_reduce_xor 🔒 Experimental
  • simd_rem 🔒 Experimental
    urem/srem/frem ints and uints: {s,u}rem incur UB if division by zero occurs. ints: srem is UB for int::MIN / -1. floats: frem is equivalent to libm::fmod in the “default” floating point environment, sans errno.
  • simd_saturating_add 🔒 Experimental
  • simd_saturating_sub 🔒 Experimental
  • simd_scatter 🔒 Experimental
    llvm.masked.scatter like gather, but more spicy, as it writes instead of reads
  • simd_select 🔒 Experimental
  • simd_select_bitmask 🔒 Experimental
  • simd_shl 🔒 Experimental
    shl for (u)ints. poison if rhs >= lhs::BITS
  • simd_shr 🔒 Experimental
    ints: ashr uints: lshr poison if rhs >= lhs::BITS
  • simd_shuffle 🔒 Experimental
  • simd_sub 🔒 Experimental
    sub/fsub
  • simd_xor 🔒 Experimental
    xor