core/intrinsics/simd.rs
1//! SIMD compiler intrinsics.
2//!
3//! In this module, a "vector" is any `repr(simd)` type.
4
5#[cfg(not(feature = "ferrocene_subset"))]
6use crate::marker::ConstParamTy;
7
8/// Inserts an element into a vector, returning the updated vector.
9///
10/// `T` must be a vector with element type `U`, and `idx` must be `const`.
11///
12/// # Safety
13///
14/// `idx` must be in-bounds of the vector.
15#[rustc_intrinsic]
16#[rustc_nounwind]
17pub const unsafe fn simd_insert<T, U>(x: T, idx: u32, val: U) -> T;
18
19/// Extracts an element from a vector.
20///
21/// `T` must be a vector with element type `U`, and `idx` must be `const`.
22///
23/// # Safety
24///
25/// `idx` must be const and in-bounds of the vector.
26#[rustc_intrinsic]
27#[rustc_nounwind]
28pub const unsafe fn simd_extract<T, U>(x: T, idx: u32) -> U;
29
30/// Inserts an element into a vector, returning the updated vector.
31///
32/// `T` must be a vector with element type `U`.
33///
34/// If the index is `const`, [`simd_insert`] may emit better assembly.
35///
36/// # Safety
37///
38/// `idx` must be in-bounds of the vector.
39#[rustc_nounwind]
40#[rustc_intrinsic]
41#[cfg(not(feature = "ferrocene_subset"))]
42pub unsafe fn simd_insert_dyn<T, U>(mut x: T, idx: u32, val: U) -> T {
43 // SAFETY: `idx` must be in-bounds
44 unsafe { (&raw mut x).cast::<U>().add(idx as usize).write(val) }
45 x
46}
47
48/// Extracts an element from a vector.
49///
50/// `T` must be a vector with element type `U`.
51///
52/// If the index is `const`, [`simd_extract`] may emit better assembly.
53///
54/// # Safety
55///
56/// `idx` must be in-bounds of the vector.
57#[rustc_nounwind]
58#[rustc_intrinsic]
59#[cfg(not(feature = "ferrocene_subset"))]
60pub unsafe fn simd_extract_dyn<T, U>(x: T, idx: u32) -> U {
61 // SAFETY: `idx` must be in-bounds
62 unsafe { (&raw const x).cast::<U>().add(idx as usize).read() }
63}
64
65/// Adds two simd vectors elementwise.
66///
67/// `T` must be a vector of integers or floats.
68#[rustc_intrinsic]
69#[rustc_nounwind]
70pub const unsafe fn simd_add<T>(x: T, y: T) -> T;
71
72/// Subtracts `rhs` from `lhs` elementwise.
73///
74/// `T` must be a vector of integers or floats.
75#[rustc_intrinsic]
76#[rustc_nounwind]
77pub const unsafe fn simd_sub<T>(lhs: T, rhs: T) -> T;
78
79/// Multiplies two simd vectors elementwise.
80///
81/// `T` must be a vector of integers or floats.
82#[rustc_intrinsic]
83#[rustc_nounwind]
84pub const unsafe fn simd_mul<T>(x: T, y: T) -> T;
85
86/// Divides `lhs` by `rhs` elementwise.
87///
88/// `T` must be a vector of integers or floats.
89///
90/// # Safety
91/// For integers, `rhs` must not contain any zero elements.
92/// Additionally for signed integers, `<int>::MIN / -1` is undefined behavior.
93#[rustc_intrinsic]
94#[rustc_nounwind]
95#[cfg(not(feature = "ferrocene_subset"))]
96pub const unsafe fn simd_div<T>(lhs: T, rhs: T) -> T;
97
98/// Returns remainder of two vectors elementwise.
99///
100/// `T` must be a vector of integers or floats.
101///
102/// # Safety
103/// For integers, `rhs` must not contain any zero elements.
104/// Additionally for signed integers, `<int>::MIN / -1` is undefined behavior.
105#[rustc_intrinsic]
106#[rustc_nounwind]
107#[cfg(not(feature = "ferrocene_subset"))]
108pub const unsafe fn simd_rem<T>(lhs: T, rhs: T) -> T;
109
110/// Shifts vector left elementwise, with UB on overflow.
111///
112/// Shifts `lhs` left by `rhs`, shifting in sign bits for signed types.
113///
114/// `T` must be a vector of integers.
115///
116/// # Safety
117///
118/// Each element of `rhs` must be less than `<int>::BITS`.
119#[rustc_intrinsic]
120#[rustc_nounwind]
121#[cfg(not(feature = "ferrocene_subset"))]
122pub const unsafe fn simd_shl<T>(lhs: T, rhs: T) -> T;
123
124/// Shifts vector right elementwise, with UB on overflow.
125///
126/// `T` must be a vector of integers.
127///
128/// Shifts `lhs` right by `rhs`, shifting in sign bits for signed types.
129///
130/// # Safety
131///
132/// Each element of `rhs` must be less than `<int>::BITS`.
133#[rustc_intrinsic]
134#[rustc_nounwind]
135#[cfg(not(feature = "ferrocene_subset"))]
136pub const unsafe fn simd_shr<T>(lhs: T, rhs: T) -> T;
137
138/// Funnel Shifts vector left elementwise, with UB on overflow.
139///
140/// Concatenates `a` and `b` elementwise (with `a` in the most significant half),
141/// creating a vector of the same length, but with each element being twice as
142/// wide. Then shift this vector left elementwise by `shift`, shifting in zeros,
143/// and extract the most significant half of each of the elements. If `a` and `b`
144/// are the same, this is equivalent to an elementwise rotate left operation.
145///
146/// `T` must be a vector of integers.
147///
148/// # Safety
149///
150/// Each element of `shift` must be less than `<int>::BITS`.
151#[rustc_intrinsic]
152#[rustc_nounwind]
153#[cfg(not(feature = "ferrocene_subset"))]
154pub const unsafe fn simd_funnel_shl<T>(a: T, b: T, shift: T) -> T;
155
156/// Funnel Shifts vector right elementwise, with UB on overflow.
157///
158/// Concatenates `a` and `b` elementwise (with `a` in the most significant half),
159/// creating a vector of the same length, but with each element being twice as
160/// wide. Then shift this vector right elementwise by `shift`, shifting in zeros,
161/// and extract the least significant half of each of the elements. If `a` and `b`
162/// are the same, this is equivalent to an elementwise rotate right operation.
163///
164/// `T` must be a vector of integers.
165///
166/// # Safety
167///
168/// Each element of `shift` must be less than `<int>::BITS`.
169#[rustc_intrinsic]
170#[rustc_nounwind]
171#[cfg(not(feature = "ferrocene_subset"))]
172pub const unsafe fn simd_funnel_shr<T>(a: T, b: T, shift: T) -> T;
173
174/// "And"s vectors elementwise.
175///
176/// `T` must be a vector of integers.
177#[rustc_intrinsic]
178#[rustc_nounwind]
179#[cfg(not(feature = "ferrocene_subset"))]
180pub const unsafe fn simd_and<T>(x: T, y: T) -> T;
181
182/// "Ors" vectors elementwise.
183///
184/// `T` must be a vector of integers.
185#[rustc_intrinsic]
186#[rustc_nounwind]
187#[cfg(not(feature = "ferrocene_subset"))]
188pub const unsafe fn simd_or<T>(x: T, y: T) -> T;
189
190/// "Exclusive ors" vectors elementwise.
191///
192/// `T` must be a vector of integers.
193#[rustc_intrinsic]
194#[rustc_nounwind]
195pub const unsafe fn simd_xor<T>(x: T, y: T) -> T;
196
197/// Numerically casts a vector, elementwise.
198///
199/// `T` and `U` must be vectors of integers or floats, and must have the same length.
200///
201/// When casting floats to integers, the result is truncated. Out-of-bounds result lead to UB.
202/// When casting integers to floats, the result is rounded.
203/// Otherwise, truncates or extends the value, maintaining the sign for signed integers.
204///
205/// # Safety
206/// Casting from integer types is always safe.
207/// Casting between two float types is also always safe.
208///
209/// Casting floats to integers truncates, following the same rules as `to_int_unchecked`.
210/// Specifically, each element must:
211/// * Not be `NaN`
212/// * Not be infinite
213/// * Be representable in the return type, after truncating off its fractional part
214#[rustc_intrinsic]
215#[rustc_nounwind]
216#[cfg(not(feature = "ferrocene_subset"))]
217pub const unsafe fn simd_cast<T, U>(x: T) -> U;
218
219/// Numerically casts a vector, elementwise.
220///
221/// `T` and `U` be a vectors of integers or floats, and must have the same length.
222///
223/// Like `simd_cast`, but saturates float-to-integer conversions (NaN becomes 0).
224/// This matches regular `as` and is always safe.
225///
226/// When casting floats to integers, the result is truncated.
227/// When casting integers to floats, the result is rounded.
228/// Otherwise, truncates or extends the value, maintaining the sign for signed integers.
229#[rustc_intrinsic]
230#[rustc_nounwind]
231#[cfg(not(feature = "ferrocene_subset"))]
232pub const unsafe fn simd_as<T, U>(x: T) -> U;
233
234/// Negates a vector elementwise.
235///
236/// `T` must be a vector of integers or floats.
237///
238/// Rust panics for `-<int>::Min` due to overflow, but it is not UB with this intrinsic.
239#[rustc_intrinsic]
240#[rustc_nounwind]
241pub const unsafe fn simd_neg<T>(x: T) -> T;
242
243/// Returns absolute value of a vector, elementwise.
244///
245/// `T` must be a vector of floating-point primitive types.
246#[rustc_intrinsic]
247#[rustc_nounwind]
248#[cfg(not(feature = "ferrocene_subset"))]
249pub const unsafe fn simd_fabs<T>(x: T) -> T;
250
251/// Returns the minimum of two vectors, elementwise.
252///
253/// `T` must be a vector of floating-point primitive types.
254///
255/// Follows IEEE-754 `minNum` semantics.
256#[rustc_intrinsic]
257#[rustc_nounwind]
258#[cfg(not(feature = "ferrocene_subset"))]
259pub const unsafe fn simd_fmin<T>(x: T, y: T) -> T;
260
261/// Returns the maximum of two vectors, elementwise.
262///
263/// `T` must be a vector of floating-point primitive types.
264///
265/// Follows IEEE-754 `maxNum` semantics.
266#[rustc_intrinsic]
267#[rustc_nounwind]
268#[cfg(not(feature = "ferrocene_subset"))]
269pub const unsafe fn simd_fmax<T>(x: T, y: T) -> T;
270
271/// Tests elementwise equality of two vectors.
272///
273/// `T` must be a vector of integers or floats.
274///
275/// `U` must be a vector of integers with the same number of elements and element size as `T`.
276///
277/// Returns `0` for false and `!0` for true.
278#[rustc_intrinsic]
279#[rustc_nounwind]
280#[cfg(not(feature = "ferrocene_subset"))]
281pub const unsafe fn simd_eq<T, U>(x: T, y: T) -> U;
282
283/// Tests elementwise inequality equality of two vectors.
284///
285/// `T` must be a vector of integers or floats.
286///
287/// `U` must be a vector of integers with the same number of elements and element size as `T`.
288///
289/// Returns `0` for false and `!0` for true.
290#[rustc_intrinsic]
291#[rustc_nounwind]
292#[cfg(not(feature = "ferrocene_subset"))]
293pub const unsafe fn simd_ne<T, U>(x: T, y: T) -> U;
294
295/// Tests if `x` is less than `y`, elementwise.
296///
297/// `T` must be a vector of integers or floats.
298///
299/// `U` must be a vector of integers with the same number of elements and element size as `T`.
300///
301/// Returns `0` for false and `!0` for true.
302#[rustc_intrinsic]
303#[rustc_nounwind]
304#[cfg(not(feature = "ferrocene_subset"))]
305pub const unsafe fn simd_lt<T, U>(x: T, y: T) -> U;
306
307/// Tests if `x` is less than or equal to `y`, elementwise.
308///
309/// `T` must be a vector of integers or floats.
310///
311/// `U` must be a vector of integers with the same number of elements and element size as `T`.
312///
313/// Returns `0` for false and `!0` for true.
314#[rustc_intrinsic]
315#[rustc_nounwind]
316#[cfg(not(feature = "ferrocene_subset"))]
317pub const unsafe fn simd_le<T, U>(x: T, y: T) -> U;
318
319/// Tests if `x` is greater than `y`, elementwise.
320///
321/// `T` must be a vector of integers or floats.
322///
323/// `U` must be a vector of integers with the same number of elements and element size as `T`.
324///
325/// Returns `0` for false and `!0` for true.
326#[rustc_intrinsic]
327#[rustc_nounwind]
328#[cfg(not(feature = "ferrocene_subset"))]
329pub const unsafe fn simd_gt<T, U>(x: T, y: T) -> U;
330
331/// Tests if `x` is greater than or equal to `y`, elementwise.
332///
333/// `T` must be a vector of integers or floats.
334///
335/// `U` must be a vector of integers with the same number of elements and element size as `T`.
336///
337/// Returns `0` for false and `!0` for true.
338#[rustc_intrinsic]
339#[rustc_nounwind]
340#[cfg(not(feature = "ferrocene_subset"))]
341pub const unsafe fn simd_ge<T, U>(x: T, y: T) -> U;
342
343/// Shuffles two vectors by const indices.
344///
345/// `T` must be a vector.
346///
347/// `U` must be a **const** vector of `u32`s. This means it must either refer to a named
348/// const or be given as an inline const expression (`const { ... }`).
349///
350/// `V` must be a vector with the same element type as `T` and the same length as `U`.
351///
352/// Returns a new vector such that element `i` is selected from `xy[idx[i]]`, where `xy`
353/// is the concatenation of `x` and `y`. It is a compile-time error if `idx[i]` is out-of-bounds
354/// of `xy`.
355#[rustc_intrinsic]
356#[rustc_nounwind]
357pub const unsafe fn simd_shuffle<T, U, V>(x: T, y: T, idx: U) -> V;
358
359/// Reads a vector of pointers.
360///
361/// `T` must be a vector.
362///
363/// `U` must be a vector of pointers to the element type of `T`, with the same length as `T`.
364///
365/// `V` must be a vector of integers with the same length as `T` (but any element size).
366///
367/// For each pointer in `ptr`, if the corresponding value in `mask` is `!0`, read the pointer.
368/// Otherwise if the corresponding value in `mask` is `0`, return the corresponding value from
369/// `val`.
370///
371/// # Safety
372/// Unmasked values in `T` must be readable as if by `<ptr>::read` (e.g. aligned to the element
373/// type).
374///
375/// `mask` must only contain `0` or `!0` values.
376#[rustc_intrinsic]
377#[rustc_nounwind]
378#[cfg(not(feature = "ferrocene_subset"))]
379pub const unsafe fn simd_gather<T, U, V>(val: T, ptr: U, mask: V) -> T;
380
381/// Writes to a vector of pointers.
382///
383/// `T` must be a vector.
384///
385/// `U` must be a vector of pointers to the element type of `T`, with the same length as `T`.
386///
387/// `V` must be a vector of integers with the same length as `T` (but any element size).
388///
389/// For each pointer in `ptr`, if the corresponding value in `mask` is `!0`, write the
390/// corresponding value in `val` to the pointer.
391/// Otherwise if the corresponding value in `mask` is `0`, do nothing.
392///
393/// The stores happen in left-to-right order.
394/// (This is relevant in case two of the stores overlap.)
395///
396/// # Safety
397/// Unmasked values in `T` must be writeable as if by `<ptr>::write` (e.g. aligned to the element
398/// type).
399///
400/// `mask` must only contain `0` or `!0` values.
401#[rustc_intrinsic]
402#[rustc_nounwind]
403#[cfg(not(feature = "ferrocene_subset"))]
404pub const unsafe fn simd_scatter<T, U, V>(val: T, ptr: U, mask: V);
405
406/// A type for alignment options for SIMD masked load/store intrinsics.
407#[derive(Debug, ConstParamTy, PartialEq, Eq)]
408#[cfg(not(feature = "ferrocene_subset"))]
409pub enum SimdAlign {
410 // These values must match the compiler's `SimdAlign` defined in
411 // `rustc_middle/src/ty/consts/int.rs`!
412 /// No alignment requirements on the pointer
413 Unaligned = 0,
414 /// The pointer must be aligned to the element type of the SIMD vector
415 Element = 1,
416 /// The pointer must be aligned to the SIMD vector type
417 Vector = 2,
418}
419
420/// Reads a vector of pointers.
421///
422/// `T` must be a vector.
423///
424/// `U` must be a pointer to the element type of `T`
425///
426/// `V` must be a vector of integers with the same length as `T` (but any element size).
427///
428/// For each element, if the corresponding value in `mask` is `!0`, read the corresponding
429/// pointer offset from `ptr`.
430/// The first element is loaded from `ptr`, the second from `ptr.wrapping_offset(1)` and so on.
431/// Otherwise if the corresponding value in `mask` is `0`, return the corresponding value from
432/// `val`.
433///
434/// # Safety
435/// `ptr` must be aligned according to the `ALIGN` parameter, see [`SimdAlign`] for details.
436///
437/// `mask` must only contain `0` or `!0` values.
438#[rustc_intrinsic]
439#[rustc_nounwind]
440#[cfg(not(feature = "ferrocene_subset"))]
441pub const unsafe fn simd_masked_load<V, U, T, const ALIGN: SimdAlign>(mask: V, ptr: U, val: T)
442-> T;
443
444/// Writes to a vector of pointers.
445///
446/// `T` must be a vector.
447///
448/// `U` must be a pointer to the element type of `T`
449///
450/// `V` must be a vector of integers with the same length as `T` (but any element size).
451///
452/// For each element, if the corresponding value in `mask` is `!0`, write the corresponding
453/// value in `val` to the pointer offset from `ptr`.
454/// The first element is written to `ptr`, the second to `ptr.wrapping_offset(1)` and so on.
455/// Otherwise if the corresponding value in `mask` is `0`, do nothing.
456///
457/// # Safety
458/// `ptr` must be aligned according to the `ALIGN` parameter, see [`SimdAlign`] for details.
459///
460/// `mask` must only contain `0` or `!0` values.
461#[rustc_intrinsic]
462#[rustc_nounwind]
463#[cfg(not(feature = "ferrocene_subset"))]
464pub const unsafe fn simd_masked_store<V, U, T, const ALIGN: SimdAlign>(mask: V, ptr: U, val: T);
465
466/// Adds two simd vectors elementwise, with saturation.
467///
468/// `T` must be a vector of integer primitive types.
469#[rustc_intrinsic]
470#[rustc_nounwind]
471#[cfg(not(feature = "ferrocene_subset"))]
472pub const unsafe fn simd_saturating_add<T>(x: T, y: T) -> T;
473
474/// Subtracts two simd vectors elementwise, with saturation.
475///
476/// `T` must be a vector of integer primitive types.
477///
478/// Subtract `rhs` from `lhs`.
479#[rustc_intrinsic]
480#[rustc_nounwind]
481#[cfg(not(feature = "ferrocene_subset"))]
482pub const unsafe fn simd_saturating_sub<T>(lhs: T, rhs: T) -> T;
483
484/// Adds elements within a vector from left to right.
485///
486/// `T` must be a vector of integers or floats.
487///
488/// `U` must be the element type of `T`.
489///
490/// Starting with the value `y`, add the elements of `x` and accumulate.
491#[rustc_intrinsic]
492#[rustc_nounwind]
493#[cfg(not(feature = "ferrocene_subset"))]
494pub const unsafe fn simd_reduce_add_ordered<T, U>(x: T, y: U) -> U;
495
496/// Adds elements within a vector in arbitrary order. May also be re-associated with
497/// unordered additions on the inputs/outputs.
498///
499/// `T` must be a vector of integers or floats.
500///
501/// `U` must be the element type of `T`.
502#[rustc_intrinsic]
503#[rustc_nounwind]
504#[cfg(not(feature = "ferrocene_subset"))]
505pub unsafe fn simd_reduce_add_unordered<T, U>(x: T) -> U;
506
507/// Multiplies elements within a vector from left to right.
508///
509/// `T` must be a vector of integers or floats.
510///
511/// `U` must be the element type of `T`.
512///
513/// Starting with the value `y`, multiply the elements of `x` and accumulate.
514#[rustc_intrinsic]
515#[rustc_nounwind]
516#[cfg(not(feature = "ferrocene_subset"))]
517pub const unsafe fn simd_reduce_mul_ordered<T, U>(x: T, y: U) -> U;
518
519/// Multiplies elements within a vector in arbitrary order. May also be re-associated with
520/// unordered additions on the inputs/outputs.
521///
522/// `T` must be a vector of integers or floats.
523///
524/// `U` must be the element type of `T`.
525#[rustc_intrinsic]
526#[rustc_nounwind]
527#[cfg(not(feature = "ferrocene_subset"))]
528pub unsafe fn simd_reduce_mul_unordered<T, U>(x: T) -> U;
529
530/// Checks if all mask values are true.
531///
532/// `T` must be a vector of integer primitive types.
533///
534/// # Safety
535/// `x` must contain only `0` or `!0`.
536#[rustc_intrinsic]
537#[rustc_nounwind]
538#[cfg(not(feature = "ferrocene_subset"))]
539pub const unsafe fn simd_reduce_all<T>(x: T) -> bool;
540
541/// Checks if any mask value is true.
542///
543/// `T` must be a vector of integer primitive types.
544///
545/// # Safety
546/// `x` must contain only `0` or `!0`.
547#[rustc_intrinsic]
548#[rustc_nounwind]
549#[cfg(not(feature = "ferrocene_subset"))]
550pub const unsafe fn simd_reduce_any<T>(x: T) -> bool;
551
552/// Returns the maximum element of a vector.
553///
554/// `T` must be a vector of integers or floats.
555///
556/// `U` must be the element type of `T`.
557///
558/// For floating-point values, uses IEEE-754 `maxNum`.
559#[rustc_intrinsic]
560#[rustc_nounwind]
561#[cfg(not(feature = "ferrocene_subset"))]
562pub const unsafe fn simd_reduce_max<T, U>(x: T) -> U;
563
564/// Returns the minimum element of a vector.
565///
566/// `T` must be a vector of integers or floats.
567///
568/// `U` must be the element type of `T`.
569///
570/// For floating-point values, uses IEEE-754 `minNum`.
571#[rustc_intrinsic]
572#[rustc_nounwind]
573#[cfg(not(feature = "ferrocene_subset"))]
574pub const unsafe fn simd_reduce_min<T, U>(x: T) -> U;
575
576/// Logical "and"s all elements together.
577///
578/// `T` must be a vector of integers or floats.
579///
580/// `U` must be the element type of `T`.
581#[rustc_intrinsic]
582#[rustc_nounwind]
583#[cfg(not(feature = "ferrocene_subset"))]
584pub const unsafe fn simd_reduce_and<T, U>(x: T) -> U;
585
586/// Logical "ors" all elements together.
587///
588/// `T` must be a vector of integers or floats.
589///
590/// `U` must be the element type of `T`.
591#[rustc_intrinsic]
592#[rustc_nounwind]
593#[cfg(not(feature = "ferrocene_subset"))]
594pub const unsafe fn simd_reduce_or<T, U>(x: T) -> U;
595
596/// Logical "exclusive ors" all elements together.
597///
598/// `T` must be a vector of integers or floats.
599///
600/// `U` must be the element type of `T`.
601#[rustc_intrinsic]
602#[rustc_nounwind]
603#[cfg(not(feature = "ferrocene_subset"))]
604pub const unsafe fn simd_reduce_xor<T, U>(x: T) -> U;
605
606/// Truncates an integer vector to a bitmask.
607///
608/// `T` must be an integer vector.
609///
610/// `U` must be either the smallest unsigned integer with at least as many bits as the length
611/// of `T`, or the smallest array of `u8` with at least as many bits as the length of `T`.
612///
613/// Each element is truncated to a single bit and packed into the result.
614///
615/// No matter whether the output is an array or an unsigned integer, it is treated as a single
616/// contiguous list of bits. The bitmask is always packed on the least-significant side of the
617/// output, and padded with 0s in the most-significant bits. The order of the bits depends on
618/// endianness:
619///
620/// * On little endian, the least significant bit corresponds to the first vector element.
621/// * On big endian, the least significant bit corresponds to the last vector element.
622///
623/// For example, `[!0, 0, !0, !0]` packs to
624/// - `0b1101u8` or `[0b1101]` on little endian, and
625/// - `0b1011u8` or `[0b1011]` on big endian.
626///
627/// To consider a larger example,
628/// `[!0, 0, 0, 0, 0, 0, 0, 0, !0, !0, 0, 0, 0, 0, !0, 0]` packs to
629/// - `0b0100001100000001u16` or `[0b00000001, 0b01000011]` on little endian, and
630/// - `0b1000000011000010u16` or `[0b10000000, 0b11000010]` on big endian.
631///
632/// And finally, a non-power-of-2 example with multiple bytes:
633/// `[!0, !0, 0, !0, 0, 0, !0, 0, !0, 0]` packs to
634/// - `0b0101001011u16` or `[0b01001011, 0b01]` on little endian, and
635/// - `0b1101001010u16` or `[0b11, 0b01001010]` on big endian.
636///
637/// # Safety
638/// `x` must contain only `0` and `!0`.
639#[rustc_intrinsic]
640#[rustc_nounwind]
641#[cfg(not(feature = "ferrocene_subset"))]
642pub const unsafe fn simd_bitmask<T, U>(x: T) -> U;
643
644/// Selects elements from a mask.
645///
646/// `T` must be a vector.
647///
648/// `M` must be an integer vector with the same length as `T` (but any element size).
649///
650/// For each element, if the corresponding value in `mask` is `!0`, select the element from
651/// `if_true`. If the corresponding value in `mask` is `0`, select the element from
652/// `if_false`.
653///
654/// # Safety
655/// `mask` must only contain `0` and `!0`.
656#[rustc_intrinsic]
657#[rustc_nounwind]
658#[cfg(not(feature = "ferrocene_subset"))]
659pub const unsafe fn simd_select<M, T>(mask: M, if_true: T, if_false: T) -> T;
660
661/// Selects elements from a bitmask.
662///
663/// `M` must be an unsigned integer or array of `u8`, matching `simd_bitmask`.
664///
665/// `T` must be a vector.
666///
667/// For each element, if the bit in `mask` is `1`, select the element from
668/// `if_true`. If the corresponding bit in `mask` is `0`, select the element from
669/// `if_false`.
670/// The remaining bits of the mask are ignored.
671///
672/// The bitmask bit order matches `simd_bitmask`.
673#[rustc_intrinsic]
674#[rustc_nounwind]
675#[cfg(not(feature = "ferrocene_subset"))]
676pub const unsafe fn simd_select_bitmask<M, T>(m: M, yes: T, no: T) -> T;
677
678/// Calculates the offset from a pointer vector elementwise, potentially
679/// wrapping.
680///
681/// `T` must be a vector of pointers.
682///
683/// `U` must be a vector of `isize` or `usize` with the same number of elements as `T`.
684///
685/// Operates as if by `<ptr>::wrapping_offset`.
686#[rustc_intrinsic]
687#[rustc_nounwind]
688#[cfg(not(feature = "ferrocene_subset"))]
689pub const unsafe fn simd_arith_offset<T, U>(ptr: T, offset: U) -> T;
690
691/// Casts a vector of pointers.
692///
693/// `T` and `U` must be vectors of pointers with the same number of elements.
694#[rustc_intrinsic]
695#[rustc_nounwind]
696#[cfg(not(feature = "ferrocene_subset"))]
697pub const unsafe fn simd_cast_ptr<T, U>(ptr: T) -> U;
698
699/// Exposes a vector of pointers as a vector of addresses.
700///
701/// `T` must be a vector of pointers.
702///
703/// `U` must be a vector of `usize` with the same length as `T`.
704#[rustc_intrinsic]
705#[rustc_nounwind]
706#[cfg(not(feature = "ferrocene_subset"))]
707pub unsafe fn simd_expose_provenance<T, U>(ptr: T) -> U;
708
709/// Creates a vector of pointers from a vector of addresses.
710///
711/// `T` must be a vector of `usize`.
712///
713/// `U` must be a vector of pointers, with the same length as `T`.
714#[rustc_intrinsic]
715#[rustc_nounwind]
716#[cfg(not(feature = "ferrocene_subset"))]
717pub const unsafe fn simd_with_exposed_provenance<T, U>(addr: T) -> U;
718
719/// Swaps bytes of each element.
720///
721/// `T` must be a vector of integers.
722#[rustc_intrinsic]
723#[rustc_nounwind]
724#[cfg(not(feature = "ferrocene_subset"))]
725pub const unsafe fn simd_bswap<T>(x: T) -> T;
726
727/// Reverses bits of each element.
728///
729/// `T` must be a vector of integers.
730#[rustc_intrinsic]
731#[rustc_nounwind]
732#[cfg(not(feature = "ferrocene_subset"))]
733pub const unsafe fn simd_bitreverse<T>(x: T) -> T;
734
735/// Counts the leading zeros of each element.
736///
737/// `T` must be a vector of integers.
738#[rustc_intrinsic]
739#[rustc_nounwind]
740#[cfg(not(feature = "ferrocene_subset"))]
741pub const unsafe fn simd_ctlz<T>(x: T) -> T;
742
743/// Counts the number of ones in each element.
744///
745/// `T` must be a vector of integers.
746#[rustc_intrinsic]
747#[rustc_nounwind]
748#[cfg(not(feature = "ferrocene_subset"))]
749pub const unsafe fn simd_ctpop<T>(x: T) -> T;
750
751/// Counts the trailing zeros of each element.
752///
753/// `T` must be a vector of integers.
754#[rustc_intrinsic]
755#[rustc_nounwind]
756#[cfg(not(feature = "ferrocene_subset"))]
757pub const unsafe fn simd_cttz<T>(x: T) -> T;
758
759/// Rounds up each element to the next highest integer-valued float.
760///
761/// `T` must be a vector of floats.
762#[rustc_intrinsic]
763#[rustc_nounwind]
764#[cfg(not(feature = "ferrocene_subset"))]
765pub const unsafe fn simd_ceil<T>(x: T) -> T;
766
767/// Rounds down each element to the next lowest integer-valued float.
768///
769/// `T` must be a vector of floats.
770#[rustc_intrinsic]
771#[rustc_nounwind]
772#[cfg(not(feature = "ferrocene_subset"))]
773pub const unsafe fn simd_floor<T>(x: T) -> T;
774
775/// Rounds each element to the closest integer-valued float.
776/// Ties are resolved by rounding away from 0.
777///
778/// `T` must be a vector of floats.
779#[rustc_intrinsic]
780#[rustc_nounwind]
781#[cfg(not(feature = "ferrocene_subset"))]
782pub const unsafe fn simd_round<T>(x: T) -> T;
783
784/// Rounds each element to the closest integer-valued float.
785/// Ties are resolved by rounding to the number with an even least significant digit
786///
787/// `T` must be a vector of floats.
788#[rustc_intrinsic]
789#[rustc_nounwind]
790#[cfg(not(feature = "ferrocene_subset"))]
791pub const unsafe fn simd_round_ties_even<T>(x: T) -> T;
792
793/// Returns the integer part of each element as an integer-valued float.
794/// In other words, non-integer values are truncated towards zero.
795///
796/// `T` must be a vector of floats.
797#[rustc_intrinsic]
798#[rustc_nounwind]
799#[cfg(not(feature = "ferrocene_subset"))]
800pub const unsafe fn simd_trunc<T>(x: T) -> T;
801
802/// Takes the square root of each element.
803///
804/// `T` must be a vector of floats.
805#[rustc_intrinsic]
806#[rustc_nounwind]
807#[cfg(not(feature = "ferrocene_subset"))]
808pub unsafe fn simd_fsqrt<T>(x: T) -> T;
809
810/// Computes `(x*y) + z` for each element, but without any intermediate rounding.
811///
812/// `T` must be a vector of floats.
813#[rustc_intrinsic]
814#[rustc_nounwind]
815pub const unsafe fn simd_fma<T>(x: T, y: T, z: T) -> T;
816
817/// Computes `(x*y) + z` for each element, non-deterministically executing either
818/// a fused multiply-add or two operations with rounding of the intermediate result.
819///
820/// The operation is fused if the code generator determines that target instruction
821/// set has support for a fused operation, and that the fused operation is more efficient
822/// than the equivalent, separate pair of mul and add instructions. It is unspecified
823/// whether or not a fused operation is selected, and that may depend on optimization
824/// level and context, for example. It may even be the case that some SIMD lanes get fused
825/// and others do not.
826///
827/// `T` must be a vector of floats.
828#[rustc_intrinsic]
829#[rustc_nounwind]
830#[cfg(not(feature = "ferrocene_subset"))]
831pub const unsafe fn simd_relaxed_fma<T>(x: T, y: T, z: T) -> T;
832
833// Computes the sine of each element.
834///
835/// `T` must be a vector of floats.
836#[rustc_intrinsic]
837#[rustc_nounwind]
838#[cfg(not(feature = "ferrocene_subset"))]
839pub unsafe fn simd_fsin<T>(a: T) -> T;
840
841// Computes the cosine of each element.
842///
843/// `T` must be a vector of floats.
844#[rustc_intrinsic]
845#[rustc_nounwind]
846#[cfg(not(feature = "ferrocene_subset"))]
847pub unsafe fn simd_fcos<T>(a: T) -> T;
848
849// Computes the exponential function of each element.
850///
851/// `T` must be a vector of floats.
852#[rustc_intrinsic]
853#[rustc_nounwind]
854#[cfg(not(feature = "ferrocene_subset"))]
855pub unsafe fn simd_fexp<T>(a: T) -> T;
856
857// Computes 2 raised to the power of each element.
858///
859/// `T` must be a vector of floats.
860#[rustc_intrinsic]
861#[rustc_nounwind]
862#[cfg(not(feature = "ferrocene_subset"))]
863pub unsafe fn simd_fexp2<T>(a: T) -> T;
864
865// Computes the base 10 logarithm of each element.
866///
867/// `T` must be a vector of floats.
868#[rustc_intrinsic]
869#[rustc_nounwind]
870#[cfg(not(feature = "ferrocene_subset"))]
871pub unsafe fn simd_flog10<T>(a: T) -> T;
872
873// Computes the base 2 logarithm of each element.
874///
875/// `T` must be a vector of floats.
876#[rustc_intrinsic]
877#[rustc_nounwind]
878#[cfg(not(feature = "ferrocene_subset"))]
879pub unsafe fn simd_flog2<T>(a: T) -> T;
880
881// Computes the natural logarithm of each element.
882///
883/// `T` must be a vector of floats.
884#[rustc_intrinsic]
885#[rustc_nounwind]
886#[cfg(not(feature = "ferrocene_subset"))]
887pub unsafe fn simd_flog<T>(a: T) -> T;