tur/simd
16-byte vector types and their lanewise operations.
GENERATED by tools/gen-simd.py -- edit the template there, not this file.
Phase S1 of docs/upcoming/simd-and-vectorization-plan.md, graduated 2026-10-30: (load "stdlib/simd.tur") is all a program needs.
| Type | Lanes | Lane | Loads from | |-------|-------|----------|------------| | F64x2 | 2 | float | F64Vec | | F32x4 | 4 | float32| F32Vec | | I64x2 | 2 | int | I64Vec | | I32x4 | 4 | int32 | I32Vec | | U16x8 | 8 | uint16 | (widen a U8x16) | | U8x16 | 16 | uint8 | U8Vec |
Each type is a ^copy struct with one field per lane (l0, l1, ...), so a vector is an ordinary value: a local, a parameter, a result, a struct field. (F64x2 7.1 3.25) builds one, (.l1 v) reads a lane. Every type has P-splat, P-lane, P-add, P-sub, P-mul, P-div, P-neg, P-min, P-max and P-hsum, and a Num instance, so {a + b} is the lanewise sum; the floats add P-sqrt and P-abs; all but U16x8 load from and store to their typed numeric array (P-load, P-store!, one bounds check per call); u8x16-widen-lo / -hi, u16x8-narrow and u16x8-shr move bytes through sixteen-bit lanes, where a product fits.
Comparisons (P-eq, P-lt, P-le, P-gt, P-ge) return a mask of the same lane width -- M64x2, M32x4, M16x8 or M8x16, -1 where the comparison held and 0 where not -- and P-select picks each lane from one of two vectors by a mask, without a branch; the masks combine with M-and, M-or, M-not and reduce with M-any / M-all. P-shuffle permutes lanes by an index vector (one instruction when the indices are constants). i32x4->f32x4, f32x4->i32x4 (truncating, saturating), f32x4-widen-lo / -hi and f64x2-narrow convert between lane types; every lane of every conversion is defined.
Compiled with gcc or clang, an operation is one vector instruction (a GNU vector extension over the struct's bytes); under tur jit the same operation is a loop over the lanes. Both compute each lane exactly as the scalar operator would -- integer lanes wrap, float operations are never fused -- so every engine gives the same bits. The types are 16 bytes on purpose: a 32-byte vector lives in memory on gcc without AVX (the plan's S0 findings).
Generic code takes a vector by value: a generic function (constrained or not) and a generic ADT such as (Option F64x2) are specialized per type. A Vec element is the exception -- each is boxed on the heap, as every multi-word element is -- so keep bulk lane data in the numeric arrays and load from them.
Since: S1 (simd-and-vectorization-plan)
F64x2
(defstruct ^copy F64x2 [l0 : float l1 : float])
a 16-byte vector of 2 float lanes.
Lanes l0 .. l1; (F64x2 7.1 7.1) builds one.
Since: S1
F32x4
(defstruct ^copy F32x4 [l0 : float32 l1 : float32 l2 : float32 l3 : float32])
a 16-byte vector of 4 float32 lanes.
Lanes l0 .. l3; (F32x4 (as float32 7.1) (as float32 7.1) (as float32 7.1) (as float32 7.1)) builds one.
Since: S1
I64x2
(defstruct ^copy I64x2 [l0 : int l1 : int])
a 16-byte vector of 2 int lanes.
Lanes l0 .. l1; (I64x2 7 7) builds one.
Since: S1
I32x4
(defstruct ^copy I32x4 [l0 : int32 l1 : int32 l2 : int32 l3 : int32])
a 16-byte vector of 4 int32 lanes.
Lanes l0 .. l3; (I32x4 (as int32 7) (as int32 7) (as int32 7) (as int32 7)) builds one.
Since: S1
U16x8
(defstruct ^copy U16x8 [])
a 16-byte vector of 8 uint16 lanes.
Lanes l0 .. l7; (U16x8 (as uint16 7) (as uint16 7) (as uint16 7) (as uint16 7) (as uint16 7) (as uint16 7) (as uint16 7) (as uint16 7)) builds one.
Since: S1
U8x16
(defstruct ^copy U8x16 [])
a 16-byte vector of 16 uint8 lanes.
Lanes l0 .. l15; (U8x16 (as uint8 7) (as uint8 7) (as uint8 7) (as uint8 7) (as uint8 7) (as uint8 7) (as uint8 7) (as uint8 7) (as uint8 7) (as uint8 7) (as uint8 7) (as uint8 7) (as uint8 7) (as uint8 7) (as uint8 7) (as uint8 7)) builds one.
Since: S1
M64x2
(defstruct ^copy M64x2 [l0 : int l1 : int])
a 16-byte mask of 2 int lanes, for the 2-lane vectors.
A comparison sets a lane to -1 where it held and 0 where it did not; -select and the mask operations take any nonzero lane as set. (M64x2 -1 -1) builds one with every lane set.
Since: S1
M32x4
(defstruct ^copy M32x4 [l0 : int32 l1 : int32 l2 : int32 l3 : int32])
a 16-byte mask of 4 int32 lanes, for the 4-lane vectors.
A comparison sets a lane to -1 where it held and 0 where it did not; -select and the mask operations take any nonzero lane as set. (M32x4 (as int32 -1) (as int32 -1) (as int32 -1) (as int32 -1)) builds one with every lane set.
Since: S1
M16x8
(defstruct ^copy M16x8 [])
a 16-byte mask of 8 int16 lanes, for the 8-lane vectors.
A comparison sets a lane to -1 where it held and 0 where it did not; -select and the mask operations take any nonzero lane as set. (M16x8 (as int16 -1) (as int16 -1) (as int16 -1) (as int16 -1) (as int16 -1) (as int16 -1) (as int16 -1) (as int16 -1)) builds one with every lane set.
Since: S1
M8x16
(defstruct ^copy M8x16 [])
a 16-byte mask of 16 int8 lanes, for the 16-lane vectors.
A comparison sets a lane to -1 where it held and 0 where it did not; -select and the mask operations take any nonzero lane as set. (M8x16 (as int8 -1) (as int8 -1) (as int8 -1) (as int8 -1) (as int8 -1) (as int8 -1) (as int8 -1) (as int8 -1) (as int8 -1) (as int8 -1) (as int8 -1) (as int8 -1) (as int8 -1) (as int8 -1) (as int8 -1) (as int8 -1)) builds one with every lane set.
Since: S1
f64x2-splat
(f64x2-splat [x : float])
every lane x.
| x | the value |
A F64x2.
(f64x2-splat 7.1)
Since: S1
f64x2-lane
(f64x2-lane [v : F64x2 k : int])
lane k of v (0 is the lowest; out of range panics).
| v | the vector | |
| k | the lane, 0 to 1 |
A float.
(f64x2-lane (f64x2-splat 7.1) 0) ; => 7.1
Since: S1
f64x2-load
(f64x2-load [^borrow arr : F64Vec i : int])
lanes from arr[i] .. arr[i + 1] (out of bounds panics, once).
The array's element type is the vector's lane type.
| arr | the array (borrowed) | |
| i | the first element |
A F64x2.
(let [a (f64vec-new 8 7.1)] (f64x2-load a 0))
Since: S1
f64x2-store!
(f64x2-store! [^borrow arr : F64Vec i : int v : F64x2])
write v's lanes to arr[i] .. arr[i + 1] (out of bounds panics, once).
| arr | the array written (borrowed) | |
| i | the first element | |
| v | the vector |
(f64x2-store! a 0 (f64x2-splat 3.25))
Since: S1
f64x2-load-unchecked
(f64x2-load-unchecked [^borrow arr : F64Vec i : int])
lanes from arr[i] .. arr[i + 1], NOT bounds-checked.
#fx{Unsafe}: for a loop that has checked its bounds once. It can not panic, so a call to it carries no panic check and no call site: in a tight loop the checked -load costs up to 3x (clang). The interpreter checks the index anyway.
| arr | the array (borrowed) | |
| i | the first element; the caller proves 0 <= i and i + 2 <= len |
A F64x2.
(unsafe (f64x2-load-unchecked a 0))
Since: S1
f64x2-store-unchecked!
(f64x2-store-unchecked! [^borrow arr : F64Vec i : int v : F64x2])
write v's lanes to arr[i] .. arr[i + 1], NOT bounds-checked.
#fx{Unsafe}, as -load-unchecked. Stores numbers: no TUR_REGION_NOTE.
| arr | the array written (borrowed) | |
| i | the first element; the caller proves 0 <= i and i + 2 <= len | |
| v | the vector |
(unsafe (f64x2-store-unchecked! a 0 (f64x2-splat 3.25)))
Since: S1
f64x2-add
(f64x2-add [a : F64x2 b : F64x2])
lanewise a + b.
Integer lanes wrap. Floats: one IEEE add per lane, as the scalar +.
| a | a vector | |
| b | a vector |
A F64x2.
(f64x2-add (f64x2-splat 7.1) (f64x2-splat 3.25))
Since: S1
f64x2-sub
(f64x2-sub [a : F64x2 b : F64x2])
lanewise a - b.
Integer lanes wrap.
| a | a vector | |
| b | a vector |
A F64x2.
(f64x2-sub (f64x2-splat 7.1) (f64x2-splat 3.25))
Since: S1
f64x2-mul
(f64x2-mul [a : F64x2 b : F64x2])
lanewise a * b.
Integer lanes wrap: a U8x16 product is taken modulo 256, lane by lane -- widen first (u8x16-widen-lo / -hi) for the full product.
| a | a vector | |
| b | a vector |
A F64x2.
(f64x2-mul (f64x2-splat 7.1) (f64x2-splat 3.25))
Since: S1
f64x2-div
(f64x2-div [a : F64x2 b : F64x2])
lanewise a / b.
An integer lane divided by zero panics; MIN / -1 wraps to MIN.
| a | a vector | |
| b | a vector |
A F64x2.
(f64x2-div (f64x2-splat 7.1) (f64x2-splat 3.25))
Since: S1
f64x2-neg
(f64x2-neg [a : F64x2])
lanewise -a.
Integer lanes wrap.
| a | a vector |
A F64x2.
(f64x2-neg (f64x2-splat 7.1))
Since: S1
f64x2-min
(f64x2-min [a : F64x2 b : F64x2])
lanewise minimum: lane k is b[k] < a[k] ? b[k] : a[k].
| a | a vector | |
| b | a vector |
A F64x2.
(f64x2-min (f64x2-splat 7.1) (f64x2-splat 3.25))
Since: S1
f64x2-max
(f64x2-max [a : F64x2 b : F64x2])
lanewise maximum: lane k is b[k] > a[k] ? b[k] : a[k].
| a | a vector | |
| b | a vector |
A F64x2.
(f64x2-max (f64x2-splat 7.1) (f64x2-splat 3.25))
Since: S1
f64x2-sqrt
(f64x2-sqrt [a : F64x2])
lanewise square root.
| a | a vector |
A F64x2.
(f64x2-sqrt (f64x2-splat 7.1))
Since: S1
f64x2-abs
(f64x2-abs [a : F64x2])
lanewise absolute value.
| a | a vector |
A F64x2.
(f64x2-abs (f64x2-splat -1.5))
Since: S1
f64x2-hsum
(f64x2-hsum [a : F64x2])
the sum of the lanes.
Floats add in one fixed tree -- (0 + 1) for two lanes, ((0 + 1) + (2 + 3)) for four -- the same on every engine. Integer lanes are widened to int and the sum wraps modulo 2^64.
| a | a vector |
A float.
(f64x2-hsum (f64x2-splat 3.25))
Since: S1
f64x2-eq
(f64x2-eq [a : F64x2 b : F64x2])
lanewise a == b: -1 where it holds, 0 where not.
Floats compare as IEEE: a NaN lane is unequal to everything and never less or greater.
| a | a vector | |
| b | a vector |
A M64x2.
(f64x2-eq (f64x2-splat 3.25) (f64x2-splat 7.1))
Since: S1
f64x2-lt
(f64x2-lt [a : F64x2 b : F64x2])
lanewise a < b: -1 where it holds, 0 where not.
| a | a vector | |
| b | a vector |
A M64x2.
(f64x2-lt (f64x2-splat 3.25) (f64x2-splat 7.1))
Since: S1
f64x2-le
(f64x2-le [a : F64x2 b : F64x2])
lanewise a <= b: -1 where it holds, 0 where not.
| a | a vector | |
| b | a vector |
A M64x2.
(f64x2-le (f64x2-splat 3.25) (f64x2-splat 7.1))
Since: S1
f64x2-gt
(f64x2-gt [a : F64x2 b : F64x2])
lanewise a > b: -1 where it holds, 0 where not.
| a | a vector | |
| b | a vector |
A M64x2.
(f64x2-gt (f64x2-splat 3.25) (f64x2-splat 7.1))
Since: S1
f64x2-ge
(f64x2-ge [a : F64x2 b : F64x2])
lanewise a >= b: -1 where it holds, 0 where not.
| a | a vector | |
| b | a vector |
A M64x2.
(f64x2-ge (f64x2-splat 3.25) (f64x2-splat 7.1))
Since: S1
f64x2-select
(f64x2-select [m : M64x2 a : F64x2 b : F64x2])
lane k is a[k] where m's lane k is set (nonzero), else b[k].
Branch-free: both a and b are computed. Lanewise min of a and b is (P-select (P-lt a b) a b), as P-min is.
| m | the mask, from a comparison | |
| a | the lanes taken where m is set | |
| b | the lanes taken where it is not |
A F64x2.
(f64x2-select (f64x2-lt (f64x2-splat 3.25) (f64x2-splat 7.1)) (f64x2-splat 3.25) (f64x2-splat 7.1))
Since: S1
f64x2-shuffle
(f64x2-shuffle [v : F64x2 idx : I64x2])
lane k is v's lane idx[k] mod 2.
Constant indices compile to one shuffle instruction (gcc and clang); an index outside 0 to 1 wraps, so there is no out-of-range case.
| v | the vector | |
| idx | which lane of v each result lane takes |
A F64x2.
(f64x2-shuffle (f64x2-splat 7.1) (I64x2 1 0)) ; lanes reversed
Since: S1
f64x2-narrow
(f64x2-narrow [lo : F64x2 hi : F64x2])
lo's lanes then hi's, each rounded to float32.
Rounds to nearest; a lane beyond float32's range becomes an infinity.
| lo | lanes 0-1 of the result | |
| hi | lanes 2-3 |
A F32x4.
(f64x2-narrow (f64x2-splat 7.1) (f64x2-splat 3.25))
Since: S1
Num[F64x2]
(definstance Num [F64x2])
lanewise arithmetic, so {a + b} works.
f32x4-splat
(f32x4-splat [x : float32])
every lane x.
| x | the value |
A F32x4.
(f32x4-splat (as float32 7.1))
Since: S1
f32x4-lane
(f32x4-lane [v : F32x4 k : int])
lane k of v (0 is the lowest; out of range panics).
| v | the vector | |
| k | the lane, 0 to 3 |
A float32.
(f32x4-lane (f32x4-splat (as float32 7.1)) 0) ; => (as float32 7.1)
Since: S1
f32x4-load
(f32x4-load [^borrow arr : F32Vec i : int])
lanes from arr[i] .. arr[i + 3] (out of bounds panics, once).
The array's element type is the vector's lane type.
| arr | the array (borrowed) | |
| i | the first element |
A F32x4.
(let [a (f32vec-new 8 (as float32 7.1))] (f32x4-load a 0))
Since: S1
f32x4-store!
(f32x4-store! [^borrow arr : F32Vec i : int v : F32x4])
write v's lanes to arr[i] .. arr[i + 3] (out of bounds panics, once).
| arr | the array written (borrowed) | |
| i | the first element | |
| v | the vector |
(f32x4-store! a 0 (f32x4-splat (as float32 3.25)))
Since: S1
f32x4-load-unchecked
(f32x4-load-unchecked [^borrow arr : F32Vec i : int])
lanes from arr[i] .. arr[i + 3], NOT bounds-checked.
#fx{Unsafe}: for a loop that has checked its bounds once. It can not panic, so a call to it carries no panic check and no call site: in a tight loop the checked -load costs up to 3x (clang). The interpreter checks the index anyway.
| arr | the array (borrowed) | |
| i | the first element; the caller proves 0 <= i and i + 4 <= len |
A F32x4.
(unsafe (f32x4-load-unchecked a 0))
Since: S1
f32x4-store-unchecked!
(f32x4-store-unchecked! [^borrow arr : F32Vec i : int v : F32x4])
write v's lanes to arr[i] .. arr[i + 3], NOT bounds-checked.
#fx{Unsafe}, as -load-unchecked. Stores numbers: no TUR_REGION_NOTE.
| arr | the array written (borrowed) | |
| i | the first element; the caller proves 0 <= i and i + 4 <= len | |
| v | the vector |
(unsafe (f32x4-store-unchecked! a 0 (f32x4-splat (as float32 3.25))))
Since: S1
f32x4-add
(f32x4-add [a : F32x4 b : F32x4])
lanewise a + b.
Integer lanes wrap. Floats: one IEEE add per lane, as the scalar +.
| a | a vector | |
| b | a vector |
A F32x4.
(f32x4-add (f32x4-splat (as float32 7.1)) (f32x4-splat (as float32 3.25)))
Since: S1
f32x4-sub
(f32x4-sub [a : F32x4 b : F32x4])
lanewise a - b.
Integer lanes wrap.
| a | a vector | |
| b | a vector |
A F32x4.
(f32x4-sub (f32x4-splat (as float32 7.1)) (f32x4-splat (as float32 3.25)))
Since: S1
f32x4-mul
(f32x4-mul [a : F32x4 b : F32x4])
lanewise a * b.
Integer lanes wrap: a U8x16 product is taken modulo 256, lane by lane -- widen first (u8x16-widen-lo / -hi) for the full product.
| a | a vector | |
| b | a vector |
A F32x4.
(f32x4-mul (f32x4-splat (as float32 7.1)) (f32x4-splat (as float32 3.25)))
Since: S1
f32x4-div
(f32x4-div [a : F32x4 b : F32x4])
lanewise a / b.
An integer lane divided by zero panics; MIN / -1 wraps to MIN.
| a | a vector | |
| b | a vector |
A F32x4.
(f32x4-div (f32x4-splat (as float32 7.1)) (f32x4-splat (as float32 3.25)))
Since: S1
f32x4-neg
(f32x4-neg [a : F32x4])
lanewise -a.
Integer lanes wrap.
| a | a vector |
A F32x4.
(f32x4-neg (f32x4-splat (as float32 7.1)))
Since: S1
f32x4-min
(f32x4-min [a : F32x4 b : F32x4])
lanewise minimum: lane k is b[k] < a[k] ? b[k] : a[k].
| a | a vector | |
| b | a vector |
A F32x4.
(f32x4-min (f32x4-splat (as float32 7.1)) (f32x4-splat (as float32 3.25)))
Since: S1
f32x4-max
(f32x4-max [a : F32x4 b : F32x4])
lanewise maximum: lane k is b[k] > a[k] ? b[k] : a[k].
| a | a vector | |
| b | a vector |
A F32x4.
(f32x4-max (f32x4-splat (as float32 7.1)) (f32x4-splat (as float32 3.25)))
Since: S1
f32x4-sqrt
(f32x4-sqrt [a : F32x4])
lanewise square root.
| a | a vector |
A F32x4.
(f32x4-sqrt (f32x4-splat (as float32 7.1)))
Since: S1
f32x4-abs
(f32x4-abs [a : F32x4])
lanewise absolute value.
| a | a vector |
A F32x4.
(f32x4-abs (f32x4-splat (as float32 -1.5)))
Since: S1
f32x4-hsum
(f32x4-hsum [a : F32x4])
the sum of the lanes.
Floats add in one fixed tree -- (0 + 1) for two lanes, ((0 + 1) + (2 + 3)) for four -- the same on every engine. Integer lanes are widened to int and the sum wraps modulo 2^64.
| a | a vector |
A float32.
(f32x4-hsum (f32x4-splat (as float32 3.25)))
Since: S1
f32x4-eq
(f32x4-eq [a : F32x4 b : F32x4])
lanewise a == b: -1 where it holds, 0 where not.
Floats compare as IEEE: a NaN lane is unequal to everything and never less or greater.
| a | a vector | |
| b | a vector |
A M32x4.
(f32x4-eq (f32x4-splat (as float32 3.25)) (f32x4-splat (as float32 7.1)))
Since: S1
f32x4-lt
(f32x4-lt [a : F32x4 b : F32x4])
lanewise a < b: -1 where it holds, 0 where not.
| a | a vector | |
| b | a vector |
A M32x4.
(f32x4-lt (f32x4-splat (as float32 3.25)) (f32x4-splat (as float32 7.1)))
Since: S1
f32x4-le
(f32x4-le [a : F32x4 b : F32x4])
lanewise a <= b: -1 where it holds, 0 where not.
| a | a vector | |
| b | a vector |
A M32x4.
(f32x4-le (f32x4-splat (as float32 3.25)) (f32x4-splat (as float32 7.1)))
Since: S1
f32x4-gt
(f32x4-gt [a : F32x4 b : F32x4])
lanewise a > b: -1 where it holds, 0 where not.
| a | a vector | |
| b | a vector |
A M32x4.
(f32x4-gt (f32x4-splat (as float32 3.25)) (f32x4-splat (as float32 7.1)))
Since: S1
f32x4-ge
(f32x4-ge [a : F32x4 b : F32x4])
lanewise a >= b: -1 where it holds, 0 where not.
| a | a vector | |
| b | a vector |
A M32x4.
(f32x4-ge (f32x4-splat (as float32 3.25)) (f32x4-splat (as float32 7.1)))
Since: S1
f32x4-select
(f32x4-select [m : M32x4 a : F32x4 b : F32x4])
lane k is a[k] where m's lane k is set (nonzero), else b[k].
Branch-free: both a and b are computed. Lanewise min of a and b is (P-select (P-lt a b) a b), as P-min is.
| m | the mask, from a comparison | |
| a | the lanes taken where m is set | |
| b | the lanes taken where it is not |
A F32x4.
(f32x4-select (f32x4-lt (f32x4-splat (as float32 3.25)) (f32x4-splat (as float32 7.1))) (f32x4-splat (as float32 3.25)) (f32x4-splat (as float32 7.1)))
Since: S1
f32x4-shuffle
(f32x4-shuffle [v : F32x4 idx : I32x4])
lane k is v's lane idx[k] mod 4.
Constant indices compile to one shuffle instruction (gcc and clang); an index outside 0 to 3 wraps, so there is no out-of-range case.
| v | the vector | |
| idx | which lane of v each result lane takes |
A F32x4.
(f32x4-shuffle (f32x4-splat (as float32 7.1)) (I32x4 (as int32 3) (as int32 2) (as int32 1) (as int32 0))) ; lanes reversed
Since: S1
f32x4->i32x4
(f32x4->i32x4 [a : F32x4])
each lane truncated toward zero to int32, saturating.
Every lane is defined: NaN gives 0, a lane at or above 2^31 gives 2147483647, one below -2^31 gives -2147483648. (A C cast is undefined there, and cvttps2dq alone gives -2147483648 for all three.)
| a | the vector |
A I32x4.
(f32x4->i32x4 (f32x4-splat (as float32 7.1))) ; => lanes of 7
Since: S1
f32x4-widen-lo
(f32x4-widen-lo [a : F32x4])
lanes 0 and 1 converted to float (exact).
| a | the vector |
A F64x2.
(f32x4-widen-lo (f32x4-splat (as float32 7.1)))
Since: S1
f32x4-widen-hi
(f32x4-widen-hi [a : F32x4])
lanes 2 and 3 converted to float (exact).
| a | the vector |
A F64x2.
(f32x4-widen-hi (f32x4-splat (as float32 7.1)))
Since: S1
Num[F32x4]
(definstance Num [F32x4])
lanewise arithmetic, so {a + b} works.
i64x2-splat
(i64x2-splat [x : int])
every lane x.
| x | the value |
A I64x2.
(i64x2-splat 7)
Since: S1
i64x2-lane
(i64x2-lane [v : I64x2 k : int])
lane k of v (0 is the lowest; out of range panics).
| v | the vector | |
| k | the lane, 0 to 1 |
A int.
(i64x2-lane (i64x2-splat 7) 0) ; => 7
Since: S1
i64x2-load
(i64x2-load [^borrow arr : I64Vec i : int])
lanes from arr[i] .. arr[i + 1] (out of bounds panics, once).
The array's element type is the vector's lane type.
| arr | the array (borrowed) | |
| i | the first element |
A I64x2.
(let [a (i64vec-new 8 7)] (i64x2-load a 0))
Since: S1
i64x2-store!
(i64x2-store! [^borrow arr : I64Vec i : int v : I64x2])
write v's lanes to arr[i] .. arr[i + 1] (out of bounds panics, once).
| arr | the array written (borrowed) | |
| i | the first element | |
| v | the vector |
(i64x2-store! a 0 (i64x2-splat 3))
Since: S1
i64x2-load-unchecked
(i64x2-load-unchecked [^borrow arr : I64Vec i : int])
lanes from arr[i] .. arr[i + 1], NOT bounds-checked.
#fx{Unsafe}: for a loop that has checked its bounds once. It can not panic, so a call to it carries no panic check and no call site: in a tight loop the checked -load costs up to 3x (clang). The interpreter checks the index anyway.
| arr | the array (borrowed) | |
| i | the first element; the caller proves 0 <= i and i + 2 <= len |
A I64x2.
(unsafe (i64x2-load-unchecked a 0))
Since: S1
i64x2-store-unchecked!
(i64x2-store-unchecked! [^borrow arr : I64Vec i : int v : I64x2])
write v's lanes to arr[i] .. arr[i + 1], NOT bounds-checked.
#fx{Unsafe}, as -load-unchecked. Stores numbers: no TUR_REGION_NOTE.
| arr | the array written (borrowed) | |
| i | the first element; the caller proves 0 <= i and i + 2 <= len | |
| v | the vector |
(unsafe (i64x2-store-unchecked! a 0 (i64x2-splat 3)))
Since: S1
i64x2-add
(i64x2-add [a : I64x2 b : I64x2])
lanewise a + b.
Integer lanes wrap. Floats: one IEEE add per lane, as the scalar +.
| a | a vector | |
| b | a vector |
A I64x2.
(i64x2-add (i64x2-splat 7) (i64x2-splat 3))
Since: S1
i64x2-sub
(i64x2-sub [a : I64x2 b : I64x2])
lanewise a - b.
Integer lanes wrap.
| a | a vector | |
| b | a vector |
A I64x2.
(i64x2-sub (i64x2-splat 7) (i64x2-splat 3))
Since: S1
i64x2-mul
(i64x2-mul [a : I64x2 b : I64x2])
lanewise a * b.
Integer lanes wrap: a U8x16 product is taken modulo 256, lane by lane -- widen first (u8x16-widen-lo / -hi) for the full product.
| a | a vector | |
| b | a vector |
A I64x2.
(i64x2-mul (i64x2-splat 7) (i64x2-splat 3))
Since: S1
i64x2-div
(i64x2-div [a : I64x2 b : I64x2])
lanewise a / b.
An integer lane divided by zero panics; MIN / -1 wraps to MIN.
| a | a vector | |
| b | a vector |
A I64x2.
(i64x2-div (i64x2-splat 7) (i64x2-splat 3))
Since: S1
i64x2-neg
(i64x2-neg [a : I64x2])
lanewise -a.
Integer lanes wrap.
| a | a vector |
A I64x2.
(i64x2-neg (i64x2-splat 7))
Since: S1
i64x2-min
(i64x2-min [a : I64x2 b : I64x2])
lanewise minimum: lane k is b[k] < a[k] ? b[k] : a[k].
| a | a vector | |
| b | a vector |
A I64x2.
(i64x2-min (i64x2-splat 7) (i64x2-splat 3))
Since: S1
i64x2-max
(i64x2-max [a : I64x2 b : I64x2])
lanewise maximum: lane k is b[k] > a[k] ? b[k] : a[k].
| a | a vector | |
| b | a vector |
A I64x2.
(i64x2-max (i64x2-splat 7) (i64x2-splat 3))
Since: S1
i64x2-hsum
(i64x2-hsum [a : I64x2])
the sum of the lanes.
Floats add in one fixed tree -- (0 + 1) for two lanes, ((0 + 1) + (2 + 3)) for four -- the same on every engine. Integer lanes are widened to int and the sum wraps modulo 2^64.
| a | a vector |
A int.
(i64x2-hsum (i64x2-splat 3))
Since: S1
i64x2-eq
(i64x2-eq [a : I64x2 b : I64x2])
lanewise a == b: -1 where it holds, 0 where not.
Floats compare as IEEE: a NaN lane is unequal to everything and never less or greater.
| a | a vector | |
| b | a vector |
A M64x2.
(i64x2-eq (i64x2-splat 3) (i64x2-splat 7))
Since: S1
i64x2-lt
(i64x2-lt [a : I64x2 b : I64x2])
lanewise a < b: -1 where it holds, 0 where not.
| a | a vector | |
| b | a vector |
A M64x2.
(i64x2-lt (i64x2-splat 3) (i64x2-splat 7))
Since: S1
i64x2-le
(i64x2-le [a : I64x2 b : I64x2])
lanewise a <= b: -1 where it holds, 0 where not.
| a | a vector | |
| b | a vector |
A M64x2.
(i64x2-le (i64x2-splat 3) (i64x2-splat 7))
Since: S1
i64x2-gt
(i64x2-gt [a : I64x2 b : I64x2])
lanewise a > b: -1 where it holds, 0 where not.
| a | a vector | |
| b | a vector |
A M64x2.
(i64x2-gt (i64x2-splat 3) (i64x2-splat 7))
Since: S1
i64x2-ge
(i64x2-ge [a : I64x2 b : I64x2])
lanewise a >= b: -1 where it holds, 0 where not.
| a | a vector | |
| b | a vector |
A M64x2.
(i64x2-ge (i64x2-splat 3) (i64x2-splat 7))
Since: S1
i64x2-select
(i64x2-select [m : M64x2 a : I64x2 b : I64x2])
lane k is a[k] where m's lane k is set (nonzero), else b[k].
Branch-free: both a and b are computed. Lanewise min of a and b is (P-select (P-lt a b) a b), as P-min is.
| m | the mask, from a comparison | |
| a | the lanes taken where m is set | |
| b | the lanes taken where it is not |
A I64x2.
(i64x2-select (i64x2-lt (i64x2-splat 3) (i64x2-splat 7)) (i64x2-splat 3) (i64x2-splat 7))
Since: S1
i64x2-shuffle
(i64x2-shuffle [v : I64x2 idx : I64x2])
lane k is v's lane idx[k] mod 2.
Constant indices compile to one shuffle instruction (gcc and clang); an index outside 0 to 1 wraps, so there is no out-of-range case.
| v | the vector | |
| idx | which lane of v each result lane takes |
A I64x2.
(i64x2-shuffle (i64x2-splat 7) (I64x2 1 0)) ; lanes reversed
Since: S1
Num[I64x2]
(definstance Num [I64x2])
lanewise arithmetic, so {a + b} works.
i32x4-splat
(i32x4-splat [x : int32])
every lane x.
| x | the value |
A I32x4.
(i32x4-splat (as int32 7))
Since: S1
i32x4-lane
(i32x4-lane [v : I32x4 k : int])
lane k of v (0 is the lowest; out of range panics).
| v | the vector | |
| k | the lane, 0 to 3 |
A int32.
(i32x4-lane (i32x4-splat (as int32 7)) 0) ; => (as int32 7)
Since: S1
i32x4-load
(i32x4-load [^borrow arr : I32Vec i : int])
lanes from arr[i] .. arr[i + 3] (out of bounds panics, once).
The array's element type is the vector's lane type.
| arr | the array (borrowed) | |
| i | the first element |
A I32x4.
(let [a (i32vec-new 8 (as int32 7))] (i32x4-load a 0))
Since: S1
i32x4-store!
(i32x4-store! [^borrow arr : I32Vec i : int v : I32x4])
write v's lanes to arr[i] .. arr[i + 3] (out of bounds panics, once).
| arr | the array written (borrowed) | |
| i | the first element | |
| v | the vector |
(i32x4-store! a 0 (i32x4-splat (as int32 3)))
Since: S1
i32x4-load-unchecked
(i32x4-load-unchecked [^borrow arr : I32Vec i : int])
lanes from arr[i] .. arr[i + 3], NOT bounds-checked.
#fx{Unsafe}: for a loop that has checked its bounds once. It can not panic, so a call to it carries no panic check and no call site: in a tight loop the checked -load costs up to 3x (clang). The interpreter checks the index anyway.
| arr | the array (borrowed) | |
| i | the first element; the caller proves 0 <= i and i + 4 <= len |
A I32x4.
(unsafe (i32x4-load-unchecked a 0))
Since: S1
i32x4-store-unchecked!
(i32x4-store-unchecked! [^borrow arr : I32Vec i : int v : I32x4])
write v's lanes to arr[i] .. arr[i + 3], NOT bounds-checked.
#fx{Unsafe}, as -load-unchecked. Stores numbers: no TUR_REGION_NOTE.
| arr | the array written (borrowed) | |
| i | the first element; the caller proves 0 <= i and i + 4 <= len | |
| v | the vector |
(unsafe (i32x4-store-unchecked! a 0 (i32x4-splat (as int32 3))))
Since: S1
i32x4-add
(i32x4-add [a : I32x4 b : I32x4])
lanewise a + b.
Integer lanes wrap. Floats: one IEEE add per lane, as the scalar +.
| a | a vector | |
| b | a vector |
A I32x4.
(i32x4-add (i32x4-splat (as int32 7)) (i32x4-splat (as int32 3)))
Since: S1
i32x4-sub
(i32x4-sub [a : I32x4 b : I32x4])
lanewise a - b.
Integer lanes wrap.
| a | a vector | |
| b | a vector |
A I32x4.
(i32x4-sub (i32x4-splat (as int32 7)) (i32x4-splat (as int32 3)))
Since: S1
i32x4-mul
(i32x4-mul [a : I32x4 b : I32x4])
lanewise a * b.
Integer lanes wrap: a U8x16 product is taken modulo 256, lane by lane -- widen first (u8x16-widen-lo / -hi) for the full product.
| a | a vector | |
| b | a vector |
A I32x4.
(i32x4-mul (i32x4-splat (as int32 7)) (i32x4-splat (as int32 3)))
Since: S1
i32x4-div
(i32x4-div [a : I32x4 b : I32x4])
lanewise a / b.
An integer lane divided by zero panics; MIN / -1 wraps to MIN.
| a | a vector | |
| b | a vector |
A I32x4.
(i32x4-div (i32x4-splat (as int32 7)) (i32x4-splat (as int32 3)))
Since: S1
i32x4-neg
(i32x4-neg [a : I32x4])
lanewise -a.
Integer lanes wrap.
| a | a vector |
A I32x4.
(i32x4-neg (i32x4-splat (as int32 7)))
Since: S1
i32x4-min
(i32x4-min [a : I32x4 b : I32x4])
lanewise minimum: lane k is b[k] < a[k] ? b[k] : a[k].
| a | a vector | |
| b | a vector |
A I32x4.
(i32x4-min (i32x4-splat (as int32 7)) (i32x4-splat (as int32 3)))
Since: S1
i32x4-max
(i32x4-max [a : I32x4 b : I32x4])
lanewise maximum: lane k is b[k] > a[k] ? b[k] : a[k].
| a | a vector | |
| b | a vector |
A I32x4.
(i32x4-max (i32x4-splat (as int32 7)) (i32x4-splat (as int32 3)))
Since: S1
i32x4-hsum
(i32x4-hsum [a : I32x4])
the sum of the lanes.
Floats add in one fixed tree -- (0 + 1) for two lanes, ((0 + 1) + (2 + 3)) for four -- the same on every engine. Integer lanes are widened to int and the sum wraps modulo 2^64.
| a | a vector |
A int.
(i32x4-hsum (i32x4-splat (as int32 3)))
Since: S1
i32x4-eq
(i32x4-eq [a : I32x4 b : I32x4])
lanewise a == b: -1 where it holds, 0 where not.
Floats compare as IEEE: a NaN lane is unequal to everything and never less or greater.
| a | a vector | |
| b | a vector |
A M32x4.
(i32x4-eq (i32x4-splat (as int32 3)) (i32x4-splat (as int32 7)))
Since: S1
i32x4-lt
(i32x4-lt [a : I32x4 b : I32x4])
lanewise a < b: -1 where it holds, 0 where not.
| a | a vector | |
| b | a vector |
A M32x4.
(i32x4-lt (i32x4-splat (as int32 3)) (i32x4-splat (as int32 7)))
Since: S1
i32x4-le
(i32x4-le [a : I32x4 b : I32x4])
lanewise a <= b: -1 where it holds, 0 where not.
| a | a vector | |
| b | a vector |
A M32x4.
(i32x4-le (i32x4-splat (as int32 3)) (i32x4-splat (as int32 7)))
Since: S1
i32x4-gt
(i32x4-gt [a : I32x4 b : I32x4])
lanewise a > b: -1 where it holds, 0 where not.
| a | a vector | |
| b | a vector |
A M32x4.
(i32x4-gt (i32x4-splat (as int32 3)) (i32x4-splat (as int32 7)))
Since: S1
i32x4-ge
(i32x4-ge [a : I32x4 b : I32x4])
lanewise a >= b: -1 where it holds, 0 where not.
| a | a vector | |
| b | a vector |
A M32x4.
(i32x4-ge (i32x4-splat (as int32 3)) (i32x4-splat (as int32 7)))
Since: S1
i32x4-select
(i32x4-select [m : M32x4 a : I32x4 b : I32x4])
lane k is a[k] where m's lane k is set (nonzero), else b[k].
Branch-free: both a and b are computed. Lanewise min of a and b is (P-select (P-lt a b) a b), as P-min is.
| m | the mask, from a comparison | |
| a | the lanes taken where m is set | |
| b | the lanes taken where it is not |
A I32x4.
(i32x4-select (i32x4-lt (i32x4-splat (as int32 3)) (i32x4-splat (as int32 7))) (i32x4-splat (as int32 3)) (i32x4-splat (as int32 7)))
Since: S1
i32x4-shuffle
(i32x4-shuffle [v : I32x4 idx : I32x4])
lane k is v's lane idx[k] mod 4.
Constant indices compile to one shuffle instruction (gcc and clang); an index outside 0 to 3 wraps, so there is no out-of-range case.
| v | the vector | |
| idx | which lane of v each result lane takes |
A I32x4.
(i32x4-shuffle (i32x4-splat (as int32 7)) (I32x4 (as int32 3) (as int32 2) (as int32 1) (as int32 0))) ; lanes reversed
Since: S1
i32x4->f32x4
(i32x4->f32x4 [a : I32x4])
each lane converted to float32, rounding to nearest (cvtdq2ps).
| a | the vector |
A F32x4.
(i32x4->f32x4 (i32x4-splat (as int32 7)))
Since: S1
Num[I32x4]
(definstance Num [I32x4])
lanewise arithmetic, so {a + b} works.
u16x8-splat
(u16x8-splat [x : uint16])
every lane x.
| x | the value |
A U16x8.
(u16x8-splat (as uint16 7))
Since: S1
u16x8-lane
(u16x8-lane [v : U16x8 k : int])
lane k of v (0 is the lowest; out of range panics).
| v | the vector | |
| k | the lane, 0 to 7 |
A uint16.
(u16x8-lane (u16x8-splat (as uint16 7)) 0) ; => (as uint16 7)
Since: S1
u16x8-add
(u16x8-add [a : U16x8 b : U16x8])
lanewise a + b.
Integer lanes wrap. Floats: one IEEE add per lane, as the scalar +.
| a | a vector | |
| b | a vector |
A U16x8.
(u16x8-add (u16x8-splat (as uint16 7)) (u16x8-splat (as uint16 3)))
Since: S1
u16x8-sub
(u16x8-sub [a : U16x8 b : U16x8])
lanewise a - b.
Integer lanes wrap.
| a | a vector | |
| b | a vector |
A U16x8.
(u16x8-sub (u16x8-splat (as uint16 7)) (u16x8-splat (as uint16 3)))
Since: S1
u16x8-mul
(u16x8-mul [a : U16x8 b : U16x8])
lanewise a * b.
Integer lanes wrap: a U8x16 product is taken modulo 256, lane by lane -- widen first (u8x16-widen-lo / -hi) for the full product.
| a | a vector | |
| b | a vector |
A U16x8.
(u16x8-mul (u16x8-splat (as uint16 7)) (u16x8-splat (as uint16 3)))
Since: S1
u16x8-div
(u16x8-div [a : U16x8 b : U16x8])
lanewise a / b.
An integer lane divided by zero panics; MIN / -1 wraps to MIN.
| a | a vector | |
| b | a vector |
A U16x8.
(u16x8-div (u16x8-splat (as uint16 7)) (u16x8-splat (as uint16 3)))
Since: S1
u16x8-neg
(u16x8-neg [a : U16x8])
lanewise -a.
Integer lanes wrap.
| a | a vector |
A U16x8.
(u16x8-neg (u16x8-splat (as uint16 7)))
Since: S1
u16x8-min
(u16x8-min [a : U16x8 b : U16x8])
lanewise minimum: lane k is b[k] < a[k] ? b[k] : a[k].
| a | a vector | |
| b | a vector |
A U16x8.
(u16x8-min (u16x8-splat (as uint16 7)) (u16x8-splat (as uint16 3)))
Since: S1
u16x8-max
(u16x8-max [a : U16x8 b : U16x8])
lanewise maximum: lane k is b[k] > a[k] ? b[k] : a[k].
| a | a vector | |
| b | a vector |
A U16x8.
(u16x8-max (u16x8-splat (as uint16 7)) (u16x8-splat (as uint16 3)))
Since: S1
u16x8-hsum
(u16x8-hsum [a : U16x8])
the sum of the lanes.
Floats add in one fixed tree -- (0 + 1) for two lanes, ((0 + 1) + (2 + 3)) for four -- the same on every engine. Integer lanes are widened to int and the sum wraps modulo 2^64.
| a | a vector |
A int.
(u16x8-hsum (u16x8-splat (as uint16 3)))
Since: S1
u16x8-narrow
(u16x8-narrow [lo : U16x8 hi : U16x8])
lo's lanes then hi's, each truncated to eight bits.
| lo | lanes 0-7 of the result | |
| hi | lanes 8-15 |
A U8x16.
(u16x8-narrow (u16x8-splat (as uint16 7)) (u16x8-splat (as uint16 3)))
Since: S1
u16x8-shr
(u16x8-shr [v : U16x8 n : int])
every lane shifted right n bits, zero-filled (n outside 0 to 15 gives zero lanes).
| v | the vector | |
| n | the shift count |
A U16x8.
(u16x8-shr (u16x8-splat (as uint16 65535)) 8)
Since: S1
u16x8-eq
(u16x8-eq [a : U16x8 b : U16x8])
lanewise a == b: -1 where it holds, 0 where not.
Floats compare as IEEE: a NaN lane is unequal to everything and never less or greater.
| a | a vector | |
| b | a vector |
A M16x8.
(u16x8-eq (u16x8-splat (as uint16 3)) (u16x8-splat (as uint16 7)))
Since: S1
u16x8-lt
(u16x8-lt [a : U16x8 b : U16x8])
lanewise a < b: -1 where it holds, 0 where not.
| a | a vector | |
| b | a vector |
A M16x8.
(u16x8-lt (u16x8-splat (as uint16 3)) (u16x8-splat (as uint16 7)))
Since: S1
u16x8-le
(u16x8-le [a : U16x8 b : U16x8])
lanewise a <= b: -1 where it holds, 0 where not.
| a | a vector | |
| b | a vector |
A M16x8.
(u16x8-le (u16x8-splat (as uint16 3)) (u16x8-splat (as uint16 7)))
Since: S1
u16x8-gt
(u16x8-gt [a : U16x8 b : U16x8])
lanewise a > b: -1 where it holds, 0 where not.
| a | a vector | |
| b | a vector |
A M16x8.
(u16x8-gt (u16x8-splat (as uint16 3)) (u16x8-splat (as uint16 7)))
Since: S1
u16x8-ge
(u16x8-ge [a : U16x8 b : U16x8])
lanewise a >= b: -1 where it holds, 0 where not.
| a | a vector | |
| b | a vector |
A M16x8.
(u16x8-ge (u16x8-splat (as uint16 3)) (u16x8-splat (as uint16 7)))
Since: S1
u16x8-select
(u16x8-select [m : M16x8 a : U16x8 b : U16x8])
lane k is a[k] where m's lane k is set (nonzero), else b[k].
Branch-free: both a and b are computed. Lanewise min of a and b is (P-select (P-lt a b) a b), as P-min is.
| m | the mask, from a comparison | |
| a | the lanes taken where m is set | |
| b | the lanes taken where it is not |
A U16x8.
(u16x8-select (u16x8-lt (u16x8-splat (as uint16 3)) (u16x8-splat (as uint16 7))) (u16x8-splat (as uint16 3)) (u16x8-splat (as uint16 7)))
Since: S1
u16x8-shuffle
(u16x8-shuffle [v : U16x8 idx : U16x8])
lane k is v's lane idx[k] mod 8.
Constant indices compile to one shuffle instruction (gcc and clang); an index outside 0 to 7 wraps, so there is no out-of-range case.
| v | the vector | |
| idx | which lane of v each result lane takes |
A U16x8.
(u16x8-shuffle (u16x8-splat (as uint16 7)) (U16x8 (as uint16 7) (as uint16 6) (as uint16 5) (as uint16 4) (as uint16 3) (as uint16 2) (as uint16 1) (as uint16 0))) ; lanes reversed
Since: S1
Num[U16x8]
(definstance Num [U16x8])
lanewise arithmetic, so {a + b} works.
u8x16-splat
(u8x16-splat [x : uint8])
every lane x.
| x | the value |
A U8x16.
(u8x16-splat (as uint8 7))
Since: S1
u8x16-lane
(u8x16-lane [v : U8x16 k : int])
lane k of v (0 is the lowest; out of range panics).
| v | the vector | |
| k | the lane, 0 to 15 |
A uint8.
(u8x16-lane (u8x16-splat (as uint8 7)) 0) ; => (as uint8 7)
Since: S1
u8x16-load
(u8x16-load [^borrow arr : U8Vec i : int])
lanes from arr[i] .. arr[i + 15] (out of bounds panics, once).
The array's element type is the vector's lane type.
| arr | the array (borrowed) | |
| i | the first element |
A U8x16.
(let [a (u8vec-new 8 (as uint8 7))] (u8x16-load a 0))
Since: S1
u8x16-store!
(u8x16-store! [^borrow arr : U8Vec i : int v : U8x16])
write v's lanes to arr[i] .. arr[i + 15] (out of bounds panics, once).
| arr | the array written (borrowed) | |
| i | the first element | |
| v | the vector |
(u8x16-store! a 0 (u8x16-splat (as uint8 3)))
Since: S1
u8x16-load-unchecked
(u8x16-load-unchecked [^borrow arr : U8Vec i : int])
lanes from arr[i] .. arr[i + 15], NOT bounds-checked.
#fx{Unsafe}: for a loop that has checked its bounds once. It can not panic, so a call to it carries no panic check and no call site: in a tight loop the checked -load costs up to 3x (clang). The interpreter checks the index anyway.
| arr | the array (borrowed) | |
| i | the first element; the caller proves 0 <= i and i + 16 <= len |
A U8x16.
(unsafe (u8x16-load-unchecked a 0))
Since: S1
u8x16-store-unchecked!
(u8x16-store-unchecked! [^borrow arr : U8Vec i : int v : U8x16])
write v's lanes to arr[i] .. arr[i + 15], NOT bounds-checked.
#fx{Unsafe}, as -load-unchecked. Stores numbers: no TUR_REGION_NOTE.
| arr | the array written (borrowed) | |
| i | the first element; the caller proves 0 <= i and i + 16 <= len | |
| v | the vector |
(unsafe (u8x16-store-unchecked! a 0 (u8x16-splat (as uint8 3))))
Since: S1
u8x16-add
(u8x16-add [a : U8x16 b : U8x16])
lanewise a + b.
Integer lanes wrap. Floats: one IEEE add per lane, as the scalar +.
| a | a vector | |
| b | a vector |
A U8x16.
(u8x16-add (u8x16-splat (as uint8 7)) (u8x16-splat (as uint8 3)))
Since: S1
u8x16-sub
(u8x16-sub [a : U8x16 b : U8x16])
lanewise a - b.
Integer lanes wrap.
| a | a vector | |
| b | a vector |
A U8x16.
(u8x16-sub (u8x16-splat (as uint8 7)) (u8x16-splat (as uint8 3)))
Since: S1
u8x16-mul
(u8x16-mul [a : U8x16 b : U8x16])
lanewise a * b.
Integer lanes wrap: a U8x16 product is taken modulo 256, lane by lane -- widen first (u8x16-widen-lo / -hi) for the full product.
| a | a vector | |
| b | a vector |
A U8x16.
(u8x16-mul (u8x16-splat (as uint8 7)) (u8x16-splat (as uint8 3)))
Since: S1
u8x16-div
(u8x16-div [a : U8x16 b : U8x16])
lanewise a / b.
An integer lane divided by zero panics; MIN / -1 wraps to MIN.
| a | a vector | |
| b | a vector |
A U8x16.
(u8x16-div (u8x16-splat (as uint8 7)) (u8x16-splat (as uint8 3)))
Since: S1
u8x16-neg
(u8x16-neg [a : U8x16])
lanewise -a.
Integer lanes wrap.
| a | a vector |
A U8x16.
(u8x16-neg (u8x16-splat (as uint8 7)))
Since: S1
u8x16-min
(u8x16-min [a : U8x16 b : U8x16])
lanewise minimum: lane k is b[k] < a[k] ? b[k] : a[k].
| a | a vector | |
| b | a vector |
A U8x16.
(u8x16-min (u8x16-splat (as uint8 7)) (u8x16-splat (as uint8 3)))
Since: S1
u8x16-max
(u8x16-max [a : U8x16 b : U8x16])
lanewise maximum: lane k is b[k] > a[k] ? b[k] : a[k].
| a | a vector | |
| b | a vector |
A U8x16.
(u8x16-max (u8x16-splat (as uint8 7)) (u8x16-splat (as uint8 3)))
Since: S1
u8x16-hsum
(u8x16-hsum [a : U8x16])
the sum of the lanes.
Floats add in one fixed tree -- (0 + 1) for two lanes, ((0 + 1) + (2 + 3)) for four -- the same on every engine. Integer lanes are widened to int and the sum wraps modulo 2^64.
| a | a vector |
A int.
(u8x16-hsum (u8x16-splat (as uint8 3)))
Since: S1
u8x16-widen-lo
(u8x16-widen-lo [a : U8x16])
lanes 0-7 widened to sixteen bits.
| a | a byte vector |
A U16x8.
(u8x16-widen-lo (u8x16-splat (as uint8 255)))
Since: S1
u8x16-widen-hi
(u8x16-widen-hi [a : U8x16])
lanes 8-15 widened to sixteen bits.
| a | a byte vector |
A U16x8.
(u8x16-widen-hi (u8x16-splat (as uint8 255)))
Since: S1
u8x16-eq
(u8x16-eq [a : U8x16 b : U8x16])
lanewise a == b: -1 where it holds, 0 where not.
Floats compare as IEEE: a NaN lane is unequal to everything and never less or greater.
| a | a vector | |
| b | a vector |
A M8x16.
(u8x16-eq (u8x16-splat (as uint8 3)) (u8x16-splat (as uint8 7)))
Since: S1
u8x16-lt
(u8x16-lt [a : U8x16 b : U8x16])
lanewise a < b: -1 where it holds, 0 where not.
| a | a vector | |
| b | a vector |
A M8x16.
(u8x16-lt (u8x16-splat (as uint8 3)) (u8x16-splat (as uint8 7)))
Since: S1
u8x16-le
(u8x16-le [a : U8x16 b : U8x16])
lanewise a <= b: -1 where it holds, 0 where not.
| a | a vector | |
| b | a vector |
A M8x16.
(u8x16-le (u8x16-splat (as uint8 3)) (u8x16-splat (as uint8 7)))
Since: S1
u8x16-gt
(u8x16-gt [a : U8x16 b : U8x16])
lanewise a > b: -1 where it holds, 0 where not.
| a | a vector | |
| b | a vector |
A M8x16.
(u8x16-gt (u8x16-splat (as uint8 3)) (u8x16-splat (as uint8 7)))
Since: S1
u8x16-ge
(u8x16-ge [a : U8x16 b : U8x16])
lanewise a >= b: -1 where it holds, 0 where not.
| a | a vector | |
| b | a vector |
A M8x16.
(u8x16-ge (u8x16-splat (as uint8 3)) (u8x16-splat (as uint8 7)))
Since: S1
u8x16-select
(u8x16-select [m : M8x16 a : U8x16 b : U8x16])
lane k is a[k] where m's lane k is set (nonzero), else b[k].
Branch-free: both a and b are computed. Lanewise min of a and b is (P-select (P-lt a b) a b), as P-min is.
| m | the mask, from a comparison | |
| a | the lanes taken where m is set | |
| b | the lanes taken where it is not |
A U8x16.
(u8x16-select (u8x16-lt (u8x16-splat (as uint8 3)) (u8x16-splat (as uint8 7))) (u8x16-splat (as uint8 3)) (u8x16-splat (as uint8 7)))
Since: S1
u8x16-shuffle
(u8x16-shuffle [v : U8x16 idx : U8x16])
lane k is v's lane idx[k] mod 16.
Constant indices compile to one shuffle instruction (gcc and clang); an index outside 0 to 15 wraps, so there is no out-of-range case.
| v | the vector | |
| idx | which lane of v each result lane takes |
A U8x16.
(u8x16-shuffle (u8x16-splat (as uint8 7)) (U8x16 (as uint8 15) (as uint8 14) (as uint8 13) (as uint8 12) (as uint8 11) (as uint8 10) (as uint8 9) (as uint8 8) (as uint8 7) (as uint8 6) (as uint8 5) (as uint8 4) (as uint8 3) (as uint8 2) (as uint8 1) (as uint8 0))) ; lanes reversed
Since: S1
Num[U8x16]
(definstance Num [U8x16])
lanewise arithmetic, so {a + b} works.
m64x2-and
(m64x2-and [a : M64x2 b : M64x2])
lane k is set where both a's and b's are.
| a | a mask | |
| b | a mask |
A M64x2.
(m64x2-and (f64x2-lt (f64x2-splat 3.25) (f64x2-splat 7.1)) (f64x2-lt (f64x2-splat 3.25) (f64x2-splat 7.1)))
Since: S1
m64x2-or
(m64x2-or [a : M64x2 b : M64x2])
lane k is set where a's or b's is.
| a | a mask | |
| b | a mask |
A M64x2.
(m64x2-or (f64x2-lt (f64x2-splat 3.25) (f64x2-splat 7.1)) (f64x2-lt (f64x2-splat 3.25) (f64x2-splat 7.1)))
Since: S1
m64x2-not
(m64x2-not [a : M64x2])
lane k is set where a's is not.
| a | a mask |
A M64x2.
(m64x2-not (f64x2-lt (f64x2-splat 3.25) (f64x2-splat 7.1)))
Since: S1
m64x2-any
(m64x2-any [a : M64x2])
true when some lane of a is set.
| a | a mask |
A bool.
(m64x2-any (f64x2-lt (f64x2-splat 3.25) (f64x2-splat 7.1))) ; => true
Since: S1
m64x2-all
(m64x2-all [a : M64x2])
true when every lane of a is set.
| a | a mask |
A bool.
(m64x2-all (f64x2-lt (f64x2-splat 3.25) (f64x2-splat 7.1))) ; => true
Since: S1
m32x4-and
(m32x4-and [a : M32x4 b : M32x4])
lane k is set where both a's and b's are.
| a | a mask | |
| b | a mask |
A M32x4.
(m32x4-and (i32x4-lt (i32x4-splat (as int32 3)) (i32x4-splat (as int32 7))) (i32x4-lt (i32x4-splat (as int32 3)) (i32x4-splat (as int32 7))))
Since: S1
m32x4-or
(m32x4-or [a : M32x4 b : M32x4])
lane k is set where a's or b's is.
| a | a mask | |
| b | a mask |
A M32x4.
(m32x4-or (i32x4-lt (i32x4-splat (as int32 3)) (i32x4-splat (as int32 7))) (i32x4-lt (i32x4-splat (as int32 3)) (i32x4-splat (as int32 7))))
Since: S1
m32x4-not
(m32x4-not [a : M32x4])
lane k is set where a's is not.
| a | a mask |
A M32x4.
(m32x4-not (i32x4-lt (i32x4-splat (as int32 3)) (i32x4-splat (as int32 7))))
Since: S1
m32x4-any
(m32x4-any [a : M32x4])
true when some lane of a is set.
| a | a mask |
A bool.
(m32x4-any (i32x4-lt (i32x4-splat (as int32 3)) (i32x4-splat (as int32 7)))) ; => true
Since: S1
m32x4-all
(m32x4-all [a : M32x4])
true when every lane of a is set.
| a | a mask |
A bool.
(m32x4-all (i32x4-lt (i32x4-splat (as int32 3)) (i32x4-splat (as int32 7)))) ; => true
Since: S1
m16x8-and
(m16x8-and [a : M16x8 b : M16x8])
lane k is set where both a's and b's are.
| a | a mask | |
| b | a mask |
A M16x8.
(m16x8-and (u16x8-lt (u16x8-splat (as uint16 3)) (u16x8-splat (as uint16 7))) (u16x8-lt (u16x8-splat (as uint16 3)) (u16x8-splat (as uint16 7))))
Since: S1
m16x8-or
(m16x8-or [a : M16x8 b : M16x8])
lane k is set where a's or b's is.
| a | a mask | |
| b | a mask |
A M16x8.
(m16x8-or (u16x8-lt (u16x8-splat (as uint16 3)) (u16x8-splat (as uint16 7))) (u16x8-lt (u16x8-splat (as uint16 3)) (u16x8-splat (as uint16 7))))
Since: S1
m16x8-not
(m16x8-not [a : M16x8])
lane k is set where a's is not.
| a | a mask |
A M16x8.
(m16x8-not (u16x8-lt (u16x8-splat (as uint16 3)) (u16x8-splat (as uint16 7))))
Since: S1
m16x8-any
(m16x8-any [a : M16x8])
true when some lane of a is set.
| a | a mask |
A bool.
(m16x8-any (u16x8-lt (u16x8-splat (as uint16 3)) (u16x8-splat (as uint16 7)))) ; => true
Since: S1
m16x8-all
(m16x8-all [a : M16x8])
true when every lane of a is set.
| a | a mask |
A bool.
(m16x8-all (u16x8-lt (u16x8-splat (as uint16 3)) (u16x8-splat (as uint16 7)))) ; => true
Since: S1
m8x16-and
(m8x16-and [a : M8x16 b : M8x16])
lane k is set where both a's and b's are.
| a | a mask | |
| b | a mask |
A M8x16.
(m8x16-and (u8x16-lt (u8x16-splat (as uint8 3)) (u8x16-splat (as uint8 7))) (u8x16-lt (u8x16-splat (as uint8 3)) (u8x16-splat (as uint8 7))))
Since: S1
m8x16-or
(m8x16-or [a : M8x16 b : M8x16])
lane k is set where a's or b's is.
| a | a mask | |
| b | a mask |
A M8x16.
(m8x16-or (u8x16-lt (u8x16-splat (as uint8 3)) (u8x16-splat (as uint8 7))) (u8x16-lt (u8x16-splat (as uint8 3)) (u8x16-splat (as uint8 7))))
Since: S1
m8x16-not
(m8x16-not [a : M8x16])
lane k is set where a's is not.
| a | a mask |
A M8x16.
(m8x16-not (u8x16-lt (u8x16-splat (as uint8 3)) (u8x16-splat (as uint8 7))))
Since: S1
m8x16-any
(m8x16-any [a : M8x16])
true when some lane of a is set.
| a | a mask |
A bool.
(m8x16-any (u8x16-lt (u8x16-splat (as uint8 3)) (u8x16-splat (as uint8 7)))) ; => true
Since: S1
m8x16-all
(m8x16-all [a : M8x16])
true when every lane of a is set.
| a | a mask |
A bool.
(m8x16-all (u8x16-lt (u8x16-splat (as uint8 3)) (u8x16-splat (as uint8 7)))) ; => true
Since: S1