From Jason Turner

[simd]

Large diff (130.1 KB) - rendering may be slow on some devices

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmppaz_l0yy/{from.md → to.md} +3299 -0
tmp/tmppaz_l0yy/{from.md → to.md} RENAMED
@@ -0,0 +1,3299 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Data-parallel types <a id="simd">[[simd]]</a>
2
+
3
+ ### General <a id="simd.general">[[simd.general]]</a>
4
+
5
+ Subclause [[simd]] defines data-parallel types and operations on these
6
+ types.
7
+
8
+ [*Note 1*: The intent is to support acceleration through data-parallel
9
+ execution resources where available, such as SIMD registers and
10
+ instructions or execution units driven by a common instruction decoder.
11
+ SIMD stands for “Single Instruction Stream – Multiple Data Stream”; it
12
+ is defined in Flynn 1966. — *end note*]
13
+
14
+ The set of *vectorizable types* comprises
15
+
16
+ - all standard integer types, character types, and the types `float` and
17
+ `double` [[basic.fundamental]];
18
+ - `std::float16_t`, `std::float32_t`, and `std::float64_t` if defined
19
+ [[basic.extended.fp]]; and
20
+ - `complex<T>` where `T` is a vectorizable floating-point type.
21
+
22
+ The term *data-parallel type* refers to all enabled specializations of
23
+ the `basic_vec` and `basic_mask` class templates. A
24
+ *data-parallel object* is an object of data-parallel type.
25
+
26
+ Each specialization of `basic_vec` or `basic_mask` is either enabled or
27
+ disabled, as described in [[simd.overview]] and [[simd.mask.overview]].
28
+
29
+ A data-parallel type consists of one or more elements of an underlying
30
+ vectorizable type, called the *element type*. The number of elements is
31
+ a constant for each data-parallel type and called the *width* of that
32
+ type. The elements in a data-parallel type are indexed from 0 to
33
+ $\textrm{width} - 1$.
34
+
35
+ An *element-wise operation* applies a specified operation to the
36
+ elements of one or more data-parallel objects. Each such application is
37
+ unsequenced with respect to the others. A *unary element-wise operation*
38
+ is an element-wise operation that applies a unary operation to each
39
+ element of a data-parallel object. A *binary element-wise operation* is
40
+ an element-wise operation that applies a binary operation to
41
+ corresponding elements of two data-parallel objects.
42
+
43
+ Given a `basic_mask<Bytes, Abi>` object `mask`, the *selected indices*
44
+ signify the integers i in the range \[`0`, `mask.size()`) for which
45
+ `mask[i]` is `true`. Given a data-parallel object `data`, the
46
+ *selected elements* signify the elements `data[i]` for all selected
47
+ indices i.
48
+
49
+ The conversion from an arithmetic type `U` to a vectorizable type `T` is
50
+ *value-preserving* if all possible values of `U` can be represented with
51
+ type `T`.
52
+
53
+ ### Exposition-only types, variables, and concepts <a id="simd.expos">[[simd.expos]]</a>
54
+
55
+ ``` cpp
56
+ using simd-size-type = see belownc; // exposition only
57
+ template<size_t Bytes> using integer-from = see belownc; // exposition only
58
+
59
+ template<class T, class Abi>
60
+ constexpr simd-size-type simd-size-v = see belownc; // exposition only
61
+ template<class T> constexpr size_t mask-element-size = see belownc; // exposition only
62
+
63
+ template<class T>
64
+ concept constexpr-wrapper-like = // exposition only
65
+ convertible_to<T, decltype(T::value)> &&
66
+ equality_comparable_with<T, decltype(T::value)> &&
67
+ bool_constant<T() == T::value>::value &&
68
+ bool_constant<static_cast<decltype(T::value)>(T()) == T::value>::value;
69
+
70
+ template<class T> using deduced-vec-t = see belownc; // exposition only
71
+
72
+ template<class V, class T> using make-compatible-simd-t = see belownc; // exposition only
73
+
74
+ template<class V>
75
+ concept simd-vec-type = // exposition only
76
+ same_as<V, basic_vec<typename V::value_type, typename V::abi_type>> &&
77
+ is_default_constructible_v<V>;
78
+
79
+ template<class V>
80
+ concept simd-mask-type = // exposition only
81
+ same_as<V, basic_mask<mask-element-size<V>, typename V::abi_type>> &&
82
+ is_default_constructible_v<V>;
83
+
84
+ template<class V>
85
+ concept simd-floating-point = // exposition only
86
+ simd-vec-type<V> && floating_point<typename V::value_type>;
87
+
88
+ template<class V>
89
+ concept simd-integral = // exposition only
90
+ simd-vec-type<V> && integral<typename V::value_type>;
91
+
92
+ template<class V>
93
+ using simd-complex-value-type = V::value_type::value_type; // exposition only
94
+
95
+ template<class V>
96
+ concept simd-complex = // exposition only
97
+ simd-vec-type<V> && same_as<typename V::value_type, complex<simd-complex-value-type<V>>>;
98
+
99
+ template<class... Ts>
100
+ concept math-floating-point = // exposition only
101
+ (exposition onlyconceptnc{simd-floating-point}<deduced-vec-t<Ts>> || ...);
102
+
103
+ template<class... Ts>
104
+ requires exposition onlyconceptnc{math-floating-point}<Ts...>
105
+ using math-common-simd-t = see belownc; // exposition only
106
+
107
+ template<class BinaryOperation, class T>
108
+ concept exposition onlyconceptnc{reduction-binary-operation} = see belownc; // exposition only
109
+
110
+ // [simd.expos.abi], simd ABI tags
111
+ template<class T> using native-abi = see belownc; // exposition only
112
+ template<class T, simd-size-type N> using deduce-abi-t = see belownc@; // exposition only
113
+
114
+ // [simd.flags], load and store flags
115
+ struct convert-flag; // exposition only
116
+ struct aligned-flag; // exposition only
117
+ template<size_t N> struct overaligned-flag; // exposition only
118
+ ```
119
+
120
+ #### Exposition-only helpers <a id="simd.expos.defn">[[simd.expos.defn]]</a>
121
+
122
+ ``` cpp
123
+ using simd-size-type = see below;
124
+ ```
125
+
126
+ *simd-size-type* is an alias for a signed integer type.
127
+
128
+ ``` cpp
129
+ template<size_t Bytes> using integer-from = see below;
130
+ ```
131
+
132
+ *`integer-from`*`<Bytes>` is an alias for a signed integer type `T` such
133
+ that `sizeof(T)` equals `Bytes`.
134
+
135
+ ``` cpp
136
+ template<class T, class Abi>
137
+ constexpr simd-size-type simd-size-v = see below;
138
+ ```
139
+
140
+ *`simd-size-v`*`<T, Abi>` denotes the width of `basic_vec<T, Abi>` if
141
+ the specialization `basic_vec<T, Abi>` is enabled, or `0` otherwise.
142
+
143
+ ``` cpp
144
+ template<class T> constexpr size_t mask-element-size = see below;
145
+ ```
146
+
147
+ *`mask-element-size`*`<basic_mask<Bytes, Abi>>` has the value `Bytes`.
148
+
149
+ ``` cpp
150
+ template<class T> using deduced-vec-t = see below;
151
+ ```
152
+
153
+ Let `x` denote an lvalue of type `const T`.
154
+
155
+ *`deduced-vec-t`*`<T>` is an alias for
156
+
157
+ - `decltype(x + x)`, if the type of `x + x` is an enabled specialization
158
+ of `basic_vec`; otherwise
159
+ - `void`.
160
+
161
+ ``` cpp
162
+ template<class V, class T> using make-compatible-simd-t = see below;
163
+ ```
164
+
165
+ Let `x` denote an lvalue of type `const T`.
166
+
167
+ *`make-compatible-simd-t`*`<V, T>` is an alias for
168
+
169
+ - *`deduced-vec-t`*`<T>`, if that type is not `void`, otherwise
170
+ - `vec<decltype(x + x), V::size()>`.
171
+
172
+ ``` cpp
173
+ template<class... Ts>
174
+ requires math-floating-point<Ts...>
175
+ using math-common-simd-t = see below;
176
+ ```
177
+
178
+ Let `T0` denote `Ts...[0]`. Let `T1` denote `Ts...[1]`. Let `TRest`
179
+ denote a pack such that `T0, T1, TRest...` is equivalent to `Ts...`.
180
+
181
+ Let *`math-common-simd-t`*`<Ts...>` be an alias for
182
+
183
+ - *`deduced-vec-t`*`<T0>`, if `sizeof...(Ts)` equals 1; otherwise
184
+ - `common_type_t<`*`deduced-vec-t`*`<T0>, `*`deduced-vec-t`*`<T1>>`, if
185
+ `sizeof...(Ts)` equals 2 and
186
+ `math-floating-point<T0> && math-floating-point<T1>` is `true`;
187
+ otherwise
188
+ - `common_type_t<`*`deduced-vec-t`*`<T0>, T1>`, if `sizeof...(Ts)`
189
+ equals 2 and *`math-floating-point`*`<T0>` is `true`; otherwise
190
+ - `common_type_t<T0, `*`deduced-vec-t`*`<T1>>`, if `sizeof...(Ts)`
191
+ equals 2; otherwise
192
+ - `common_type_t<`*`math-common-simd-t`*`<T0, T1>, TRest...>`, if
193
+ *`math-common-simd-t`*`<T0, T1>` is valid and denotes a type;
194
+ otherwise
195
+ - `common_type_t<`*`math-common-simd-t`*`<TRest...>, T0, T1>`.
196
+
197
+ ``` cpp
198
+ template<class BinaryOperation, class T>
199
+ concept reduction-binary-operation =
200
+ requires (const BinaryOperation binary_op, const vec<T, 1> v) {
201
+ { binary_op(v, v) } -> same_as<vec<T, 1>>;
202
+ };
203
+ ```
204
+
205
+ Types `BinaryOperation` and `T` model
206
+ `reduction-binary-operation<BinaryOperation, T>` only if:
207
+
208
+ - `BinaryOperation` is a binary element-wise operation and the operation
209
+ is commutative.
210
+ - An object of type `BinaryOperation` can be invoked with two arguments
211
+ of type `basic_vec<T, Abi>`, with unspecified ABI tag `Abi`, returning
212
+ a `basic_vec<T, Abi>`.
213
+
214
+ #### `simd` ABI tags <a id="simd.expos.abi">[[simd.expos.abi]]</a>
215
+
216
+ ``` cpp
217
+ template<class T> using native-abi = see below;
218
+ template<class T, simd-size-type N> using deduce-abi-t = see below;
219
+ ```
220
+
221
+ An *ABI tag* is a type that indicates a choice of size and binary
222
+ representation for objects of data-parallel type.
223
+
224
+ [*Note 1*: The intent is for the size and binary representation to
225
+ depend on the target architecture and compiler flags. The ABI tag,
226
+ together with a given element type, implies the width. — *end note*]
227
+
228
+ [*Note 2*: The ABI tag is orthogonal to selecting the machine
229
+ instruction set. The selected machine instruction set limits the usable
230
+ ABI tag types, though (see [[simd.overview]]). The ABI tags enable users
231
+ to safely pass objects of data-parallel type between translation unit
232
+ boundaries (e.g., function calls or I/O). — *end note*]
233
+
234
+ An implementation defines ABI tag types as necessary for the following
235
+ aliases.
236
+
237
+ *`deduce-abi-t`*`<T, N>` is defined if
238
+
239
+ - `T` is a vectorizable type,
240
+ - `N` is greater than zero, and
241
+ - `N` is not larger than an implementation-defined maximum.
242
+
243
+ The *implementation-defined* maximum for `N` is not smaller than 64 and
244
+ can differ depending on `T`.
245
+
246
+ Where present, *`deduce-abi-t`*`<T, N>` names an ABI tag type such that
247
+
248
+ - *`simd-size-v`*`<T, `*`deduce-abi-t`*`<T, N>>` equals `N`,
249
+ - `basic_vec<T, `*`deduce-abi-t`*`<T, N>>` is enabled [[simd.overview]],
250
+ and
251
+ - `basic_mask<sizeof(T), `*`deduce-abi-t`*`<`*`integer-from`*`<sizeof(T)>, N>>`
252
+ is enabled.
253
+
254
+ *`native-abi`*`<T>` is an *implementation-defined* alias for an ABI tag.
255
+ `basic_vec<T, `*`native-abi`*`<T>>` is an enabled specialization.
256
+
257
+ [*Note 3*: The intent is to use the ABI tag producing the most
258
+ efficient data-parallel execution for the element type `T` on the
259
+ currently targeted system. For target architectures with ISA extensions,
260
+ compiler flags can change the type of the *`native-abi`*`<T>`
261
+ alias. — *end note*]
262
+
263
+ [*Example 1*:
264
+
265
+ Consider a target architecture supporting the ABI tags `__simd128` and
266
+ `__simd256`, where hardware support for `__simd256` exists only for
267
+ floating-point types. The implementation therefore defines
268
+ *`native-abi`*`<T>` as an alias for
269
+
270
+ - `__simd256` if `T` is a floating-point type, and
271
+ - `__simd128` otherwise.
272
+
273
+ — *end example*]
274
+
275
+ ### Header `<simd>` synopsis <a id="simd.syn">[[simd.syn]]</a>
276
+
277
+ ``` cpp
278
+ namespace std::simd {
279
+ // [simd.traits], type traits
280
+ template<class T, class U = typename T::value_type> struct alignment;
281
+ template<class T, class U = typename T::value_type>
282
+ constexpr size_t alignment_v = alignment<T, U>::value;
283
+
284
+ template<class T, class V> struct rebind { using type = see below; };
285
+ template<class T, class V> using rebind_t = rebind<T, V>::type;
286
+ template<simd-size-type N, class V> struct resize { using type = see below; };
287
+ template<simd-size-type N, class V> using resize_t = resize<N, V>::type;
288
+
289
+ // [simd.flags], load and store flags
290
+ template<class... Flags> struct flags;
291
+ inline constexpr flags<> flag_default{};
292
+ inline constexpr flags<convert-flag> flag_convert{};
293
+ inline constexpr flags<aligned-flag> flag_aligned{};
294
+ template<size_t N> requires (has_single_bit(N))
295
+ constexpr flags<overaligned-flag<N>> flag_overaligned{};
296
+
297
+ // [simd.iterator], class template simd-iterator
298
+ template<class V>
299
+ class simd-iterator; // exposition only
300
+
301
+ // [simd.class], class template basic_vec
302
+ template<class T, class Abi = native-abi<T>> class basic_vec;
303
+ template<class T, simd-size-type N = simd-size-v<T, native-abi<T>>>
304
+ using vec = basic_vec<T, deduce-abi-t<T, N>>;
305
+
306
+ // [simd.reductions], reductions
307
+ template<class T, class Abi, class BinaryOperation = plus<>>
308
+ constexpr T reduce(const basic_vec<T, Abi>&, BinaryOperation = {});
309
+ template<class T, class Abi, class BinaryOperation = plus<>>
310
+ constexpr T reduce(
311
+ const basic_vec<T, Abi>& x, const typename basic_vec<T, Abi>::mask_type& mask,
312
+ BinaryOperation binary_op = {}, type_identity_t<T> identity_element = see below);
313
+
314
+ template<class T, class Abi>
315
+ constexpr T reduce_min(const basic_vec<T, Abi>&) noexcept;
316
+ template<class T, class Abi>
317
+ constexpr T reduce_min(const basic_vec<T, Abi>&,
318
+ const typename basic_vec<T, Abi>::mask_type&) noexcept;
319
+ template<class T, class Abi>
320
+ constexpr T reduce_max(const basic_vec<T, Abi>&) noexcept;
321
+ template<class T, class Abi>
322
+ constexpr T reduce_max(const basic_vec<T, Abi>&,
323
+ const typename basic_vec<T, Abi>::mask_type&) noexcept;
324
+
325
+ // [simd.loadstore], load and store functions
326
+ template<class V = see below, ranges::contiguous_range R, class... Flags>
327
+ requires ranges::sized_range<R>
328
+ constexpr V unchecked_load(R&& r, flags<Flags...> f = {});
329
+ template<class V = see below, ranges::contiguous_range R, class... Flags>
330
+ requires ranges::sized_range<R>
331
+ constexpr V unchecked_load(R&& r, const typename V::mask_type& k,
332
+ flags<Flags...> f = {});
333
+ template<class V = see below, contiguous_iterator I, class... Flags>
334
+ constexpr V unchecked_load(I first, iter_difference_t<I> n,
335
+ flags<Flags...> f = {});
336
+ template<class V = see below, contiguous_iterator I, class... Flags>
337
+ constexpr V unchecked_load(I first, iter_difference_t<I> n,
338
+ const typename V::mask_type& k, flags<Flags...> f = {});
339
+ template<class V = see below, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags>
340
+ constexpr V unchecked_load(I first, S last, flags<Flags...> f = {});
341
+ template<class V = see below, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags>
342
+ constexpr V unchecked_load(I first, S last, const typename V::mask_type& k,
343
+ flags<Flags...> f = {});
344
+
345
+ template<class V = see below, ranges::contiguous_range R, class... Flags>
346
+ requires ranges::sized_range<R>
347
+ constexpr V partial_load(R&& r, flags<Flags...> f = {});
348
+ template<class V = see below, ranges::contiguous_range R, class... Flags>
349
+ requires ranges::sized_range<R>
350
+ constexpr V partial_load(R&& r, const typename V::mask_type& k,
351
+ flags<Flags...> f = {});
352
+ template<class V = see below, contiguous_iterator I, class... Flags>
353
+ constexpr V partial_load(I first, iter_difference_t<I> n, flags<Flags...> f = {});
354
+ template<class V = see below, contiguous_iterator I, class... Flags>
355
+ constexpr V partial_load(I first, iter_difference_t<I> n,
356
+ const typename V::mask_type& k, flags<Flags...> f = {});
357
+ template<class V = see below, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags>
358
+ constexpr V partial_load(I first, S last, flags<Flags...> f = {});
359
+ template<class V = see below, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags>
360
+ constexpr V partial_load(I first, S last, const typename V::mask_type& k,
361
+ flags<Flags...> f = {});
362
+
363
+ template<class T, class Abi, ranges::contiguous_range R, class... Flags>
364
+ requires ranges::sized_range<R> && indirectly_writable<ranges::iterator_t<R>, T>
365
+ constexpr void unchecked_store(const basic_vec<T, Abi>& v, R&& r,
366
+ flags<Flags...> f = {});
367
+ template<class T, class Abi, ranges::contiguous_range R, class... Flags>
368
+ requires ranges::sized_range<R> && indirectly_writable<ranges::iterator_t<R>, T>
369
+ constexpr void unchecked_store(const basic_vec<T, Abi>& v, R&& r,
370
+ const typename basic_vec<T, Abi>::mask_type& mask, flags<Flags...> f = {});
371
+ template<class T, class Abi, contiguous_iterator I, class... Flags>
372
+ requires indirectly_writable<I, T>
373
+ constexpr void unchecked_store(const basic_vec<T, Abi>& v, I first,
374
+ iter_difference_t<I> n, flags<Flags...> f = {});
375
+ template<class T, class Abi, contiguous_iterator I, class... Flags>
376
+ requires indirectly_writable<I, T>
377
+ constexpr void unchecked_store(const basic_vec<T, Abi>& v, I first,
378
+ iter_difference_t<I> n, const typename basic_vec<T, Abi>::mask_type& mask,
379
+ flags<Flags...> f = {});
380
+ template<class T, class Abi, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags>
381
+ requires indirectly_writable<I, T>
382
+ constexpr void unchecked_store(const basic_vec<T, Abi>& v, I first, S last,
383
+ flags<Flags...> f = {});
384
+ template<class T, class Abi, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags>
385
+ requires indirectly_writable<I, T>
386
+ constexpr void unchecked_store(const basic_vec<T, Abi>& v, I first, S last,
387
+ const typename basic_vec<T, Abi>::mask_type& mask, flags<Flags...> f = {});
388
+
389
+ template<class T, class Abi, ranges::contiguous_range R, class... Flags>
390
+ requires ranges::sized_range<R> && indirectly_writable<ranges::iterator_t<R>, T>
391
+ constexpr void partial_store(const basic_vec<T, Abi>& v, R&& r,
392
+ flags<Flags...> f = {});
393
+ template<class T, class Abi, ranges::contiguous_range R, class... Flags>
394
+ requires ranges::sized_range<R> && indirectly_writable<ranges::iterator_t<R>, T>
395
+ constexpr void partial_store(const basic_vec<T, Abi>& v, R&& r,
396
+ const typename basic_vec<T, Abi>::mask_type& mask, flags<Flags...> f = {});
397
+ template<class T, class Abi, contiguous_iterator I, class... Flags>
398
+ requires indirectly_writable<I, T>
399
+ constexpr void partial_store(
400
+ const basic_vec<T, Abi>& v, I first, iter_difference_t<I> n, flags<Flags...> f = {});
401
+ template<class T, class Abi, contiguous_iterator I, class... Flags>
402
+ requires indirectly_writable<I, T>
403
+ constexpr void partial_store(
404
+ const basic_vec<T, Abi>& v, I first, iter_difference_t<I> n,
405
+ const typename basic_vec<T, Abi>::mask_type& mask, flags<Flags...> f = {});
406
+ template<class T, class Abi, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags>
407
+ requires indirectly_writable<I, T>
408
+ constexpr void partial_store(const basic_vec<T, Abi>& v, I first, S last,
409
+ flags<Flags...> f = {});
410
+ template<class T, class Abi, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags>
411
+ requires indirectly_writable<I, T>
412
+ constexpr void partial_store(const basic_vec<T, Abi>& v, I first, S last,
413
+ const typename basic_vec<T, Abi>::mask_type& mask, flags<Flags...> f = {});
414
+
415
+ // [simd.permute.static], static permute
416
+ static constexpr simd-size-type zero_element = implementation-defined // value of simd::zero_element;
417
+ static constexpr simd-size-type uninit_element = implementation-defined // value of simd::uninit_element;
418
+
419
+ template<simd-size-type N = see below, simd-vec-type V, class IdxMap>
420
+ constexpr resize_t<N, V> permute(const V& v, IdxMap&& idxmap);
421
+ template<simd-size-type N = see below, simd-mask-type M, class IdxMap>
422
+ constexpr resize_t<N, M> permute(const M& v, IdxMap&& idxmap);
423
+
424
+ // [simd.permute.dynamic], dynamic permute
425
+ template<simd-vec-type V, simd-integral I>
426
+ constexpr resize_t<I::size(), V> permute(const V& v, const I& indices);
427
+ template<simd-mask-type M, simd-integral I>
428
+ constexpr resize_t<I::size(), M> permute(const M& v, const I& indices);
429
+
430
+ // [simd.permute.mask], mask permute
431
+ template<simd-vec-type V>
432
+ constexpr V compress(const V& v, const typename V::mask_type& selector);
433
+ template<simd-mask-type M>
434
+ constexpr M compress(const M& v, const type_identity_t<M>& selector);
435
+ template<simd-vec-type V>
436
+ constexpr V compress(const V& v, const typename V::mask_type& selector,
437
+ const typename V::value_type& fill_value);
438
+ template<simd-mask-type M>
439
+ constexpr M compress(const M& v, const type_identity_t<M>& selector,
440
+ const typename M::value_type& fill_value);
441
+
442
+ template<simd-vec-type V>
443
+ constexpr V expand(const V& v, const typename V::mask_type& selector,
444
+ const V& original = {});
445
+ template<simd-mask-type M>
446
+ constexpr M expand(const M& v, const type_identity_t<M>& selector,
447
+ const M& original = {});
448
+
449
+ // [simd.permute.memory], memory permute
450
+ template<class V = see below, ranges::contiguous_range R, simd-integral I, class... Flags>
451
+ requires ranges::sized_range<R>
452
+ constexpr V unchecked_gather_from(R&& in, const I& indices, flags<Flags...> f = {});
453
+ template<class V = see below, ranges::contiguous_range R, simd-integral I, class... Flags>
454
+ requires ranges::sized_range<R>
455
+ constexpr V unchecked_gather_from(R&& in, const typename I::mask_type& mask,
456
+ const I& indices, flags<Flags...> f = {});
457
+
458
+ template<class V = see below, ranges::contiguous_range R, simd-integral I, class... Flags>
459
+ requires ranges::sized_range<R>
460
+ constexpr V partial_gather_from(R&& in, const I& indices, flags<Flags...> f = {});
461
+ template<class V = see below, ranges::contiguous_range R, simd-integral I, class... Flags>
462
+ requires ranges::sized_range<R>
463
+ constexpr V partial_gather_from(R&& in, const typename I::mask_type& mask,
464
+ const I& indices, flags<Flags...> f = {});
465
+
466
+ template<simd-vec-type V, ranges::contiguous_range R, simd-integral I, class... Flags>
467
+ requires ranges::sized_range<R>
468
+ constexpr void unchecked_scatter_to(const V& v, R&& out,
469
+ const I& indices, flags<Flags...> f = {});
470
+ template<simd-vec-type V, ranges::contiguous_range R, simd-integral I, class... Flags>
471
+ requires ranges::sized_range<R>
472
+ constexpr void unchecked_scatter_to(const V& v, R&& out, const typename I::mask_type& mask,
473
+ const I& indices, flags<Flags...> f = {});
474
+
475
+ template<simd-vec-type V, ranges::contiguous_range R, simd-integral I, class... Flags>
476
+ requires ranges::sized_range<R>
477
+ constexpr void partial_scatter_to(const V& v, R&& out,
478
+ const I& indices, flags<Flags...> f = {});
479
+ template<simd-vec-type V, ranges::contiguous_range R, simd-integral I, class... Flags>
480
+ requires ranges::sized_range<R>
481
+ constexpr void partial_scatter_to(const V& v, R&& out, const typename I::mask_type& mask,
482
+ const I& indices, flags<Flags...> f = {});
483
+
484
+ // [simd.creation], creation
485
+ template<class T, class Abi>
486
+ constexpr auto chunk(const basic_vec<typename T::value_type, Abi>& x) noexcept;
487
+ template<class T, class Abi>
488
+ constexpr auto chunk(const basic_mask<mask-element-size<T>, Abi>& x) noexcept;
489
+
490
+ template<simd-size-type N, class T, class Abi>
491
+ constexpr auto chunk(const basic_vec<T, Abi>& x) noexcept;
492
+ template<simd-size-type N, size_t Bytes, class Abi>
493
+ constexpr auto chunk(const basic_mask<Bytes, Abi>& x) noexcept;
494
+
495
+ template<class T, class... Abis>
496
+ constexpr basic_vec<T, deduce-abi-t<T, (basic_vec<T, Abis>::size() + ...)>>
497
+ cat(const basic_vec<T, Abis>&...) noexcept;
498
+ template<size_t Bytes, class... Abis>
499
+ constexpr basic_mask<Bytes, deduce-abi-t<integer-from<Bytes>,
500
+ (basic_mask<Bytes, Abis>::size() + ...)>>
501
+ cat(const basic_mask<Bytes, Abis>&...) noexcept;
502
+
503
+ // [simd.alg], algorithms
504
+ template<class T, class Abi>
505
+ constexpr basic_vec<T, Abi>
506
+ min(const basic_vec<T, Abi>& a, const basic_vec<T, Abi>& b) noexcept;
507
+ template<class T, class Abi>
508
+ constexpr basic_vec<T, Abi>
509
+ max(const basic_vec<T, Abi>& a, const basic_vec<T, Abi>& b) noexcept;
510
+ template<class T, class Abi>
511
+ constexpr pair<basic_vec<T, Abi>, basic_vec<T, Abi>>
512
+ minmax(const basic_vec<T, Abi>& a, const basic_vec<T, Abi>& b) noexcept;
513
+ template<class T, class Abi>
514
+ constexpr basic_vec<T, Abi>
515
+ clamp(const basic_vec<T, Abi>& v, const basic_vec<T, Abi>& lo,
516
+ const basic_vec<T, Abi>& hi);
517
+
518
+ template<class T, class U>
519
+ constexpr auto select(bool c, const T& a, const U& b)
520
+ -> remove_cvref_t<decltype(c ? a : b)>;
521
+ template<size_t Bytes, class Abi, class T, class U>
522
+ constexpr auto select(const basic_mask<Bytes, Abi>& c, const T& a, const U& b)
523
+ noexcept -> decltype(simd-select-impl(c, a, b));
524
+
525
+ // [simd.math], mathematical functions
526
+ template<math-floating-point V> constexpr deduced-vec-t<V> acos(const V& x);
527
+ template<math-floating-point V> constexpr deduced-vec-t<V> asin(const V& x);
528
+ template<math-floating-point V> constexpr deduced-vec-t<V> atan(const V& x);
529
+ template<class V0, class V1>
530
+ constexpr math-common-simd-t<V0, V1> atan2(const V0& y, const V1& x);
531
+ template<math-floating-point V> constexpr deduced-vec-t<V> cos(const V& x);
532
+ template<math-floating-point V> constexpr deduced-vec-t<V> sin(const V& x);
533
+ template<math-floating-point V> constexpr deduced-vec-t<V> tan(const V& x);
534
+ template<math-floating-point V> constexpr deduced-vec-t<V> acosh(const V& x);
535
+ template<math-floating-point V> constexpr deduced-vec-t<V> asinh(const V& x);
536
+ template<math-floating-point V> constexpr deduced-vec-t<V> atanh(const V& x);
537
+ template<math-floating-point V> constexpr deduced-vec-t<V> cosh(const V& x);
538
+ template<math-floating-point V> constexpr deduced-vec-t<V> sinh(const V& x);
539
+ template<math-floating-point V> constexpr deduced-vec-t<V> tanh(const V& x);
540
+ template<math-floating-point V> constexpr deduced-vec-t<V> exp(const V& x);
541
+ template<math-floating-point V> constexpr deduced-vec-t<V> exp2(const V& x);
542
+ template<math-floating-point V> constexpr deduced-vec-t<V> expm1(const V& x);
543
+ template<math-floating-point V>
544
+ constexpr deduced-vec-t<V>
545
+ frexp(const V& value, rebind_t<int, deduced-vec-t<V>>* exp);
546
+ template<math-floating-point V>
547
+ constexpr rebind_t<int, deduced-vec-t<V>> ilogb(const V& x);
548
+ template<math-floating-point V>
549
+ constexpr deduced-vec-t<V> ldexp(const V& x, const rebind_t<int, deduced-vec-t<V>>& exp);
550
+ template<math-floating-point V> constexpr deduced-vec-t<V> log(const V& x);
551
+ template<math-floating-point V> constexpr deduced-vec-t<V> log10(const V& x);
552
+ template<math-floating-point V> constexpr deduced-vec-t<V> log1p(const V& x);
553
+ template<math-floating-point V> constexpr deduced-vec-t<V> log2(const V& x);
554
+ template<math-floating-point V> constexpr deduced-vec-t<V> logb(const V& x);
555
+ template<class T, class Abi>
556
+ constexpr basic_vec<T, Abi>
557
+ modf(const type_identity_t<basic_vec<T, Abi>>& value, basic_vec<T, Abi>* iptr);
558
+ template<math-floating-point V>
559
+ constexpr deduced-vec-t<V> scalbn(const V& x, const rebind_t<int, deduced-vec-t<V>>& n);
560
+ template<math-floating-point V>
561
+ constexpr deduced-vec-t<V> scalbln(
562
+ const V& x, const rebind_t<long int, deduced-vec-t<V>>& n);
563
+ template<math-floating-point V> constexpr deduced-vec-t<V> cbrt(const V& x);
564
+ template<signed_integral T, class Abi>
565
+ constexpr basic_vec<T, Abi> abs(const basic_vec<T, Abi>& j);
566
+ template<math-floating-point V> constexpr deduced-vec-t<V> abs(const V& j);
567
+ template<math-floating-point V> constexpr deduced-vec-t<V> fabs(const V& x);
568
+ template<class V0, class V1>
569
+ constexpr math-common-simd-t<V0, V1> hypot(const V0& x, const V1& y);
570
+ template<class V0, class V1, class V2>
571
+ constexpr math-common-simd-t<V0, V1, V2> hypot(const V0& x, const V1& y, const V2& z);
572
+ template<class V0, class V1>
573
+ constexpr math-common-simd-t<V0, V1> pow(const V0& x, const V1& y);
574
+ template<math-floating-point V> constexpr deduced-vec-t<V> sqrt(const V& x);
575
+ template<math-floating-point V> constexpr deduced-vec-t<V> erf(const V& x);
576
+ template<math-floating-point V> constexpr deduced-vec-t<V> erfc(const V& x);
577
+ template<math-floating-point V> constexpr deduced-vec-t<V> lgamma(const V& x);
578
+ template<math-floating-point V> constexpr deduced-vec-t<V> tgamma(const V& x);
579
+ template<math-floating-point V> constexpr deduced-vec-t<V> ceil(const V& x);
580
+ template<math-floating-point V> constexpr deduced-vec-t<V> floor(const V& x);
581
+ template<math-floating-point V> deduced-vec-t<V> nearbyint(const V& x);
582
+ template<math-floating-point V> deduced-vec-t<V> rint(const V& x);
583
+ template<math-floating-point V>
584
+ rebind_t<long int, deduced-vec-t<V>> lrint(const V& x);
585
+ template<math-floating-point V>
586
+ rebind_t<long long int, V> llrint(const deduced-vec-t<V>& x);
587
+ template<math-floating-point V>
588
+ constexpr deduced-vec-t<V> round(const V& x);
589
+ template<math-floating-point V>
590
+ constexpr rebind_t<long int, deduced-vec-t<V>> lround(const V& x);
591
+ template<math-floating-point V>
592
+ constexpr rebind_t<long long int, deduced-vec-t<V>> llround(const V& x);
593
+ template<math-floating-point V>
594
+ constexpr deduced-vec-t<V> trunc(const V& x);
595
+ template<class V0, class V1>
596
+ constexpr math-common-simd-t<V0, V1> fmod(const V0& x, const V1& y);
597
+ template<class V0, class V1>
598
+ constexpr math-common-simd-t<V0, V1> remainder(const V0& x, const V1& y);
599
+ template<class V0, class V1>
600
+ constexpr math-common-simd-t<V0, V1>
601
+ remquo(const V0& x, const V1& y, rebind_t<int, math-common-simd-t<V0, V1>>* quo);
602
+ template<class V0, class V1>
603
+ constexpr math-common-simd-t<V0, V1> copysign(const V0& x, const V1& y);
604
+ template<class V0, class V1>
605
+ constexpr math-common-simd-t<V0, V1> nextafter(const V0& x, const V1& y);
606
+ template<class V0, class V1>
607
+ constexpr math-common-simd-t<V0, V1> fdim(const V0& x, const V1& y);
608
+ template<class V0, class V1>
609
+ constexpr math-common-simd-t<V0, V1> fmax(const V0& x, const V1& y);
610
+ template<class V0, class V1>
611
+ constexpr math-common-simd-t<V0, V1> fmin(const V0& x, const V1& y);
612
+ template<class V0, class V1, class V2>
613
+ constexpr math-common-simd-t<V0, V1, V2> fma(const V0& x, const V1& y, const V2& z);
614
+ template<class V0, class V1, class V2>
615
+ constexpr math-common-simd-t<V0, V1, V2>
616
+ lerp(const V0& a, const V1& b, const V2& t) noexcept;
617
+ template<math-floating-point V>
618
+ constexpr rebind_t<int, deduced-vec-t<V>> fpclassify(const V& x);
619
+ template<math-floating-point V>
620
+ constexpr typename deduced-vec-t<V>::mask_type isfinite(const V& x);
621
+ template<math-floating-point V>
622
+ constexpr typename deduced-vec-t<V>::mask_type isinf(const V& x);
623
+ template<math-floating-point V>
624
+ constexpr typename deduced-vec-t<V>::mask_type isnan(const V& x);
625
+ template<math-floating-point V>
626
+ constexpr typename deduced-vec-t<V>::mask_type isnormal(const V& x);
627
+ template<math-floating-point V>
628
+ constexpr typename deduced-vec-t<V>::mask_type signbit(const V& x);
629
+ template<class V0, class V1>
630
+ constexpr typename math-common-simd-t<V0, V1>::mask_type
631
+ isgreater(const V0& x, const V1& y);
632
+ template<class V0, class V1>
633
+ constexpr typename math-common-simd-t<V0, V1>::mask_type
634
+ isgreaterequal(const V0& x, const V1& y);
635
+ template<class V0, class V1>
636
+ constexpr typename math-common-simd-t<V0, V1>::mask_type
637
+ isless(const V0& x, const V1& y);
638
+ template<class V0, class V1>
639
+ constexpr typename math-common-simd-t<V0, V1>::mask_type
640
+ islessequal(const V0& x, const V1& y);
641
+ template<class V0, class V1>
642
+ constexpr typename math-common-simd-t<V0, V1>::mask_type
643
+ islessgreater(const V0& x, const V1& y);
644
+ template<class V0, class V1>
645
+ constexpr typename math-common-simd-t<V0, V1>::mask_type
646
+ isunordered(const V0& x, const V1& y);
647
+ template<math-floating-point V>
648
+ deduced-vec-t<V> assoc_laguerre(const rebind_t<unsigned, deduced-vec-t<V>>& n,
649
+ const rebind_t<unsigned, deduced-vec-t<V>>& m, const V& x);
650
+ template<math-floating-point V>
651
+ deduced-vec-t<V> assoc_legendre(const rebind_t<unsigned, deduced-vec-t<V>>& l,
652
+ const rebind_t<unsigned, deduced-vec-t<V>>& m, const V& x);
653
+ template<class V0, class V1>
654
+ math-common-simd-t<V0, V1> beta(const V0& x, const V1& y);
655
+ template<math-floating-point V> deduced-vec-t<V> comp_ellint_1(const V& k);
656
+ template<math-floating-point V> deduced-vec-t<V> comp_ellint_2(const V& k);
657
+ template<class V0, class V1>
658
+ math-common-simd-t<V0, V1> comp_ellint_3(const V0& k, const V1& nu);
659
+ template<class V0, class V1>
660
+ math-common-simd-t<V0, V1> cyl_bessel_i(const V0& nu, const V1& x);
661
+ template<class V0, class V1>
662
+ math-common-simd-t<V0, V1> cyl_bessel_j(const V0& nu, const V1& x);
663
+ template<class V0, class V1>
664
+ math-common-simd-t<V0, V1> cyl_bessel_k(const V0& nu, const V1& x);
665
+ template<class V0, class V1>
666
+ math-common-simd-t<V0, V1> cyl_neumann(const V0& nu, const V1& x);
667
+ template<class V0, class V1>
668
+ math-common-simd-t<V0, V1> ellint_1(const V0& k, const V1& phi);
669
+ template<class V0, class V1>
670
+ math-common-simd-t<V0, V1> ellint_2(const V0& k, const V1& phi);
671
+ template<class V0, class V1, class V2>
672
+ math-common-simd-t<V0, V1, V2> ellint_3(const V0& k, const V1& nu, const V2& phi);
673
+ template<math-floating-point V> deduced-vec-t<V> expint(const V& x);
674
+ template<math-floating-point V>
675
+ deduced-vec-t<V> hermite(const rebind_t<unsigned, deduced-vec-t<V>>& n, const V& x);
676
+ template<math-floating-point V>
677
+ deduced-vec-t<V> laguerre(const rebind_t<unsigned, deduced-vec-t<V>>& n, const V& x);
678
+ template<math-floating-point V>
679
+ deduced-vec-t<V> legendre(const rebind_t<unsigned, deduced-vec-t<V>>& l, const V& x);
680
+ template<math-floating-point V>
681
+ deduced-vec-t<V> riemann_zeta(const V& x);
682
+ template<math-floating-point V>
683
+ deduced-vec-t<V> sph_bessel(
684
+ const rebind_t<unsigned, deduced-vec-t<V>>& n, const V& x);
685
+ template<math-floating-point V>
686
+ deduced-vec-t<V> sph_legendre(const rebind_t<unsigned, deduced-vec-t<V>>& l,
687
+ const rebind_t<unsigned, deduced-vec-t<V>>& m, const V& theta);
688
+ template<math-floating-point V>
689
+ deduced-vec-t<V>
690
+ sph_neumann(const rebind_t<unsigned, deduced-vec-t<V>>& n, const V& x);
691
+
692
+ // [simd.bit], bit manipulation
693
+ template<simd-vec-type V> constexpr V byteswap(const V& v) noexcept;
694
+ template<simd-vec-type V> constexpr V bit_ceil(const V& v) noexcept;
695
+ template<simd-vec-type V> constexpr V bit_floor(const V& v) noexcept;
696
+
697
+ template<simd-vec-type V>
698
+ constexpr typename V::mask_type has_single_bit(const V& v) noexcept;
699
+
700
+ template<simd-vec-type V0, simd-vec-type V1>
701
+ constexpr V0 rotl(const V0& v, const V1& s) noexcept;
702
+ template<simd-vec-type V>
703
+ constexpr V rotl(const V& v, int s) noexcept;
704
+
705
+ template<simd-vec-type V0, simd-vec-type V1>
706
+ constexpr V0 rotr(const V0& v, const V1& s) noexcept;
707
+ template<simd-vec-type V>
708
+ constexpr V rotr(const V& v, int s) noexcept;
709
+
710
+ template<simd-vec-type V>
711
+ constexpr rebind_t<make_signed_t<typename V::value_type>, V>
712
+ bit_width(const V& v) noexcept;
713
+ template<simd-vec-type V>
714
+ constexpr rebind_t<make_signed_t<typename V::value_type>, V>
715
+ countl_zero(const V& v) noexcept;
716
+ template<simd-vec-type V>
717
+ constexpr rebind_t<make_signed_t<typename V::value_type>, V>
718
+ countl_one(const V& v) noexcept;
719
+ template<simd-vec-type V>
720
+ constexpr rebind_t<make_signed_t<typename V::value_type>, V>
721
+ countr_zero(const V& v) noexcept;
722
+ template<simd-vec-type V>
723
+ constexpr rebind_t<make_signed_t<typename V::value_type>, V>
724
+ countr_one(const V& v) noexcept;
725
+ template<simd-vec-type V>
726
+ constexpr rebind_t<make_signed_t<typename V::value_type>, V>
727
+ popcount(const V& v) noexcept;
728
+
729
+ // [simd.complex.math], complex math
730
+ template<simd-complex V>
731
+ constexpr rebind_t<simd-complex-value-type<V>, V> real(const V&) noexcept;
732
+
733
+ template<simd-complex V>
734
+ constexpr rebind_t<simd-complex-value-type<V>, V> imag(const V&) noexcept;
735
+
736
+ template<simd-complex V>
737
+ constexpr rebind_t<simd-complex-value-type<V>, V> abs(const V&);
738
+
739
+ template<simd-complex V>
740
+ constexpr rebind_t<simd-complex-value-type<V>, V> arg(const V&);
741
+
742
+ template<simd-complex V>
743
+ constexpr rebind_t<simd-complex-value-type<V>, V> norm(const V&);
744
+
745
+ template<simd-complex V> constexpr V conj(const V&);
746
+ template<simd-complex V> constexpr V proj(const V&);
747
+ template<simd-complex V> constexpr V exp(const V& v);
748
+ template<simd-complex V> constexpr V log(const V& v);
749
+ template<simd-complex V> constexpr V log10(const V& v);
750
+
751
+ template<simd-complex V> constexpr V sqrt(const V& v);
752
+ template<simd-complex V> constexpr V sin(const V& v);
753
+ template<simd-complex V> constexpr V asin(const V& v);
754
+ template<simd-complex V> constexpr V cos(const V& v);
755
+ template<simd-complex V> constexpr V acos(const V& v);
756
+ template<simd-complex V> constexpr V tan(const V& v);
757
+ template<simd-complex V> constexpr V atan(const V& v);
758
+ template<simd-complex V> constexpr V sinh(const V& v);
759
+ template<simd-complex V> constexpr V asinh(const V& v);
760
+ template<simd-complex V> constexpr V cosh(const V& v);
761
+ template<simd-complex V> constexpr V acosh(const V& v);
762
+ template<simd-complex V> constexpr V tanh(const V& v);
763
+ template<simd-complex V> constexpr V atanh(const V& v);
764
+
765
+ template<simd-floating-point V>
766
+ rebind_t<complex<typename V::value_type>, V> polar(const V& x, const V& y = {});
767
+
768
+ template<simd-complex V> constexpr V pow(const V& x, const V& y);
769
+
770
+ // [simd.mask.class], class template basic_mask
771
+ template<size_t Bytes, class Abi = native-abi<integer-from<Bytes>>> class basic_mask;
772
+ template<class T, simd-size-type N = simd-size-v<T, native-abi<T>>>
773
+ using mask = basic_mask<sizeof(T), deduce-abi-t<T, N>>;
774
+
775
+ // [simd.mask.reductions], reductions
776
+ template<size_t Bytes, class Abi>
777
+ constexpr bool all_of(const basic_mask<Bytes, Abi>&) noexcept;
778
+ template<size_t Bytes, class Abi>
779
+ constexpr bool any_of(const basic_mask<Bytes, Abi>&) noexcept;
780
+ template<size_t Bytes, class Abi>
781
+ constexpr bool none_of(const basic_mask<Bytes, Abi>&) noexcept;
782
+ template<size_t Bytes, class Abi>
783
+ constexpr simd-size-type reduce_count(const basic_mask<Bytes, Abi>&) noexcept;
784
+ template<size_t Bytes, class Abi>
785
+ constexpr simd-size-type reduce_min_index(const basic_mask<Bytes, Abi>&);
786
+ template<size_t Bytes, class Abi>
787
+ constexpr simd-size-type reduce_max_index(const basic_mask<Bytes, Abi>&);
788
+
789
+ constexpr bool all_of(same_as<bool> auto) noexcept;
790
+ constexpr bool any_of(same_as<bool> auto) noexcept;
791
+ constexpr bool none_of(same_as<bool> auto) noexcept;
792
+ constexpr simd-size-type reduce_count(same_as<bool> auto) noexcept;
793
+ constexpr simd-size-type reduce_min_index(same_as<bool> auto);
794
+ constexpr simd-size-type reduce_max_index(same_as<bool> auto);
795
+ }
796
+
797
+ namespace std {
798
+ // See [simd.alg], algorithms
799
+ using simd::min;
800
+ using simd::max;
801
+ using simd::minmax;
802
+ using simd::clamp;
803
+
804
+ // See [simd.math], mathematical functions
805
+ using simd::acos;
806
+ using simd::asin;
807
+ using simd::atan;
808
+ using simd::atan2;
809
+ using simd::cos;
810
+ using simd::sin;
811
+ using simd::tan;
812
+ using simd::acosh;
813
+ using simd::asinh;
814
+ using simd::atanh;
815
+ using simd::cosh;
816
+ using simd::sinh;
817
+ using simd::tanh;
818
+ using simd::exp;
819
+ using simd::exp2;
820
+ using simd::expm1;
821
+ using simd::frexp;
822
+ using simd::ilogb;
823
+ using simd::ldexp;
824
+ using simd::log;
825
+ using simd::log10;
826
+ using simd::log1p;
827
+ using simd::log2;
828
+ using simd::logb;
829
+ using simd::modf;
830
+ using simd::scalbn;
831
+ using simd::scalbln;
832
+ using simd::cbrt;
833
+ using simd::abs;
834
+ using simd::fabs;
835
+ using simd::hypot;
836
+ using simd::pow;
837
+ using simd::sqrt;
838
+ using simd::erf;
839
+ using simd::erfc;
840
+ using simd::lgamma;
841
+ using simd::tgamma;
842
+ using simd::ceil;
843
+ using simd::floor;
844
+ using simd::nearbyint;
845
+ using simd::rint;
846
+ using simd::lrint;
847
+ using simd::llrint;
848
+ using simd::round;
849
+ using simd::lround;
850
+ using simd::llround;
851
+ using simd::trunc;
852
+ using simd::fmod;
853
+ using simd::remainder;
854
+ using simd::remquo;
855
+ using simd::copysign;
856
+ using simd::nextafter;
857
+ using simd::fdim;
858
+ using simd::fmax;
859
+ using simd::fmin;
860
+ using simd::fma;
861
+ using simd::lerp;
862
+ using simd::fpclassify;
863
+ using simd::isfinite;
864
+ using simd::isinf;
865
+ using simd::isnan;
866
+ using simd::isnormal;
867
+ using simd::signbit;
868
+ using simd::isgreater;
869
+ using simd::isgreaterequal;
870
+ using simd::isless;
871
+ using simd::islessequal;
872
+ using simd::islessgreater;
873
+ using simd::isunordered;
874
+ using simd::assoc_laguerre;
875
+ using simd::assoc_legendre;
876
+ using simd::beta;
877
+ using simd::comp_ellint_1;
878
+ using simd::comp_ellint_2;
879
+ using simd::comp_ellint_3;
880
+ using simd::cyl_bessel_i;
881
+ using simd::cyl_bessel_j;
882
+ using simd::cyl_bessel_k;
883
+ using simd::cyl_neumann;
884
+ using simd::ellint_1;
885
+ using simd::ellint_2;
886
+ using simd::ellint_3;
887
+ using simd::expint;
888
+ using simd::hermite;
889
+ using simd::laguerre;
890
+ using simd::legendre;
891
+ using simd::riemann_zeta;
892
+ using simd::sph_bessel;
893
+ using simd::sph_legendre;
894
+ using simd::sph_neumann;
895
+
896
+ // See [simd.bit], bit manipulation
897
+ using simd::byteswap;
898
+ using simd::bit_ceil;
899
+ using simd::bit_floor;
900
+ using simd::has_single_bit;
901
+ using simd::rotl;
902
+ using simd::rotr;
903
+ using simd::bit_width;
904
+ using simd::countl_zero;
905
+ using simd::countl_one;
906
+ using simd::countr_zero;
907
+ using simd::countr_one;
908
+ using simd::popcount;
909
+
910
+ // See [simd.complex.math], vec complex math
911
+ using simd::real;
912
+ using simd::imag;
913
+ using simd::arg;
914
+ using simd::norm;
915
+ using simd::conj;
916
+ using simd::proj;
917
+ using simd::polar;
918
+ }
919
+ ```
920
+
921
+ ### Type traits <a id="simd.traits">[[simd.traits]]</a>
922
+
923
+ ``` cpp
924
+ template<class T, class U = typename T::value_type> struct alignment { see below };
925
+ ```
926
+
927
+ `alignment<T, U>` has a member `value` if and only if
928
+
929
+ - `T` is a specialization of `basic_mask` and `U` is `bool`, or
930
+ - `T` is a specialization of `basic_vec` and `U` is a vectorizable type.
931
+
932
+ If `value` is present, the type `alignment<T, U>` is a `BinaryTypeTrait`
933
+ with a base characteristic of `integral_constant<size_t, N>` for some
934
+ unspecified `N` [[simd.ctor]], [[simd.loadstore]].
935
+
936
+ [*Note 1*: `value` identifies the alignment restrictions on pointers
937
+ used for (converting) loads and stores for the given type `T` on arrays
938
+ of type `U`. — *end note*]
939
+
940
+ The behavior of a program that adds specializations for `alignment` is
941
+ undefined.
942
+
943
+ ``` cpp
944
+ template<class T, class V> struct rebind { using type = see below; };
945
+ ```
946
+
947
+ The member `type` is present if and only if
948
+
949
+ - `V` is a data-parallel type,
950
+ - `T` is a vectorizable type, and
951
+ - *`deduce-abi-t`*`<T, V::size()>` has a member type `type`.
952
+
953
+ If V is a specialization of `basic_vec`, let `Abi1` denote an ABI tag
954
+ such that `basic_vec<T, Abi1>::size()` equals `V::size()`. If V is a
955
+ specialization of `basic_mask`, let `Abi1` denote an ABI tag such that
956
+ `basic_mask<sizeof(T), Abi1>::size()` equals `V::size()`.
957
+
958
+ Where present, the member typedef `type` names `basic_vec<T, Abi1>` if V
959
+ is a specialization of `basic_vec` or `basic_mask<sizeof(T), Abi1>` if V
960
+ is a specialization of `basic_mask`.
961
+
962
+ ``` cpp
963
+ template<simd-size-type N, class V> struct resize { using type = see below; };
964
+ ```
965
+
966
+ Let `T` denote
967
+
968
+ - `typename V::value_type` if `V` is a specialization of `basic_vec`,
969
+ - otherwise *`integer-from`*`<`*`mask-element-size`*`<V>>` if `V` is a
970
+ specialization of `basic_mask`.
971
+
972
+ The member `type` is present if and only if
973
+
974
+ - `V` is a data-parallel type, and
975
+ - *`deduce-abi-t`*`<T, N>` has a member type `type`.
976
+
977
+ If V is a specialization of `basic_vec`, let `Abi1` denote an ABI tag
978
+ such that `basic_vec<T, Abi1>::size()` equals `N`. If V is a
979
+ specialization of `basic_mask`, let `Abi1` denote an ABI tag such that
980
+ `basic_mask<sizeof(T), Abi1>::size()` equals `N`.
981
+
982
+ Where present, the member typedef `type` names `basic_vec<T, Abi1>` if V
983
+ is a specialization of `basic_vec` or `basic_mask<sizeof(T), Abi1>` if V
984
+ is a specialization of `basic_mask`.
985
+
986
+ ### Load and store flags <a id="simd.flags">[[simd.flags]]</a>
987
+
988
+ #### Class template `flags` overview <a id="simd.flags.overview">[[simd.flags.overview]]</a>
989
+
990
+ ``` cpp
991
+ namespace std::simd {
992
+ template<class... Flags> struct flags {
993
+ // [simd.flags.oper], flags operators
994
+ template<class... Other>
995
+ friend consteval auto operator|(flags, flags<Other...>);
996
+ };
997
+ }
998
+ ```
999
+
1000
+ [*Note 1*: The class template `flags` acts like an integer bit-flag for
1001
+ types. — *end note*]
1002
+
1003
+ *Constraints:* Every type in the parameter pack `Flags` is one of
1004
+ `convert-flag`, `aligned-flag`, or `overaligned-{flag}<N>`.
1005
+
1006
+ #### `flags` operators <a id="simd.flags.oper">[[simd.flags.oper]]</a>
1007
+
1008
+ ``` cpp
1009
+ template<class... Other>
1010
+ friend consteval auto operator|(flags a, flags<Other...> b);
1011
+ ```
1012
+
1013
+ *Returns:* A default-initialized object of type `flags<Flags2...>` for
1014
+ some `Flags2` where every type in `Flags2` is present either in template
1015
+ parameter pack `Flags` or in template parameter pack `Other`, and every
1016
+ type in template parameter packs `Flags` and `Other` is present in
1017
+ `Flags2`. If the packs `Flags` and `Other` contain two different
1018
+ specializations *`overaligned-flag`*`<N1>` and
1019
+ *`overaligned-flag`*`<N2>`, `Flags2` is not required to contain the
1020
+ specialization *`overaligned-flag`*`<std::min(N1, N2)>`.
1021
+
1022
+ ### Class template *`simd-iterator`* <a id="simd.iterator">[[simd.iterator]]</a>
1023
+
1024
+ ``` cpp
1025
+ namespace std::simd {
1026
+ template<class V>
1027
+ class simd-iterator { // exposition only
1028
+ V* data_ = nullptr; // exposition only
1029
+ simd-size-type offset_ = 0; // exposition only
1030
+
1031
+ constexpr simd-iterator(V& d, simd-size-type off) noexcept; // exposition only
1032
+
1033
+ public:
1034
+ using value_type = V::value_type;
1035
+ using iterator_category = input_iterator_tag;
1036
+ using iterator_concept = random_access_iterator_tag;
1037
+ using difference_type = simd-size-type;
1038
+
1039
+ constexpr simd-iterator() = default;
1040
+
1041
+ constexpr simd-iterator(const simd-iterator&) = default;
1042
+ constexpr simd-iterator& operator=(const simd-iterator&) = default;
1043
+
1044
+ constexpr simd-iterator(const simd-iterator<remove_const_t<V>>&) requires is_const_v<V>;
1045
+
1046
+ constexpr value_type operator*() const;
1047
+
1048
+ constexpr simd-iterator& operator++();
1049
+ constexpr simd-iterator operator++(int);
1050
+ constexpr simd-iterator& operator--();
1051
+ constexpr simd-iterator operator--(int);
1052
+
1053
+ constexpr simd-iterator& operator+=(difference_type n);
1054
+ constexpr simd-iterator& operator-=(difference_type n);
1055
+
1056
+ constexpr value_type operator[](difference_type n) const;
1057
+
1058
+ friend constexpr bool operator==(simd-iterator a, simd-iterator b) = default;
1059
+ friend constexpr bool operator==(simd-iterator a, default_sentinel_t) noexcept;
1060
+ friend constexpr auto operator<=>(simd-iterator a, simd-iterator b);
1061
+
1062
+ friend constexpr simd-iterator operator+(simd-iterator i, difference_type n);
1063
+ friend constexpr simd-iterator operator+(difference_type n, simd-iterator i);
1064
+ friend constexpr simd-iterator operator-(simd-iterator i, difference_type n);
1065
+
1066
+ friend constexpr difference_type operator-(simd-iterator a, simd-iterator b);
1067
+ friend constexpr difference_type operator-(simd-iterator i, default_sentinel_t) noexcept;
1068
+ friend constexpr difference_type operator-(default_sentinel_t, simd-iterator i) noexcept;
1069
+ };
1070
+ }
1071
+ ```
1072
+
1073
+ ``` cpp
1074
+ constexpr simd-iterator(V& d, simd-size-type off) noexcept;
1075
+ ```
1076
+
1077
+ *Effects:* Initializes *data\_* with `addressof(d)` and *offset\_* with
1078
+ `off`.
1079
+
1080
+ ``` cpp
1081
+ constexpr simd-iterator(const simd-iterator<remove_const_t<V>>& i) requires is_const_v<V>;
1082
+ ```
1083
+
1084
+ *Effects:* Initializes *data\_* with `i.`*`data_`* and *offset\_* with
1085
+ `i.`*`offset_`*.
1086
+
1087
+ ``` cpp
1088
+ constexpr value_type operator*() const;
1089
+ ```
1090
+
1091
+ *Effects:* Equivalent to: `return (*`*`data_`*`)[`*`offset_`*`];`
1092
+
1093
+ ``` cpp
1094
+ constexpr simd-iterator& operator++();
1095
+ ```
1096
+
1097
+ *Effects:* Equivalent to: `return *this += 1;`
1098
+
1099
+ ``` cpp
1100
+ constexpr simd-iterator operator++(int);
1101
+ ```
1102
+
1103
+ *Effects:* Equivalent to:
1104
+
1105
+ ``` cpp
1106
+ simd-iterator tmp = *this;
1107
+ *this += 1;
1108
+ return tmp;
1109
+ ```
1110
+
1111
+ ``` cpp
1112
+ constexpr simd-iterator& operator--();
1113
+ ```
1114
+
1115
+ *Effects:* Equivalent to: `return *this -= 1;`
1116
+
1117
+ ``` cpp
1118
+ constexpr simd-iterator operator--(int);
1119
+ ```
1120
+
1121
+ *Effects:* Equivalent to:
1122
+
1123
+ ``` cpp
1124
+ simd-iterator tmp = *this;
1125
+ *this -= 1;
1126
+ return tmp;
1127
+ ```
1128
+
1129
+ ``` cpp
1130
+ constexpr simd-iterator& operator+=(difference_type n);
1131
+ ```
1132
+
1133
+ *Preconditions:* *`offset_`*` + n` is in the range \[`0`, `V::size()`\].
1134
+
1135
+ *Effects:* Equivalent to:
1136
+
1137
+ ``` cpp
1138
+ offset_ += n;
1139
+ return *this;
1140
+ ```
1141
+
1142
+ ``` cpp
1143
+ constexpr simd-iterator& operator-=(difference_type n);
1144
+ ```
1145
+
1146
+ *Preconditions:* *`offset_`*` - n` is in the range \[`0`, `V::size()`\].
1147
+
1148
+ *Effects:* Equivalent to:
1149
+
1150
+ ``` cpp
1151
+ offset_ -= n;
1152
+ return *this;
1153
+ ```
1154
+
1155
+ ``` cpp
1156
+ constexpr value_type operator[](difference_type n) const;
1157
+ ```
1158
+
1159
+ *Effects:* Equivalent to: `return (*`*`data_`*`)[`*`offset_`*` + n];`
1160
+
1161
+ ``` cpp
1162
+ friend constexpr bool operator==(simd-iterator i, default_sentinel_t) noexcept;
1163
+ ```
1164
+
1165
+ *Effects:* Equivalent to: `return i.`*`offset_`*` == V::size();`
1166
+
1167
+ ``` cpp
1168
+ friend constexpr auto operator<=>(simd-iterator a, simd-iterator b);
1169
+ ```
1170
+
1171
+ *Preconditions:* `a.`*`data_`*` == b.`*`data_`* is `true`.
1172
+
1173
+ *Effects:* Equivalent to: `return a.`*`offset_`*` <=> b.`*`offset_`*`;`
1174
+
1175
+ ``` cpp
1176
+ friend constexpr simd-iterator operator+(simd-iterator i, difference_type n);
1177
+ friend constexpr simd-iterator operator+(difference_type n, simd-iterator i);
1178
+ ```
1179
+
1180
+ *Effects:* Equivalent to: `return i += n;`
1181
+
1182
+ ``` cpp
1183
+ friend constexpr simd-iterator operator-(simd-iterator i, difference_type n);
1184
+ ```
1185
+
1186
+ *Effects:* Equivalent to: `return i -= n;`
1187
+
1188
+ ``` cpp
1189
+ friend constexpr difference_type operator-(simd-iterator a, simd-iterator b);
1190
+ ```
1191
+
1192
+ *Preconditions:* `a.`*`data_`*` == b.`*`data_`* is `true`.
1193
+
1194
+ *Effects:* Equivalent to: `return a.`*`offset_`*` - b.`*`offset_`*`;`
1195
+
1196
+ ``` cpp
1197
+ friend constexpr difference_type operator-(simd-iterator i, default_sentinel_t) noexcept;
1198
+ ```
1199
+
1200
+ *Effects:* Equivalent to: `return i.`*`offset_`*` - V::size();`
1201
+
1202
+ ``` cpp
1203
+ friend constexpr difference_type operator-(default_sentinel_t, simd-iterator i) noexcept;
1204
+ ```
1205
+
1206
+ *Effects:* Equivalent to: `return V::size() - i.`*`offset_`*`;`
1207
+
1208
+ ### Class template `basic_vec` <a id="simd.class">[[simd.class]]</a>
1209
+
1210
+ #### Overview <a id="simd.overview">[[simd.overview]]</a>
1211
+
1212
+ ``` cpp
1213
+ namespace std::simd {
1214
+ template<class T, class Abi> class basic_vec {
1215
+ public:
1216
+ using value_type = T;
1217
+ using mask_type = basic_mask<sizeof(T), Abi>;
1218
+ using abi_type = Abi;
1219
+ using iterator = simd-iterator<basic_vec>;
1220
+ using const_iterator = simd-iterator<const basic_vec>;
1221
+
1222
+ constexpr iterator begin() noexcept { return {*this, 0}; }
1223
+ constexpr const_iterator begin() const noexcept { return {*this, 0}; }
1224
+ constexpr const_iterator cbegin() const noexcept { return {*this, 0}; }
1225
+ constexpr default_sentinel_t end() const noexcept { return {}; }
1226
+ constexpr default_sentinel_t cend() const noexcept { return {}; }
1227
+
1228
+ static constexpr integral_constant<simd-size-type, simd-size-v<T, Abi>> size {};
1229
+
1230
+ constexpr basic_vec() noexcept = default;
1231
+
1232
+ // [simd.ctor], basic_vec constructors
1233
+ template<class U>
1234
+ constexpr explicit(see below) basic_vec(U&& value) noexcept;
1235
+ template<class U, class UAbi>
1236
+ constexpr explicit(see below) basic_vec(const basic_vec<U, UAbi>&) noexcept;
1237
+ template<class G>
1238
+ constexpr explicit basic_vec(G&& gen);
1239
+ template<class R, class... Flags>
1240
+ constexpr basic_vec(R&& range, flags<Flags...> = {});
1241
+ template<class R, class... Flags>
1242
+ constexpr basic_vec(R&& range, const mask_type& mask, flags<Flags...> = {});
1243
+ template<simd-floating-point V>
1244
+ constexpr explicit(see below) basic_vec(const V& reals, const V& imags = {}) noexcept;
1245
+
1246
+ // [simd.subscr], basic_vec subscript operators
1247
+ constexpr value_type operator[](simd-size-type) const;
1248
+ template<simd-integral I>
1249
+ constexpr resize_t<I::size(), basic_vec> operator[](const I& indices) const;
1250
+
1251
+ // [simd.complex.access], basic_vec complex accessors
1252
+ constexpr auto real() const noexcept;
1253
+ constexpr auto imag() const noexcept;
1254
+ template<simd-floating-point V>
1255
+ constexpr void real(const V& v) noexcept;
1256
+ template<simd-floating-point V>
1257
+ constexpr void imag(const V& v) noexcept;
1258
+
1259
+ // [simd.unary], basic_vec unary operators
1260
+ constexpr basic_vec& operator++() noexcept;
1261
+ constexpr basic_vec operator++(int) noexcept;
1262
+ constexpr basic_vec& operator--() noexcept;
1263
+ constexpr basic_vec operator--(int) noexcept;
1264
+ constexpr mask_type operator!() const noexcept;
1265
+ constexpr basic_vec operator~() const noexcept;
1266
+ constexpr basic_vec operator+() const noexcept;
1267
+ constexpr basic_vec operator-() const noexcept;
1268
+
1269
+ // [simd.binary], basic_vec binary operators
1270
+ friend constexpr basic_vec operator+(const basic_vec&, const basic_vec&) noexcept;
1271
+ friend constexpr basic_vec operator-(const basic_vec&, const basic_vec&) noexcept;
1272
+ friend constexpr basic_vec operator*(const basic_vec&, const basic_vec&) noexcept;
1273
+ friend constexpr basic_vec operator/(const basic_vec&, const basic_vec&) noexcept;
1274
+ friend constexpr basic_vec operator%(const basic_vec&, const basic_vec&) noexcept;
1275
+ friend constexpr basic_vec operator&(const basic_vec&, const basic_vec&) noexcept;
1276
+ friend constexpr basic_vec operator|(const basic_vec&, const basic_vec&) noexcept;
1277
+ friend constexpr basic_vec operator^(const basic_vec&, const basic_vec&) noexcept;
1278
+ friend constexpr basic_vec operator<<(const basic_vec&, const basic_vec&) noexcept;
1279
+ friend constexpr basic_vec operator>>(const basic_vec&, const basic_vec&) noexcept;
1280
+ friend constexpr basic_vec operator<<(const basic_vec&, simd-size-type) noexcept;
1281
+ friend constexpr basic_vec operator>>(const basic_vec&, simd-size-type) noexcept;
1282
+
1283
+ // [simd.cassign], basic_vec compound assignment
1284
+ friend constexpr basic_vec& operator+=(basic_vec&, const basic_vec&) noexcept;
1285
+ friend constexpr basic_vec& operator-=(basic_vec&, const basic_vec&) noexcept;
1286
+ friend constexpr basic_vec& operator*=(basic_vec&, const basic_vec&) noexcept;
1287
+ friend constexpr basic_vec& operator/=(basic_vec&, const basic_vec&) noexcept;
1288
+ friend constexpr basic_vec& operator%=(basic_vec&, const basic_vec&) noexcept;
1289
+ friend constexpr basic_vec& operator&=(basic_vec&, const basic_vec&) noexcept;
1290
+ friend constexpr basic_vec& operator|=(basic_vec&, const basic_vec&) noexcept;
1291
+ friend constexpr basic_vec& operator^=(basic_vec&, const basic_vec&) noexcept;
1292
+ friend constexpr basic_vec& operator<<=(basic_vec&, const basic_vec&) noexcept;
1293
+ friend constexpr basic_vec& operator>>=(basic_vec&, const basic_vec&) noexcept;
1294
+ friend constexpr basic_vec& operator<<=(basic_vec&, simd-size-type) noexcept;
1295
+ friend constexpr basic_vec& operator>>=(basic_vec&, simd-size-type) noexcept;
1296
+
1297
+ // [simd.comparison], basic_vec compare operators
1298
+ friend constexpr mask_type operator==(const basic_vec&, const basic_vec&) noexcept;
1299
+ friend constexpr mask_type operator!=(const basic_vec&, const basic_vec&) noexcept;
1300
+ friend constexpr mask_type operator>=(const basic_vec&, const basic_vec&) noexcept;
1301
+ friend constexpr mask_type operator<=(const basic_vec&, const basic_vec&) noexcept;
1302
+ friend constexpr mask_type operator>(const basic_vec&, const basic_vec&) noexcept;
1303
+ friend constexpr mask_type operator<(const basic_vec&, const basic_vec&) noexcept;
1304
+
1305
+ // [simd.cond], basic_vec exposition only conditional operators
1306
+ friend constexpr basic_vec simd-select-impl( // exposition only
1307
+ const mask_type&, const basic_vec&, const basic_vec&) noexcept;
1308
+ };
1309
+
1310
+ template<class R, class... Ts>
1311
+ basic_vec(R&& r, Ts...) -> see below;
1312
+ }
1313
+ ```
1314
+
1315
+ Every specialization of `basic_vec` is a complete type. The
1316
+ specialization of `basic_vec<T, Abi>` is
1317
+
1318
+ - enabled, if `T` is a vectorizable type, and there exists value `N` in
1319
+ the range \[`1`, `64`\], such that `Abi` is `deduce-abi-t<T, N>`,
1320
+ - otherwise, disabled, if `T` is not a vectorizable type,
1321
+ - otherwise, it is *implementation-defined* if such a specialization is
1322
+ enabled.
1323
+
1324
+ If `basic_vec<T, Abi>` is disabled, then the specialization has a
1325
+ deleted default constructor, deleted destructor, deleted copy
1326
+ constructor, and deleted copy assignment. In addition only the
1327
+ `value_type`, `abi_type`, and `mask_type` members are present.
1328
+
1329
+ If `basic_vec<T, Abi>` is enabled, then `basic_vec<T, Abi>` is trivially
1330
+ copyable, default-initialization of an object of such a type
1331
+ default-initializes all elements, and value-initialization
1332
+ value-initializes all elements [[dcl.init.general]].
1333
+
1334
+ *Recommended practice:* Implementations should support implicit
1335
+ conversions between specializations of `basic_vec` and appropriate
1336
+ *implementation-defined* types.
1337
+
1338
+ [*Note 1*: Appropriate types are non-standard vector types which are
1339
+ available in the implementation. — *end note*]
1340
+
1341
+ #### Constructors <a id="simd.ctor">[[simd.ctor]]</a>
1342
+
1343
+ ``` cpp
1344
+ template<class U> constexpr explicit(see below) basic_vec(U&& value) noexcept;
1345
+ ```
1346
+
1347
+ Let `From` denote the type `remove_cvref_t<U>`.
1348
+
1349
+ *Constraints:* `value_type` satisfies `constructible_from<U>`.
1350
+
1351
+ *Effects:* Initializes each element to the value of the argument after
1352
+ conversion to `value_type`.
1353
+
1354
+ *Remarks:* The expression inside `explicit` evaluates to `false` if and
1355
+ only if `U` satisfies `convertible_to<value_type>`, and either
1356
+
1357
+ - `From` is not an arithmetic type and does not satisfy
1358
+ `constexpr-wrapper-like`,
1359
+ - `From` is an arithmetic type and the conversion from `From` to
1360
+ `value_type` is value-preserving [[simd.general]], or
1361
+ - `From` satisfies `constexpr-wrapper-like`,
1362
+ `remove_const_t<decltype(From::value)>` is an arithmetic type, and
1363
+ `From::value` is representable by `value_type`.
1364
+
1365
+ ``` cpp
1366
+ template<class U, class UAbi>
1367
+ constexpr explicit(see below) basic_vec(const basic_vec<U, UAbi>& x) noexcept;
1368
+ ```
1369
+
1370
+ *Constraints:* *`simd-size-v`*`<U, UAbi> == size()` is `true`.
1371
+
1372
+ *Effects:* Initializes the iᵗʰ element with `static_cast<T>(x[`i`])` for
1373
+ all i in the range of \[`0`, `size()`).
1374
+
1375
+ *Remarks:* The expression inside `explicit` evaluates to `true` if
1376
+ either
1377
+
1378
+ - the conversion from `U` to `value_type` is not value-preserving, or
1379
+ - both `U` and `value_type` are integral types and the integer
1380
+ conversion rank [[conv.rank]] of `U` is greater than the integer
1381
+ conversion rank of `value_type`, or
1382
+ - both `U` and `value_type` are floating-point types and the
1383
+ floating-point conversion rank [[conv.rank]] of `U` is greater than
1384
+ the floating-point conversion rank of `value_type`.
1385
+
1386
+ ``` cpp
1387
+ template<class G> constexpr explicit basic_vec(G&& gen);
1388
+ ```
1389
+
1390
+ Let `From`ᵢ denote the type
1391
+ `decltype(gen(integral_constant<`*`simd-size-type`*`, `i`>()))`.
1392
+
1393
+ *Constraints:* `From`ᵢ satisfies `convertible_to<value_type>` for all i
1394
+ in the range of \[`0`, `size()`). In addition, for all i in the range of
1395
+ \[`0`, `size()`), if `From`ᵢ is an arithmetic type, conversion from
1396
+ `From`ᵢ to `value_type` is value-preserving.
1397
+
1398
+ *Effects:* Initializes the iᵗʰ element with
1399
+ `static_cast<value_type>(gen(integral_constant<`*`simd-size-type`*`, i>()))`
1400
+ for all i in the range of \[`0`, `size()`).
1401
+
1402
+ *Remarks:* `gen` is invoked exactly once for each i, in increasing order
1403
+ of i.
1404
+
1405
+ ``` cpp
1406
+ template<class R, class... Flags>
1407
+ constexpr basic_vec(R&& r, flags<Flags...> = {});
1408
+ template<class R, class... Flags>
1409
+ constexpr basic_vec(R&& r, const mask_type& mask, flags<Flags...> = {});
1410
+ ```
1411
+
1412
+ Let `mask` be `mask_type(true)` for the overload with no `mask`
1413
+ parameter.
1414
+
1415
+ *Constraints:*
1416
+
1417
+ - `R` models `ranges::contiguous_range` and `ranges::sized_range`,
1418
+ - `ranges::size(r)` is a constant expression, and
1419
+ - `ranges::size(r)` is equal to `size()`.
1420
+
1421
+ *Mandates:*
1422
+
1423
+ - `ranges::range_value_t<R>` is a vectorizable type, and
1424
+ - if the template parameter pack `Flags` does not contain
1425
+ *`convert-flag`*, then the conversion from `ranges::range_value_t<R>`
1426
+ to `value_type` is value-preserving.
1427
+
1428
+ *Preconditions:*
1429
+
1430
+ - If the template parameter pack `Flags` contains *`aligned-flag`*,
1431
+ `ranges::data(r)` points to storage aligned by
1432
+ `alignment_v<basic_vec, ranges::range_value_t<R>>`.
1433
+ - If the template parameter pack `Flags` contains
1434
+ *`overaligned-flag`*`<N>`, `ranges::data(r)` points to storage aligned
1435
+ by `N`.
1436
+
1437
+ *Effects:* Initializes the iᵗʰ element with
1438
+ `mask[`i`] ? static_cast<T>(ranges::data(r)[`i`]) : T()` for all i in
1439
+ the range of \[`0`, `size()`).
1440
+
1441
+ ``` cpp
1442
+ template<class R, class... Ts>
1443
+ basic_vec(R&& r, Ts...) -> see below;
1444
+ ```
1445
+
1446
+ *Constraints:*
1447
+
1448
+ - `R` models `ranges::contiguous_range` and `ranges::sized_range`, and
1449
+ - `ranges::size(r)` is a constant expression.
1450
+
1451
+ *Remarks:* The deduced type is equivalent to
1452
+ `vec<ranges::range_value_t<R>, ranges::size(r)>`.
1453
+
1454
+ ``` cpp
1455
+ template<simd-floating-point V>
1456
+ constexpr explicit(see below)
1457
+ basic_vec(const V& reals, const V& imags = {}) noexcept;
1458
+ ```
1459
+
1460
+ *Constraints:*
1461
+
1462
+ - `simd-complex<basic_vec>` is modeled, and
1463
+ - `V::size() == size()` is `true`.
1464
+
1465
+ *Effects:* Initializes the iᵗʰ element with
1466
+ `value_type(reals[`i`], imags[`i`])` for all i in the range \[`0`,
1467
+ `size()`).
1468
+
1469
+ *Remarks:* The expression inside `explicit` evaluates to `false` if and
1470
+ only if the floating-point conversion rank of `T::value_type` is greater
1471
+ than or equal to the floating-point conversion rank of `V::value_type`.
1472
+
1473
+ #### Subscript operator <a id="simd.subscr">[[simd.subscr]]</a>
1474
+
1475
+ ``` cpp
1476
+ constexpr value_type operator[](simd-size-type i) const;
1477
+ ```
1478
+
1479
+ *Preconditions:* `i >= 0 && i < size()` is `true`.
1480
+
1481
+ *Returns:* The value of the iᵗʰ element.
1482
+
1483
+ *Throws:* Nothing.
1484
+
1485
+ ``` cpp
1486
+ template<simd-integral I>
1487
+ constexpr resize_t<I::size(), basic_vec> operator[](const I& indices) const;
1488
+ ```
1489
+
1490
+ *Effects:* Equivalent to: `return permute(*this, indices);`
1491
+
1492
+ #### Complex accessors <a id="simd.complex.access">[[simd.complex.access]]</a>
1493
+
1494
+ ``` cpp
1495
+ constexpr auto real() const noexcept;
1496
+ constexpr auto imag() const noexcept;
1497
+ ```
1498
+
1499
+ *Constraints:* `simd-complex<basic_vec>` is modeled.
1500
+
1501
+ *Returns:* An object of type
1502
+ `rebind_t<typename T::value_type, basic_vec>` where the iᵗʰ element is
1503
+ initialized to the result of *`cmplx-func`*`(operator[](`i`))` for all i
1504
+ in the range \[`0`, `size()`), where *`cmplx-func`* is the corresponding
1505
+ function from `<complex>`.
1506
+
1507
+ ``` cpp
1508
+ template<simd-floating-point V>
1509
+ constexpr void real(const V& v) noexcept;
1510
+ template<simd-floating-point V>
1511
+ constexpr void imag(const V& v) noexcept;
1512
+ ```
1513
+
1514
+ *Constraints:*
1515
+
1516
+ - `simd-complex<basic_vec>` is modeled,
1517
+ - `same_as<typename V::value_type, typename T::value_type>` is modeled,
1518
+ and
1519
+ - `V::size() == size()` is `true`.
1520
+
1521
+ *Effects:* Replaces each element of the `basic_vec` object such that the
1522
+ iᵗʰ element is replaced with
1523
+ `value_type(v[`i`], operator[](`i`).imag())` or
1524
+ `value_type(operator[](`i`).real(), v[`i`])` for `real` and `imag`
1525
+ respectively, for all i in the range \[`0`, `size()`).
1526
+
1527
+ #### Unary operators <a id="simd.unary">[[simd.unary]]</a>
1528
+
1529
+ Effects in [[simd.unary]] are applied as unary element-wise operations.
1530
+
1531
+ ``` cpp
1532
+ constexpr basic_vec& operator++() noexcept;
1533
+ ```
1534
+
1535
+ *Constraints:* `requires (value_type a) { ++a; }` is `true`.
1536
+
1537
+ *Effects:* Increments every element by one.
1538
+
1539
+ *Returns:* `*this`.
1540
+
1541
+ ``` cpp
1542
+ constexpr basic_vec operator++(int) noexcept;
1543
+ ```
1544
+
1545
+ *Constraints:* `requires (value_type a) { a++; }` is `true`.
1546
+
1547
+ *Effects:* Increments every element by one.
1548
+
1549
+ *Returns:* A copy of `*this` before incrementing.
1550
+
1551
+ ``` cpp
1552
+ constexpr basic_vec& operator--() noexcept;
1553
+ ```
1554
+
1555
+ *Constraints:* `requires (value_type a) { –a; }` is `true`.
1556
+
1557
+ *Effects:* Decrements every element by one.
1558
+
1559
+ *Returns:* `*this`.
1560
+
1561
+ ``` cpp
1562
+ constexpr basic_vec operator--(int) noexcept;
1563
+ ```
1564
+
1565
+ *Constraints:* `requires (value_type a) { a–; }` is `true`.
1566
+
1567
+ *Effects:* Decrements every element by one.
1568
+
1569
+ *Returns:* A copy of `*this` before decrementing.
1570
+
1571
+ ``` cpp
1572
+ constexpr mask_type operator!() const noexcept;
1573
+ ```
1574
+
1575
+ *Constraints:* `requires (const value_type a) { !a; }` is `true`.
1576
+
1577
+ *Returns:* A `basic_mask` object with the iᵗʰ element set to
1578
+ `!operator[](`i`)` for all i in the range of \[`0`, `size()`).
1579
+
1580
+ ``` cpp
1581
+ constexpr basic_vec operator~() const noexcept;
1582
+ ```
1583
+
1584
+ *Constraints:* `requires (const value_type a) { ~a; }` is `true`.
1585
+
1586
+ *Returns:* A `basic_vec` object with the iᵗʰ element set to
1587
+ `~operator[](`i`)` for all i in the range of \[`0`, `size()`).
1588
+
1589
+ ``` cpp
1590
+ constexpr basic_vec operator+() const noexcept;
1591
+ ```
1592
+
1593
+ *Constraints:* `requires (const value_type a) { +a; }` is `true`.
1594
+
1595
+ *Returns:* `*this`.
1596
+
1597
+ ``` cpp
1598
+ constexpr basic_vec operator-() const noexcept;
1599
+ ```
1600
+
1601
+ *Constraints:* `requires (const value_type a) { -a; }` is `true`.
1602
+
1603
+ *Returns:* A `basic_vec` object where the iᵗʰ element is initialized to
1604
+ `-operator[](`i`)` for all i in the range of \[`0`, `size()`).
1605
+
1606
+ ### `basic_vec` non-member operations <a id="simd.nonmembers">[[simd.nonmembers]]</a>
1607
+
1608
+ #### Binary operators <a id="simd.binary">[[simd.binary]]</a>
1609
+
1610
+ ``` cpp
1611
+ friend constexpr basic_vec operator+(const basic_vec& lhs, const basic_vec& rhs) noexcept;
1612
+ friend constexpr basic_vec operator-(const basic_vec& lhs, const basic_vec& rhs) noexcept;
1613
+ friend constexpr basic_vec operator*(const basic_vec& lhs, const basic_vec& rhs) noexcept;
1614
+ friend constexpr basic_vec operator/(const basic_vec& lhs, const basic_vec& rhs) noexcept;
1615
+ friend constexpr basic_vec operator%(const basic_vec& lhs, const basic_vec& rhs) noexcept;
1616
+ friend constexpr basic_vec operator&(const basic_vec& lhs, const basic_vec& rhs) noexcept;
1617
+ friend constexpr basic_vec operator|(const basic_vec& lhs, const basic_vec& rhs) noexcept;
1618
+ friend constexpr basic_vec operator^(const basic_vec& lhs, const basic_vec& rhs) noexcept;
1619
+ friend constexpr basic_vec operator<<(const basic_vec& lhs, const basic_vec& rhs) noexcept;
1620
+ friend constexpr basic_vec operator>>(const basic_vec& lhs, const basic_vec& rhs) noexcept;
1621
+ ```
1622
+
1623
+ Let *op* be the operator.
1624
+
1625
+ *Constraints:* `requires (value_type a, value_type b) { a `*`op`*` b; }`
1626
+ is `true`.
1627
+
1628
+ *Returns:* A `basic_vec` object initialized with the results of applying
1629
+ *op* to `lhs` and `rhs` as a binary element-wise operation.
1630
+
1631
+ ``` cpp
1632
+ friend constexpr basic_vec operator<<(const basic_vec& v, simd-size-type n) noexcept;
1633
+ friend constexpr basic_vec operator>>(const basic_vec& v, simd-size-type n) noexcept;
1634
+ ```
1635
+
1636
+ Let *op* be the operator.
1637
+
1638
+ *Constraints:*
1639
+ `requires (value_type a, `*`simd-size-type`*` b) { a `*`op`*` b; }` is
1640
+ `true`.
1641
+
1642
+ *Returns:* A `basic_vec` object where the iᵗʰ element is initialized to
1643
+ the result of applying *op* to `v[`i`]` and `n` for all i in the range
1644
+ of \[`0`, `size()`).
1645
+
1646
+ #### Compound assignment <a id="simd.cassign">[[simd.cassign]]</a>
1647
+
1648
+ ``` cpp
1649
+ friend constexpr basic_vec& operator+=(basic_vec& lhs, const basic_vec& rhs) noexcept;
1650
+ friend constexpr basic_vec& operator-=(basic_vec& lhs, const basic_vec& rhs) noexcept;
1651
+ friend constexpr basic_vec& operator*=(basic_vec& lhs, const basic_vec& rhs) noexcept;
1652
+ friend constexpr basic_vec& operator/=(basic_vec& lhs, const basic_vec& rhs) noexcept;
1653
+ friend constexpr basic_vec& operator%=(basic_vec& lhs, const basic_vec& rhs) noexcept;
1654
+ friend constexpr basic_vec& operator&=(basic_vec& lhs, const basic_vec& rhs) noexcept;
1655
+ friend constexpr basic_vec& operator|=(basic_vec& lhs, const basic_vec& rhs) noexcept;
1656
+ friend constexpr basic_vec& operator^=(basic_vec& lhs, const basic_vec& rhs) noexcept;
1657
+ friend constexpr basic_vec& operator<<=(basic_vec& lhs, const basic_vec& rhs) noexcept;
1658
+ friend constexpr basic_vec& operator>>=(basic_vec& lhs, const basic_vec& rhs) noexcept;
1659
+ ```
1660
+
1661
+ Let *op* be the operator.
1662
+
1663
+ *Constraints:* `requires (value_type a, value_type b) { a `*`op`*` b; }`
1664
+ is `true`.
1665
+
1666
+ *Effects:* These operators apply the indicated operator to `lhs` and
1667
+ `rhs` as an element-wise operation.
1668
+
1669
+ *Returns:* `lhs`.
1670
+
1671
+ ``` cpp
1672
+ friend constexpr basic_vec& operator<<=(basic_vec& lhs, simd-size-type n) noexcept;
1673
+ friend constexpr basic_vec& operator>>=(basic_vec& lhs, simd-size-type n) noexcept;
1674
+ ```
1675
+
1676
+ Let *op* be the operator.
1677
+
1678
+ *Constraints:*
1679
+ `requires (value_type a, `*`simd-size-type`*` b) { a `*`op`*` b; }` is
1680
+ `true`.
1681
+
1682
+ *Effects:* Equivalent to:
1683
+ `return operator `*`op`*` (lhs, basic_vec(n));`
1684
+
1685
+ #### Comparison operators <a id="simd.comparison">[[simd.comparison]]</a>
1686
+
1687
+ ``` cpp
1688
+ friend constexpr mask_type operator==(const basic_vec& lhs, const basic_vec& rhs) noexcept;
1689
+ friend constexpr mask_type operator!=(const basic_vec& lhs, const basic_vec& rhs) noexcept;
1690
+ friend constexpr mask_type operator>=(const basic_vec& lhs, const basic_vec& rhs) noexcept;
1691
+ friend constexpr mask_type operator<=(const basic_vec& lhs, const basic_vec& rhs) noexcept;
1692
+ friend constexpr mask_type operator>(const basic_vec& lhs, const basic_vec& rhs) noexcept;
1693
+ friend constexpr mask_type operator<(const basic_vec& lhs, const basic_vec& rhs) noexcept;
1694
+ ```
1695
+
1696
+ Let *op* be the operator.
1697
+
1698
+ *Constraints:* `requires (value_type a, value_type b) { a `*`op`*` b; }`
1699
+ is `true`.
1700
+
1701
+ *Returns:* A `basic_mask` object initialized with the results of
1702
+ applying *op* to `lhs` and `rhs` as a binary element-wise operation.
1703
+
1704
+ #### Exposition-only conditional operators <a id="simd.cond">[[simd.cond]]</a>
1705
+
1706
+ ``` cpp
1707
+ friend constexpr basic_vec
1708
+ simd-select-impl(const mask_type& mask, const basic_vec& a, const basic_vec& b) noexcept;
1709
+ ```
1710
+
1711
+ *Returns:* A `basic_vec` object where the iᵗʰ element equals
1712
+ `mask[`i`] ? a[`i`] : b[`i`]` for all i in the range of \[`0`,
1713
+ `size()`).
1714
+
1715
+ #### Reductions <a id="simd.reductions">[[simd.reductions]]</a>
1716
+
1717
+ ``` cpp
1718
+ template<class T, class Abi, class BinaryOperation = plus<>>
1719
+ constexpr T reduce(const basic_vec<T, Abi>& x, BinaryOperation binary_op = {});
1720
+ ```
1721
+
1722
+ *Constraints:* `BinaryOperation` models `reduction-binary-operation<T>`.
1723
+
1724
+ *Preconditions:* `binary_op` does not modify `x`.
1725
+
1726
+ *Returns:* *GENERALIZED_SUM*(binary_op, vec\<T, 1\>(x\[0\]), …, vec\<T,
1727
+ 1\>(x\[x.size() - 1\]))\[0\] [[numerics.defns]].
1728
+
1729
+ *Throws:* Any exception thrown from `binary_op`.
1730
+
1731
+ ``` cpp
1732
+ template<class T, class Abi, class BinaryOperation = plus<>>
1733
+ constexpr T reduce(
1734
+ const basic_vec<T, Abi>& x, const typename basic_vec<T, Abi>::mask_type& mask,
1735
+ BinaryOperation binary_op = {}, type_identity_t<T> identity_element = see below);
1736
+ ```
1737
+
1738
+ *Constraints:*
1739
+
1740
+ - `BinaryOperation` models `reduction-binary-operation<T>`.
1741
+ - An argument for `identity_element` is provided for the invocation,
1742
+ unless `BinaryOperation` is one of `plus<>`, `multiplies<>`,
1743
+ `bit_and<>`, `bit_or<>`, or `bit_xor<>`.
1744
+
1745
+ *Preconditions:*
1746
+
1747
+ - `binary_op` does not modify `x`.
1748
+ - For all finite values `y` representable by `T`, the results of
1749
+ `y == binary_op(vec<T, 1>(identity_element), vec<T, 1>(y))[0]` and
1750
+ `y == binary_op(vec<T, 1>(y), vec<T, 1>(identity_element))[0]` are
1751
+ `true`.
1752
+
1753
+ *Returns:* If `none_of(mask)` is `true`, returns `identity_element`.
1754
+ Otherwise, returns *GENERALIZED_SUM*(binary_op, vec\<T, 1\>(x\[k₀\]), …,
1755
+ vec\<T, 1\>(x\[kₙ\]))\[0\] where k₀, …, kₙ are the selected indices of
1756
+ `mask`.
1757
+
1758
+ *Throws:* Any exception thrown from `binary_op`.
1759
+
1760
+ *Remarks:* The default argument for `identity_element` is equal to
1761
+
1762
+ - `T()` if `BinaryOperation` is `plus<>`,
1763
+ - `T(1)` if `BinaryOperation` is `multiplies<>`,
1764
+ - `T(~T())` if `BinaryOperation` is `bit_and<>`,
1765
+ - `T()` if `BinaryOperation` is `bit_or<>`, or
1766
+ - `T()` if `BinaryOperation` is `bit_xor<>`.
1767
+
1768
+ ``` cpp
1769
+ template<class T, class Abi> constexpr T reduce_min(const basic_vec<T, Abi>& x) noexcept;
1770
+ ```
1771
+
1772
+ *Constraints:* `T` models `totally_ordered`.
1773
+
1774
+ *Returns:* The value of an element `x[`j`]` for which `x[`i`] < x[`j`]`
1775
+ is `false` for all i in the range of \[`0`,
1776
+ `basic_vec<T, Abi>::size()`).
1777
+
1778
+ ``` cpp
1779
+ template<class T, class Abi>
1780
+ constexpr T reduce_min(
1781
+ const basic_vec<T, Abi>&, const typename basic_vec<T, Abi>::mask_type&) noexcept;
1782
+ ```
1783
+
1784
+ *Constraints:* `T` models `totally_ordered`.
1785
+
1786
+ *Returns:* If `none_of(mask)` is `true`, returns
1787
+ `numeric_limits<T>::max()`. Otherwise, returns the value of a selected
1788
+ element `x[`j`]` for which `x[`i`] < x[`j`]` is `false` for all selected
1789
+ indices i of `mask`.
1790
+
1791
+ ``` cpp
1792
+ template<class T, class Abi> constexpr T reduce_max(const basic_vec<T, Abi>& x) noexcept;
1793
+ ```
1794
+
1795
+ *Constraints:* `T` models `totally_ordered`.
1796
+
1797
+ *Returns:* The value of an element `x[`j`]` for which `x[`j`] < x[`i`]`
1798
+ is `false` for all i in the range of \[`0`,
1799
+ `basic_vec<T, Abi>::size()`).
1800
+
1801
+ ``` cpp
1802
+ template<class T, class Abi>
1803
+ constexpr T reduce_max(
1804
+ const basic_vec<T, Abi>&, const typename basic_vec<T, Abi>::mask_type&) noexcept;
1805
+ ```
1806
+
1807
+ *Constraints:* `T` models `totally_ordered`.
1808
+
1809
+ *Returns:* If `none_of(mask)` is `true`, returns
1810
+ `numeric_limits<V::value_type>::lowest()`. Otherwise, returns the value
1811
+ of a selected element `x[`j`]` for which `x[`j`] < x[`i`]` is `false`
1812
+ for all selected indices i of `mask`.
1813
+
1814
+ #### Load and store functions <a id="simd.loadstore">[[simd.loadstore]]</a>
1815
+
1816
+ ``` cpp
1817
+ template<class V = see below, ranges::contiguous_range R, class... Flags>
1818
+ requires ranges::sized_range<R>
1819
+ constexpr V unchecked_load(R&& r, flags<Flags...> f = {});
1820
+ template<class V = see below, ranges::contiguous_range R, class... Flags>
1821
+ requires ranges::sized_range<R>
1822
+ constexpr V unchecked_load(R&& r, const typename V::mask_type& mask, flags<Flags...> f = {});
1823
+ template<class V = see below, contiguous_iterator I, class... Flags>
1824
+ constexpr V unchecked_load(I first, iter_difference_t<I> n, flags<Flags...> f = {});
1825
+ template<class V = see below, contiguous_iterator I, class... Flags>
1826
+ constexpr V unchecked_load(I first, iter_difference_t<I> n, const typename V::mask_type& mask,
1827
+ flags<Flags...> f = {});
1828
+ template<class V = see below, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags>
1829
+ constexpr V unchecked_load(I first, S last, flags<Flags...> f = {});
1830
+ template<class V = see below, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags>
1831
+ constexpr V unchecked_load(I first, S last, const typename V::mask_type& mask,
1832
+ flags<Flags...> f = {});
1833
+ ```
1834
+
1835
+ Let
1836
+
1837
+ - `mask` be `V::mask_type(true)` for the overloads with no `mask`
1838
+ parameter;
1839
+ - `R` be `span<const iter_value_t<I>>` for the overloads with no
1840
+ template parameter `R`;
1841
+ - `r` be `R(first, n)` for the overloads with an `n` parameter and
1842
+ `R(first, last)` for the overloads with a `last` parameter.
1843
+
1844
+ *Mandates:* If `ranges::size(r)` is a constant expression then
1845
+ `ranges::size(r)` ≥ `V::size()`.
1846
+
1847
+ *Preconditions:*
1848
+
1849
+ - \[`first`, `first + n`) is a valid range for the overloads with an `n`
1850
+ parameter.
1851
+ - \[`first`, `last`) is a valid range for the overloads with a `last`
1852
+ parameter.
1853
+ - `ranges::size(r)` ≥ `V::size()`
1854
+
1855
+ *Effects:* Equivalent to: `return partial_load<V>(r, mask, f);`
1856
+
1857
+ *Remarks:* The default argument for template parameter `V` is
1858
+ `basic_vec<ranges::range_value_t<R>>`.
1859
+
1860
+ ``` cpp
1861
+ template<class V = see below, ranges::contiguous_range R, class... Flags>
1862
+ requires ranges::sized_range<R>
1863
+ constexpr V partial_load(R&& r, flags<Flags...> f = {});
1864
+ template<class V = see below, ranges::contiguous_range R, class... Flags>
1865
+ requires ranges::sized_range<R>
1866
+ constexpr V partial_load(R&& r, const typename V::mask_type& mask, flags<Flags...> f = {});
1867
+ template<class V = see below, contiguous_iterator I, class... Flags>
1868
+ constexpr V partial_load(I first, iter_difference_t<I> n, flags<Flags...> f = {});
1869
+ template<class V = see below, contiguous_iterator I, class... Flags>
1870
+ constexpr V partial_load(I first, iter_difference_t<I> n, const typename V::mask_type& mask,
1871
+ flags<Flags...> f = {});
1872
+ template<class V = see below, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags>
1873
+ constexpr V partial_load(I first, S last, flags<Flags...> f = {});
1874
+ template<class V = see below, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags>
1875
+ constexpr V partial_load(I first, S last, const typename V::mask_type& mask,
1876
+ flags<Flags...> f = {});
1877
+ ```
1878
+
1879
+ Let
1880
+
1881
+ - `mask` be `V::mask_type(true)` for the overloads with no `mask`
1882
+ parameter;
1883
+ - `R` be `span<const iter_value_t<I>>` for the overloads with no
1884
+ template parameter `R`;
1885
+ - `r` be `R(first, n)` for the overloads with an `n` parameter and
1886
+ `R(first, last)` for the overloads with a `last` parameter.
1887
+
1888
+ *Mandates:*
1889
+
1890
+ - `ranges::range_value_t<R>` is a vectorizable type,
1891
+ - `same_as<remove_cvref_t<V>, V>` is `true`,
1892
+ - `V` is an enabled specialization of `basic_vec`, and
1893
+ - if the template parameter pack `Flags` does not contain
1894
+ *`convert-flag`*, then the conversion from `ranges::range_value_t<R>`
1895
+ to `V::value_type` is value-preserving.
1896
+
1897
+ *Preconditions:*
1898
+
1899
+ - \[`first`, `first + n`) is a valid range for the overloads with an `n`
1900
+ parameter.
1901
+ - \[`first`, `last`) is a valid range for the overloads with a `last`
1902
+ parameter.
1903
+ - If the template parameter pack `Flags` contains *`aligned-flag`*,
1904
+ `ranges::data(r)` points to storage aligned by
1905
+ `alignment_v<V, ranges::range_value_t<R>>`.
1906
+ - If the template parameter pack `Flags` contains
1907
+ *`overaligned-flag`*`<N>`, `ranges::data(r)` points to storage aligned
1908
+ by `N`.
1909
+
1910
+ *Effects:* Initializes the iᵗʰ element with
1911
+ `mask[`i`] && `i` < ranges::size(r) ? static_cast<T>(ranges::data(r)[`i`]) : T()`
1912
+ for all i in the range of \[`0`, `V::size()`).
1913
+
1914
+ *Remarks:* The default argument for template parameter `V` is
1915
+ `basic_vec<ranges::range_value_t<R>>`.
1916
+
1917
+ ``` cpp
1918
+ template<class T, class Abi, ranges::contiguous_range R, class... Flags>
1919
+ requires ranges::sized_range<R> && indirectly_writable<ranges::iterator_t<R>, T>
1920
+ constexpr void unchecked_store(const basic_vec<T, Abi>& v, R&& r, flags<Flags...> f = {});
1921
+ template<class T, class Abi, ranges::contiguous_range R, class... Flags>
1922
+ requires ranges::sized_range<R> && indirectly_writable<ranges::iterator_t<R>, T>
1923
+ constexpr void unchecked_store(const basic_vec<T, Abi>& v, R&& r,
1924
+ const typename basic_vec<T, Abi>::mask_type& mask, flags<Flags...> f = {});
1925
+ template<class T, class Abi, contiguous_iterator I, class... Flags>
1926
+ requires indirectly_writable<I, T>
1927
+ constexpr void unchecked_store(const basic_vec<T, Abi>& v, I first, iter_difference_t<I> n,
1928
+ flags<Flags...> f = {});
1929
+ template<class T, class Abi, contiguous_iterator I, class... Flags>
1930
+ requires indirectly_writable<I, T>
1931
+ constexpr void unchecked_store(const basic_vec<T, Abi>& v, I first, iter_difference_t<I> n,
1932
+ const typename basic_vec<T, Abi>::mask_type& mask, flags<Flags...> f = {});
1933
+ template<class T, class Abi, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags>
1934
+ requires indirectly_writable<I, T>
1935
+ constexpr void unchecked_store(const basic_vec<T, Abi>& v, I first, S last,
1936
+ flags<Flags...> f = {});
1937
+ template<class T, class Abi, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags>
1938
+ requires indirectly_writable<I, T>
1939
+ constexpr void unchecked_store(const basic_vec<T, Abi>& v, I first, S last,
1940
+ const typename basic_vec<T, Abi>::mask_type& mask, flags<Flags...> f = {});
1941
+ ```
1942
+
1943
+ Let
1944
+
1945
+ - `mask` be `basic_vec<T, Abi>::mask_type(true)` for the overloads with
1946
+ no `mask` parameter;
1947
+ - `R` be `span<iter_value_t<I>>` for the overloads with no template
1948
+ parameter `R`;
1949
+ - `r` be `R(first, n)` for the overloads with an `n` parameter and
1950
+ `R(first, last)` for the overloads with a `last` parameter.
1951
+
1952
+ *Mandates:* If `ranges::size(r)` is a constant expression then
1953
+ `ranges::size(r)` ≥ *`simd-size-v`*`<T, Abi>`.
1954
+
1955
+ *Preconditions:*
1956
+
1957
+ - \[`first`, `first + n`) is a valid range for the overloads with an `n`
1958
+ parameter.
1959
+ - \[`first`, `last`) is a valid range for the overloads with a `last`
1960
+ parameter.
1961
+ - `ranges::size(r)` ≥ *`simd-size-v`*`<T, Abi>`
1962
+
1963
+ *Effects:* Equivalent to: `partial_store(v, r, mask, f)`.
1964
+
1965
+ ``` cpp
1966
+ template<class T, class Abi, ranges::contiguous_range R, class... Flags>
1967
+ requires ranges::sized_range<R> && indirectly_writable<ranges::iterator_t<R>, T>
1968
+ constexpr void partial_store(const basic_vec<T, Abi>& v, R&& r, flags<Flags...> f = {});
1969
+ template<class T, class Abi, ranges::contiguous_range R, class... Flags>
1970
+ requires ranges::sized_range<R> && indirectly_writable<ranges::iterator_t<R>, T>
1971
+ constexpr void partial_store(const basic_vec<T, Abi>& v, R&& r,
1972
+ const typename basic_vec<T, Abi>::mask_type& mask, flags<Flags...> f = {});
1973
+ template<class T, class Abi, contiguous_iterator I, class... Flags>
1974
+ requires indirectly_writable<I, T>
1975
+ constexpr void partial_store(const basic_vec<T, Abi>& v, I first, iter_difference_t<I> n,
1976
+ flags<Flags...> f = {});
1977
+ template<class T, class Abi, contiguous_iterator I, class... Flags>
1978
+ requires indirectly_writable<I, T>
1979
+ constexpr void partial_store(const basic_vec<T, Abi>& v, I first, iter_difference_t<I> n,
1980
+ const typename basic_vec<T, Abi>::mask_type& mask, flags<Flags...> f = {});
1981
+ template<class T, class Abi, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags>
1982
+ requires indirectly_writable<I, T>
1983
+ constexpr void partial_store(const basic_vec<T, Abi>& v, I first, S last,
1984
+ flags<Flags...> f = {});
1985
+ template<class T, class Abi, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags>
1986
+ requires indirectly_writable<I, T>
1987
+ constexpr void partial_store(const basic_vec<T, Abi>& v, I first, S last,
1988
+ const typename basic_vec<T, Abi>::mask_type& mask, flags<Flags...> f = {});
1989
+ ```
1990
+
1991
+ Let
1992
+
1993
+ - `mask` be `basic_vec<T, Abi>::mask_type(true)` for the overloads with
1994
+ no `mask` parameter;
1995
+ - `R` be `span<iter_value_t<I>>` for the overloads with no template
1996
+ parameter `R`;
1997
+ - `r` be `R(first, n)` for the overloads with an `n` parameter and
1998
+ `R(first, last)` for the overloads with a `last` parameter.
1999
+
2000
+ *Mandates:*
2001
+
2002
+ - `ranges::range_value_t<R>` is a vectorizable type, and
2003
+ - if the template parameter pack `Flags` does not contain
2004
+ *`convert-flag`*, then the conversion from `T` to
2005
+ `ranges::range_value_t<R>` is value-preserving.
2006
+
2007
+ *Preconditions:*
2008
+
2009
+ - \[`first`, `first + n`) is a valid range for the overloads with an `n`
2010
+ parameter.
2011
+ - \[`first`, `last`) is a valid range for the overloads with a `last`
2012
+ parameter.
2013
+ - If the template parameter pack `Flags` contains *`aligned-flag`*,
2014
+ `ranges::data(r)` points to storage aligned by
2015
+ `alignment_v<basic_vec<T, Abi>, ranges::range_value_t<R>>`.
2016
+ - If the template parameter pack `Flags` contains
2017
+ *`overaligned-flag`*`<N>`, `ranges::data(r)` points to storage aligned
2018
+ by `N`.
2019
+
2020
+ *Effects:* For all i in the range of \[`0`,
2021
+ `basic_vec<T, Abi>::size()`), if `mask[`i`] && `i` < ranges::size(r)` is
2022
+ `true`, evaluates `ranges::data(r)[`i`] = v[`i`]`.
2023
+
2024
+ #### Static permute <a id="simd.permute.static">[[simd.permute.static]]</a>
2025
+
2026
+ ``` cpp
2027
+ template<simd-size-type N = see below, simd-vec-type V, class IdxMap>
2028
+ constexpr resize_t<N, V> permute(const V& v, IdxMap&& idxmap);
2029
+ template<simd-size-type N = see below, simd-mask-type M, class IdxMap>
2030
+ constexpr resize_t<N, M> permute(const M& v, IdxMap&& idxmap);
2031
+ ```
2032
+
2033
+ Let:
2034
+
2035
+ - *`gen-fn`*`(i)` be `idxmap(i, V::size())` if that expression is
2036
+ well-formed, and `idxmap(i)` otherwise.
2037
+ - *perm-fn* be the following exposition-only function template:
2038
+ ``` cpp
2039
+ template<simd-size-type I>
2040
+ typename V::value_type perm-fn() {
2041
+ constexpr auto src_index = gen-fn(I);
2042
+ if constexpr (src_index == zero_element) {
2043
+ return typename V::value_type();
2044
+ } else if constexpr (src_index == uninit_element) {
2045
+ return unspecified-value;
2046
+ } else {
2047
+ return v[src_index];
2048
+ }
2049
+ }
2050
+ ```
2051
+
2052
+ *Constraints:* At least one of
2053
+ `invoke_result_t<IdxMap&, `*`simd-size-type`*`>` and
2054
+ `invoke_result_t<IdxMap&, `*`simd-size-type`*`, `*`simd-size-type`*`>`
2055
+ satisfies `integral`.
2056
+
2057
+ *Mandates:* *`gen-fn`*`(`i`)` is a constant expression whose value is
2058
+ `zero_element`, `uninit_element`, or in the range \[`0`, `V::size()`),
2059
+ for all i in the range \[`0`, `N`).
2060
+
2061
+ *Returns:* A data-parallel object where the iᵗʰ element is initialized
2062
+ to the result of *`perm-fn`*`<`i`>()` for all i in the range \[`0`,
2063
+ `N`).
2064
+
2065
+ *Remarks:* The default argument for template parameter `N` is
2066
+ `V::size()`.
2067
+
2068
+ #### Dynamic permute <a id="simd.permute.dynamic">[[simd.permute.dynamic]]</a>
2069
+
2070
+ ``` cpp
2071
+ template<simd-vec-type V, simd-integral I>
2072
+ constexpr resize_t<I::size(), V> permute(const V& v, const I& indices);
2073
+ template<simd-mask-type M, simd-integral I>
2074
+ constexpr resize_t<I::size(), M> permute(const M& v, const I& indices);
2075
+ ```
2076
+
2077
+ *Preconditions:* All values in `indices` are in the range \[`0`,
2078
+ `V::size()`).
2079
+
2080
+ *Returns:* A data-parallel object where the iᵗʰ element is initialized
2081
+ to the result of `v[indices[`i`]]` for all i in the range \[`0`,
2082
+ `I::size()`).
2083
+
2084
+ #### Mask permute <a id="simd.permute.mask">[[simd.permute.mask]]</a>
2085
+
2086
+ ``` cpp
2087
+ template<simd-vec-type V>
2088
+ constexpr V compress(const V& v, const typename V::mask_type& selector);
2089
+ template<simd-mask-type M>
2090
+ constexpr M compress(const M& v, const type_identity_t<M>& selector);
2091
+ ```
2092
+
2093
+ Let:
2094
+
2095
+ - *`bit-index`*`(`i`)` be a function which returns the index of the iᵗʰ
2096
+ element of `selector` that is `true`.
2097
+ - *`select-value`*`(`i`)` be a function which returns
2098
+ `v[`*`bit-index`*`(`i`)]` for i in the range \[`0`,
2099
+ `reduce_count(selector)`) and a valid but unspecified value otherwise.
2100
+ \[*Note 1*: Different calls to *`select-value`* can return different
2101
+ unspecified values. — *end note*]
2102
+
2103
+ *Returns:* A data-parallel object where the iᵗʰ element is initialized
2104
+ to the result of *`select-value`*`(`i`)` for all i in the range \[`0`,
2105
+ `V::size()`).
2106
+
2107
+ ``` cpp
2108
+ template<simd-vec-type V>
2109
+ constexpr V compress(const V& v, const typename V::mask_type& selector,
2110
+ const typename V::value_type& fill_value);
2111
+ template<simd-mask-type M>
2112
+ constexpr M compress(const M& v, const type_identity_t<M>& selector,
2113
+ const typename M::value_type& fill_value);
2114
+ ```
2115
+
2116
+ Let:
2117
+
2118
+ - *`bit-index`*`(`i`)` be a function which returns the index of the iᵗʰ
2119
+ element of `selector` that is `true`.
2120
+ - *`select-value`*`(`i`)` be a function which returns
2121
+ `v[`*`bit-index`*`(`i`)]` for i in the range \[`0`,
2122
+ `reduce_count(selector)`) and `fill_value` otherwise.
2123
+
2124
+ *Returns:* A data-parallel object where the iᵗʰ element is initialized
2125
+ to the result of *`select-value`*`(`i`)` for all i in the range \[`0`,
2126
+ `V::size()`).
2127
+
2128
+ ``` cpp
2129
+ template<simd-vec-type V>
2130
+ constexpr V expand(const V& v, const typename V::mask_type& selector, const V& original = {});
2131
+ template<simd-mask-type M>
2132
+ constexpr M expand(const M& v, const type_identity_t<M>& selector, const M& original = {});
2133
+ ```
2134
+
2135
+ Let:
2136
+
2137
+ - *set-indices* be a list of the index positions of `true` elements in
2138
+ `selector`, in ascending order.
2139
+ - *`bit-lookup`*`(`b`)` be a function which returns the index where b
2140
+ appears in *`set-indices`*.
2141
+ - *`select-value`*`(`i`)` be a function which returns
2142
+ `v[`*`bit-lookup`*`(`i`)]` if `selector[`i`]` is `true`, otherwise
2143
+ returns `original[`i`]`.
2144
+
2145
+ *Returns:* A data-parallel object where the iᵗʰ element is initialized
2146
+ to the result of *`select-value`*`(`i`)` for all i in the range \[`0`,
2147
+ `V::size()`).
2148
+
2149
+ #### Memory permute <a id="simd.permute.memory">[[simd.permute.memory]]</a>
2150
+
2151
+ ``` cpp
2152
+ template<class V = see below, ranges::contiguous_range R, simd-integral I, class... Flags>
2153
+ requires ranges::sized_range<R>
2154
+ constexpr V unchecked_gather_from(R&& in, const I& indices, flags<Flags...> f = {});
2155
+ template<class V = see below, ranges::contiguous_range R, simd-integral I, class... Flags>
2156
+ requires ranges::sized_range<R>
2157
+ constexpr V unchecked_gather_from(R&& in, const typename I::mask_type& mask,
2158
+ const I& indices, flags<Flags...> f = {});
2159
+ ```
2160
+
2161
+ Let `mask` be `typename I::mask_type(true)` for the overload with no
2162
+ `mask` parameter.
2163
+
2164
+ *Preconditions:* All values in
2165
+ `select(mask, indices, typename I::value_type())` are in the range
2166
+ \[`0`, `ranges::size(in)`).
2167
+
2168
+ *Effects:* Equivalent to:
2169
+ `return partial_gather_from<V>(in, mask, indices, f);`
2170
+
2171
+ *Remarks:* The default argument for template parameter `V` is
2172
+ `vec<ranges::range_value_t<R>, I::size()>`.
2173
+
2174
+ ``` cpp
2175
+ template<class V = see below, ranges::contiguous_range R, simd-integral I, class... Flags>
2176
+ requires ranges::sized_range<R>
2177
+ constexpr V partial_gather_from(R&& in, const I& indices, flags<Flags...> f = {});
2178
+ template<class V = see below, ranges::contiguous_range R, simd-integral I, class... Flags>
2179
+ requires ranges::sized_range<R>
2180
+ constexpr V partial_gather_from(R&& in, const typename I::mask_type& mask,
2181
+ const I& indices, flags<Flags...> f = {});
2182
+ ```
2183
+
2184
+ Let:
2185
+
2186
+ - `mask` be `typename I::mask_type(true)` for the overload with no
2187
+ `mask` parameter;
2188
+ - `T` be `typename V::value_type`.
2189
+
2190
+ *Mandates:*
2191
+
2192
+ - `ranges::range_value_t<R>` is a vectorizable type,
2193
+ - `same_as<remove_cvref_t<V>, V>` is `true`,
2194
+ - `V` is an enabled specialization of `basic_vec`,
2195
+ - `V::size() == I::size()` is `true`, and
2196
+ - if the template parameter pack `Flags` does not contain
2197
+ *convert-flag*, then the conversion from `ranges::range_value_t<R>` to
2198
+ `T` is value-preserving.
2199
+
2200
+ *Preconditions:*
2201
+
2202
+ - If the template parameter pack `Flags` contains *aligned-flag*,
2203
+ `ranges::data(in)` points to storage aligned by
2204
+ `alignment_v<V, ranges::range_value_t<R>>`.
2205
+ - If the template parameter pack `Flags` contains
2206
+ *`overaligned-flag`*`<N>`, `ranges::data(in)` points to storage
2207
+ aligned by `N`.
2208
+
2209
+ *Returns:* A `basic_vec` object where the iᵗʰ element is initialized to
2210
+ the result of
2211
+
2212
+ ``` cpp
2213
+ mask[i] && indices[i] < ranges::size(in) ? static_cast<T>(ranges::data(in)[indices[i]]) : T()
2214
+ ```
2215
+
2216
+ for all i in the range \[`0`, `I::size()`).
2217
+
2218
+ *Remarks:* The default argument for template parameter `V` is
2219
+ `vec<ranges::range_value_t<R>, I::size()>`.
2220
+
2221
+ ``` cpp
2222
+ template<simd-vec-type V, ranges::contiguous_range R, simd-integral I, class... Flags>
2223
+ requires ranges::sized_range<R>
2224
+ constexpr void unchecked_scatter_to(const V& v, R&& out, const I& indices,
2225
+ flags<Flags...> f = {});
2226
+ template<simd-vec-type V, ranges::contiguous_range R, simd-integral I, class... Flags>
2227
+ requires ranges::sized_range<R>
2228
+ constexpr void unchecked_scatter_to(const V& v, R&& out, const typename I::mask_type& mask,
2229
+ const I& indices, flags<Flags...> f = {});
2230
+ ```
2231
+
2232
+ Let `mask` be `typename I::mask_type(true)` for the overload with no
2233
+ `mask` parameter.
2234
+
2235
+ *Preconditions:* All values in
2236
+ `select(mask, indices, typename I::value_type())` are in the range
2237
+ \[`0`, `ranges::size(out)`).
2238
+
2239
+ *Effects:* Equivalent to:
2240
+ `partial_scatter_to(v, out, mask, indices, f);`
2241
+
2242
+ ``` cpp
2243
+ template<simd-vec-type V, ranges::contiguous_range R, simd-integral I, class... Flags>
2244
+ requires ranges::sized_range<R>
2245
+ constexpr void
2246
+ partial_scatter_to(const V& v, R&& out, const I& indices, flags<Flags...> f = {});
2247
+ template<simd-vec-type V, ranges::contiguous_range R, simd-integral I, class... Flags>
2248
+ requires ranges::sized_range<R>
2249
+ constexpr void partial_scatter_to(const V& v, R&& out, const typename I::mask_type& mask,
2250
+ const I& indices, flags<Flags...> f = {});
2251
+ ```
2252
+
2253
+ Let `mask` be `typename I::mask_type(true)` for the overload with no
2254
+ `mask` parameter.
2255
+
2256
+ *Constraints:* `V::size() == I::size()` is `true`.
2257
+
2258
+ *Mandates:*
2259
+
2260
+ - `ranges::range_value_t<R>` is a vectorizable type, and
2261
+ - if the template parameter pack `Flags` does not contain
2262
+ *convert-flag*, then the conversion from `typename V::value_type` to
2263
+ `ranges::range_value_t<R>` is value-preserving.
2264
+
2265
+ *Preconditions:*
2266
+
2267
+ - For all selected indices i the values `indices[`i`]` are unique.
2268
+ - If the template parameter pack `Flags` contains *aligned-flag*,
2269
+ `ranges::data(out)` points to storage aligned by
2270
+ `alignment_v<V, ranges::range_value_t<R>>`.
2271
+ - If the template parameter pack `Flags` contains
2272
+ *`overaligned-flag`*`<N>`, `ranges::data(out)` points to storage
2273
+ aligned by `N`.
2274
+
2275
+ *Effects:* For all i in the range \[`0`, `I::size()`), if
2276
+ `mask[`i`] && (indices[`i`] < ranges::size(out))` is `true`, evaluates
2277
+ `ranges::data(out)[indices[`i`]] = v[`i`]`.
2278
+
2279
+ #### Creation <a id="simd.creation">[[simd.creation]]</a>
2280
+
2281
+ ``` cpp
2282
+ template<class T, class Abi>
2283
+ constexpr auto chunk(const basic_vec<typename T::value_type, Abi>& x) noexcept;
2284
+ template<class T, class Abi>
2285
+ constexpr auto chunk(const basic_mask<mask-element-size<T>, Abi>& x) noexcept;
2286
+ ```
2287
+
2288
+ *Constraints:*
2289
+
2290
+ - For the first overload, `T` is an enabled specialization of
2291
+ `basic_vec`. If
2292
+ `basic_vec<typename T::value_type, Abi>::size() % T::size()` is not
2293
+ `0`, then
2294
+ `resize_t<basic_vec<typename T::value_type, Abi>::size() % T::size(), T>`
2295
+ is valid and denotes a type.
2296
+ - For the second overload, `T` is an enabled specialization of
2297
+ `basic_mask`. If
2298
+ `basic_mask<`*`mask-element-size`*`<T>, Abi>::size() % T::size()` is
2299
+ not `0`, then
2300
+ `resize_t<basic_mask<`*`mask-element-size`*`<T>, Abi>::size() % T::size(), T>`
2301
+ is valid and denotes a type.
2302
+
2303
+ Let N be `x.size() / T::size()`.
2304
+
2305
+ *Returns:*
2306
+
2307
+ - If `x.size() % T::size() == 0` is `true`, an `array<T, `N`>` with the
2308
+ iᵗʰ `basic_vec` or `basic_mask` element of the jᵗʰ `array` element
2309
+ initialized to the value of the element in `x` with index
2310
+ i` + `j` * T::size()`.
2311
+ - Otherwise, a `tuple` of N objects of type `T` and one object of type
2312
+ `resize_t<x.size() % T::size(), T>`. The iᵗʰ `basic_vec` or
2313
+ `basic_mask` element of the jᵗʰ `tuple` element of type `T` is
2314
+ initialized to the value of the element in `x` with index
2315
+ i` + `j` * T::size()`. The iᵗʰ `basic_vec` or `basic_mask` element of
2316
+ the Nᵗʰ `tuple` element is initialized to the value of the element in
2317
+ `x` with index i` + `N` * T::size()`.
2318
+
2319
+ ``` cpp
2320
+ template<simd-size-type N, class T, class Abi>
2321
+ constexpr auto chunk(const basic_vec<T, Abi>& x) noexcept;
2322
+ ```
2323
+
2324
+ *Effects:* Equivalent to:
2325
+ `return chunk<resize_t<N, basic_vec<T, Abi>>>(x);`
2326
+
2327
+ ``` cpp
2328
+ template<simd-size-type N, size_t Bytes, class Abi>
2329
+ constexpr auto chunk(const basic_mask<Bytes, Abi>& x) noexcept;
2330
+ ```
2331
+
2332
+ *Effects:* Equivalent to:
2333
+ `return chunk<resize_t<N, basic_mask<Bytes, Abi>>>(x);`
2334
+
2335
+ ``` cpp
2336
+ template<class T, class... Abis>
2337
+ constexpr vec<T, (basic_vec<T, Abis>::size() + ...)>
2338
+ cat(const basic_vec<T, Abis>&... xs) noexcept;
2339
+ template<size_t Bytes, class... Abis>
2340
+ constexpr basic_mask<Bytes, deduce-abi-t<integer-from<Bytes>,
2341
+ (basic_mask<Bytes, Abis>::size() + ...)>>
2342
+ cat(const basic_mask<Bytes, Abis>&... xs) noexcept;
2343
+ ```
2344
+
2345
+ *Constraints:*
2346
+
2347
+ - For the first overload `vec<T, (basic_vec<T, Abis>::size() + ...)>` is
2348
+ enabled.
2349
+ - For the second overload
2350
+ `basic_mask<Bytes, `*`deduce-abi-t`*`<`*`integer-from`*`<Bytes>, (basic_mask<Bytes, Abis>::size() + ...)>>`
2351
+ is enabled.
2352
+
2353
+ *Returns:* A data-parallel object initialized with the concatenated
2354
+ values in the `xs` pack of data-parallel objects: The iᵗʰ
2355
+ `basic_vec`/`basic_mask` element of the jᵗʰ parameter in the `xs` pack
2356
+ is copied to the return value’s element with index i + the sum of the
2357
+ width of the first j parameters in the `xs` pack.
2358
+
2359
+ #### Algorithms <a id="simd.alg">[[simd.alg]]</a>
2360
+
2361
+ ``` cpp
2362
+ template<class T, class Abi>
2363
+ constexpr basic_vec<T, Abi> min(const basic_vec<T, Abi>& a,
2364
+ const basic_vec<T, Abi>& b) noexcept;
2365
+ ```
2366
+
2367
+ *Constraints:* `T` models `totally_ordered`.
2368
+
2369
+ *Returns:* The result of the element-wise application of
2370
+ `min(a[`i`], b[`i`])` for all i in the range of \[`0`,
2371
+ `basic_vec<T, Abi>::size()`).
2372
+
2373
+ ``` cpp
2374
+ template<class T, class Abi>
2375
+ constexpr basic_vec<T, Abi> max(const basic_vec<T, Abi>& a,
2376
+ const basic_vec<T, Abi>& b) noexcept;
2377
+ ```
2378
+
2379
+ *Constraints:* `T` models `totally_ordered`.
2380
+
2381
+ *Returns:* The result of the element-wise application of
2382
+ `max(a[`i`], b[`i`])` for all i in the range of \[`0`,
2383
+ `basic_vec<T, Abi>::size()`).
2384
+
2385
+ ``` cpp
2386
+ template<class T, class Abi>
2387
+ constexpr pair<basic_vec<T, Abi>, basic_vec<T, Abi>>
2388
+ minmax(const basic_vec<T, Abi>& a, const basic_vec<T, Abi>& b) noexcept;
2389
+ ```
2390
+
2391
+ *Effects:* Equivalent to: `return pair{min(a, b), max(a, b)};`
2392
+
2393
+ ``` cpp
2394
+ template<class T, class Abi>
2395
+ constexpr basic_vec<T, Abi> clamp(
2396
+ const basic_vec<T, Abi>& v, const basic_vec<T, Abi>& lo, const basic_vec<T, Abi>& hi);
2397
+ ```
2398
+
2399
+ *Constraints:* `T` models `totally_ordered`.
2400
+
2401
+ *Preconditions:* No element in `lo` is greater than the corresponding
2402
+ element in `hi`.
2403
+
2404
+ *Returns:* The result of element-wise application of
2405
+ `clamp(v[`i`], lo[`i`], hi[`i`])` for all i in the range of \[`0`,
2406
+ `basic_vec<T, Abi>::size()`).
2407
+
2408
+ ``` cpp
2409
+ template<class T, class U>
2410
+ constexpr auto select(bool c, const T& a, const U& b)
2411
+ -> remove_cvref_t<decltype(c ? a : b)>;
2412
+ ```
2413
+
2414
+ *Effects:* Equivalent to: `return c ? a : b;`
2415
+
2416
+ ``` cpp
2417
+ template<size_t Bytes, class Abi, class T, class U>
2418
+ constexpr auto select(const basic_mask<Bytes, Abi>& c, const T& a, const U& b)
2419
+ noexcept -> decltype(simd-select-impl(c, a, b));
2420
+ ```
2421
+
2422
+ *Effects:* Equivalent to:
2423
+
2424
+ ``` cpp
2425
+ return simd-select-impl(c, a, b);
2426
+ ```
2427
+
2428
+ where *`simd-select-impl`* is found by argument-dependent
2429
+ lookup [[basic.lookup.argdep]] contrary to [[contents]].
2430
+
2431
+ #### Mathematical functions <a id="simd.math">[[simd.math]]</a>
2432
+
2433
+ ``` cpp
2434
+ template<math-floating-point V>
2435
+ constexpr rebind_t<int, deduced-vec-t<V>> ilogb(const V& x);
2436
+ template<math-floating-point V>
2437
+ constexpr deduced-vec-t<V> ldexp(const V& x, const rebind_t<int, deduced-vec-t<V>>& exp);
2438
+ template<math-floating-point V>
2439
+ constexpr deduced-vec-t<V> scalbn(const V& x, const rebind_t<int, deduced-vec-t<V>>& n);
2440
+ template<math-floating-point V>
2441
+ constexpr deduced-vec-t<V>
2442
+ scalbln(const V& x, const rebind_t<long int, deduced-vec-t<V>>& n);
2443
+ template<signed_integral T, class Abi>
2444
+ constexpr basic_vec<T, Abi> abs(const basic_vec<T, Abi>& j);
2445
+ template<math-floating-point V>
2446
+ constexpr deduced-vec-t<V> abs(const V& j);
2447
+ template<math-floating-point V>
2448
+ constexpr deduced-vec-t<V> fabs(const V& x);
2449
+ template<math-floating-point V>
2450
+ constexpr deduced-vec-t<V> ceil(const V& x);
2451
+ template<math-floating-point V>
2452
+ constexpr deduced-vec-t<V> floor(const V& x);
2453
+ template<math-floating-point V>
2454
+ deduced-vec-t<V> nearbyint(const V& x);
2455
+ template<math-floating-point V>
2456
+ deduced-vec-t<V> rint(const V& x);
2457
+ template<math-floating-point V>
2458
+ rebind_t<long int, deduced-vec-t<V>> lrint(const V& x);
2459
+ template<math-floating-point V>
2460
+ rebind_t<long long int, deduced-vec-t<V>> llrint(const V& x);
2461
+ template<math-floating-point V>
2462
+ constexpr deduced-vec-t<V> round(const V& x);
2463
+ template<math-floating-point V>
2464
+ constexpr rebind_t<long int, deduced-vec-t<V>> lround(const V& x);
2465
+ template<math-floating-point V>
2466
+ constexpr rebind_t<long long int, deduced-vec-t<V>> llround(const V& x);
2467
+ template<class V0, class V1>
2468
+ constexpr math-common-simd-t<V0, V1> fmod(const V0& x, const V1& y);
2469
+ template<math-floating-point V>
2470
+ constexpr deduced-vec-t<V> trunc(const V& x);
2471
+ template<class V0, class V1>
2472
+ constexpr math-common-simd-t<V0, V1> remainder(const V0& x, const V1& y);
2473
+ template<class V0, class V1>
2474
+ constexpr math-common-simd-t<V0, V1> copysign(const V0& x, const V1& y);
2475
+ template<class V0, class V1>
2476
+ constexpr math-common-simd-t<V0, V1> nextafter(const V0& x, const V1& y);
2477
+ template<class V0, class V1>
2478
+ constexpr math-common-simd-t<V0, V1> fdim(const V0& x, const V1& y);
2479
+ template<class V0, class V1>
2480
+ constexpr math-common-simd-t<V0, V1> fmax(const V0& x, const V1& y);
2481
+ template<class V0, class V1>
2482
+ constexpr math-common-simd-t<V0, V1> fmin(const V0& x, const V1& y);
2483
+ template<class V0, class V1, class V2>
2484
+ constexpr math-common-simd-t<V0, V1, V2> fma(const V0& x, const V1& y, const V2& z);
2485
+ template<math-floating-point V>
2486
+ constexpr rebind_t<int, deduced-vec-t<V>> fpclassify(const V& x);
2487
+ template<math-floating-point V>
2488
+ constexpr typename deduced-vec-t<V>::mask_type isfinite(const V& x);
2489
+ template<math-floating-point V>
2490
+ constexpr typename deduced-vec-t<V>::mask_type isinf(const V& x);
2491
+ template<math-floating-point V>
2492
+ constexpr typename deduced-vec-t<V>::mask_type isnan(const V& x);
2493
+ template<math-floating-point V>
2494
+ constexpr typename deduced-vec-t<V>::mask_type isnormal(const V& x);
2495
+ template<math-floating-point V>
2496
+ constexpr typename deduced-vec-t<V>::mask_type signbit(const V& x);
2497
+ template<class V0, class V1>
2498
+ constexpr typename math-common-simd-t<V0, V1>::mask_type isgreater(const V0& x, const V1& y);
2499
+ template<class V0, class V1>
2500
+ constexpr typename math-common-simd-t<V0, V1>::mask_type
2501
+ isgreaterequal(const V0& x, const V1& y);
2502
+ template<class V0, class V1>
2503
+ constexpr typename math-common-simd-t<V0, V1>::mask_type isless(const V0& x, const V1& y);
2504
+ template<class V0, class V1>
2505
+ constexpr typename math-common-simd-t<V0, V1>::mask_type islessequal(const V0& x, const V1& y);
2506
+ template<class V0, class V1>
2507
+ constexpr typename math-common-simd-t<V0, V1>::mask_type islessgreater(const V0& x, const V1& y);
2508
+ template<class V0, class V1>
2509
+ constexpr typename math-common-simd-t<V0, V1>::mask_type isunordered(const V0& x, const V1& y);
2510
+ ```
2511
+
2512
+ Let `Ret` denote the return type of the specialization of a function
2513
+ template with the name *`math-func`*. Let *`math-func-vec`* denote:
2514
+
2515
+ ``` cpp
2516
+ template<class... Args>
2517
+ Ret math-func-vec(Args... args) {
2518
+ return Ret([&](simd-size-type i) {
2519
+ return math-func(make-compatible-simd-t<Ret, Args>(args)[i]...);
2520
+ });
2521
+ }
2522
+ ```
2523
+
2524
+ *Returns:* A value `ret` of type `Ret`, that is element-wise equal to
2525
+ the result of calling *`math-func-vec`* with the arguments of the above
2526
+ functions. If in an invocation of a scalar overload of *`math-func`* for
2527
+ index `i` in *`math-func-vec`* a domain, pole, or range error would
2528
+ occur, the value of `ret[i]` is unspecified.
2529
+
2530
+ *Remarks:* It is unspecified whether `errno` [[errno]] is accessed.
2531
+
2532
+ ``` cpp
2533
+ template<math-floating-point V> constexpr deduced-vec-t<V> acos(const V& x);
2534
+ template<math-floating-point V> constexpr deduced-vec-t<V> asin(const V& x);
2535
+ template<math-floating-point V> constexpr deduced-vec-t<V> atan(const V& x);
2536
+ template<class V0, class V1>
2537
+ constexpr math-common-simd-t<V0, V1> atan2(const V0& y, const V1& x);
2538
+ template<math-floating-point V> constexpr deduced-vec-t<V> cos(const V& x);
2539
+ template<math-floating-point V> constexpr deduced-vec-t<V> sin(const V& x);
2540
+ template<math-floating-point V> constexpr deduced-vec-t<V> tan(const V& x);
2541
+ template<math-floating-point V> constexpr deduced-vec-t<V> acosh(const V& x);
2542
+ template<math-floating-point V> constexpr deduced-vec-t<V> asinh(const V& x);
2543
+ template<math-floating-point V> constexpr deduced-vec-t<V> atanh(const V& x);
2544
+ template<math-floating-point V> constexpr deduced-vec-t<V> cosh(const V& x);
2545
+ template<math-floating-point V> constexpr deduced-vec-t<V> sinh(const V& x);
2546
+ template<math-floating-point V> constexpr deduced-vec-t<V> tanh(const V& x);
2547
+ template<math-floating-point V> constexpr deduced-vec-t<V> exp(const V& x);
2548
+ template<math-floating-point V> constexpr deduced-vec-t<V> exp2(const V& x);
2549
+ template<math-floating-point V> constexpr deduced-vec-t<V> expm1(const V& x);
2550
+ template<math-floating-point V> constexpr deduced-vec-t<V> log(const V& x);
2551
+ template<math-floating-point V> constexpr deduced-vec-t<V> log10(const V& x);
2552
+ template<math-floating-point V> constexpr deduced-vec-t<V> log1p(const V& x);
2553
+ template<math-floating-point V> constexpr deduced-vec-t<V> log2(const V& x);
2554
+ template<math-floating-point V> constexpr deduced-vec-t<V> logb(const V& x);
2555
+ template<math-floating-point V> constexpr deduced-vec-t<V> cbrt(const V& x);
2556
+ template<class V0, class V1>
2557
+ constexpr math-common-simd-t<V0, V1> hypot(const V0& x, const V1& y);
2558
+ template<class V0, class V1, class V2>
2559
+ constexpr math-common-simd-t<V0, V1, V2> hypot(const V0& x, const V1& y, const V2& z);
2560
+ template<class V0, class V1>
2561
+ constexpr math-common-simd-t<V0, V1> pow(const V0& x, const V1& y);
2562
+ template<math-floating-point V> constexpr deduced-vec-t<V> sqrt(const V& x);
2563
+ template<math-floating-point V> constexpr deduced-vec-t<V> erf(const V& x);
2564
+ template<math-floating-point V> constexpr deduced-vec-t<V> erfc(const V& x);
2565
+ template<math-floating-point V> constexpr deduced-vec-t<V> lgamma(const V& x);
2566
+ template<math-floating-point V> constexpr deduced-vec-t<V> tgamma(const V& x);
2567
+ template<class V0, class V1, class V2>
2568
+ constexpr math-common-simd-t<V0, V1, V2> lerp(const V0& a, const V1& b, const V2& t) noexcept;
2569
+ template<math-floating-point V>
2570
+ deduced-vec-t<V> assoc_laguerre(const rebind_t<unsigned, deduced-vec-t<V>>& n, const
2571
+ rebind_t<unsigned, deduced-vec-t<V>>& m, const V& x);
2572
+ template<math-floating-point V>
2573
+ deduced-vec-t<V> assoc_legendre(const rebind_t<unsigned, deduced-vec-t<V>>& l, const
2574
+ rebind_t<unsigned, deduced-vec-t<V>>& m, const V& x);
2575
+ template<class V0, class V1>
2576
+ math-common-simd-t<V0, V1> beta(const V0& x, const V1& y);
2577
+ template<math-floating-point V> deduced-vec-t<V> comp_ellint_1(const V& k);
2578
+ template<math-floating-point V> deduced-vec-t<V> comp_ellint_2(const V& k);
2579
+ template<class V0, class V1>
2580
+ math-common-simd-t<V0, V1> comp_ellint_3(const V0& k, const V1& nu);
2581
+ template<class V0, class V1>
2582
+ math-common-simd-t<V0, V1> cyl_bessel_i(const V0& nu, const V1& x);
2583
+ template<class V0, class V1>
2584
+ math-common-simd-t<V0, V1> cyl_bessel_j(const V0& nu, const V1& x);
2585
+ template<class V0, class V1>
2586
+ math-common-simd-t<V0, V1> cyl_bessel_k(const V0& nu, const V1& x);
2587
+ template<class V0, class V1>
2588
+ math-common-simd-t<V0, V1> cyl_neumann(const V0& nu, const V1& x);
2589
+ template<class V0, class V1>
2590
+ math-common-simd-t<V0, V1> ellint_1(const V0& k, const V1& phi);
2591
+ template<class V0, class V1>
2592
+ math-common-simd-t<V0, V1> ellint_2(const V0& k, const V1& phi);
2593
+ template<class V0, class V1, class V2>
2594
+ math-common-simd-t<V0, V1, V2> ellint_3(const V0& k, const V1& nu, const V2& phi);
2595
+ template<math-floating-point V> deduced-vec-t<V> expint(const V& x);
2596
+ template<math-floating-point V> deduced-vec-t<V> hermite(const rebind_t<unsigned,
2597
+ deduced-vec-t<V>>& n, const V& x);
2598
+ template<math-floating-point V> deduced-vec-t<V> laguerre(const rebind_t<unsigned,
2599
+ deduced-vec-t<V>>& n, const V& x);
2600
+ template<math-floating-point V> deduced-vec-t<V> legendre(const rebind_t<unsigned,
2601
+ deduced-vec-t<V>>& l, const V& x);
2602
+ template<math-floating-point V> deduced-vec-t<V> riemann_zeta(const V& x);
2603
+ template<math-floating-point V> deduced-vec-t<V> sph_bessel(const rebind_t<unsigned,
2604
+ deduced-vec-t<V>>& n, const V& x);
2605
+ template<math-floating-point V>
2606
+ deduced-vec-t<V> sph_legendre(const rebind_t<unsigned, deduced-vec-t<V>>& l,
2607
+ const rebind_t<unsigned, deduced-vec-t<V>>& m,
2608
+ const V& theta);
2609
+ template<math-floating-point V> deduced-vec-t<V> sph_neumann(const rebind_t<unsigned,
2610
+ deduced-vec-t<V>>& n, const V& x);
2611
+ ```
2612
+
2613
+ Let `Ret` denote the return type of the specialization of a function
2614
+ template with the name *`math-func`*. Let *`math-func-vec`* denote:
2615
+
2616
+ ``` cpp
2617
+ template<class... Args>
2618
+ Ret math-func-vec(Args... args) {
2619
+ return Ret([&](simd-size-type i) {
2620
+ return math-func(make-compatible-simd-t<Ret, Args>(args)[i]...);
2621
+ });
2622
+ }
2623
+ ```
2624
+
2625
+ *Returns:* A value `ret` of type `Ret`, that is element-wise
2626
+ approximately equal to the result of calling *`math-func-vec`* with the
2627
+ arguments of the above functions. If in an invocation of a scalar
2628
+ overload of *`math-func`* for index `i` in *`math-func-vec`* a domain,
2629
+ pole, or range error would occur, the value of `ret[i]` is unspecified.
2630
+
2631
+ *Remarks:* It is unspecified whether `errno` [[errno]] is accessed.
2632
+
2633
+ ``` cpp
2634
+ template<math-floating-point V>
2635
+ constexpr deduced-vec-t<V> frexp(const V& value, rebind_t<int, deduced-vec-t<V>>* exp);
2636
+ ```
2637
+
2638
+ Let `Ret` be *`deduced-vec-t`*`<V>`. Let *`frexp-vec`* denote:
2639
+
2640
+ ``` cpp
2641
+ template<class V>
2642
+ pair<Ret, rebind_t<int, Ret>> frexp-vec(const V& x) {
2643
+ int r1[Ret::size()];
2644
+ Ret r0([&](simd-size-type i) {
2645
+ return frexp(make-compatible-simd-t<Ret, V>(x)[i], &r1[i]);
2646
+ });
2647
+ return {r0, rebind_t<int, Ret>(r1)};
2648
+ }
2649
+ ```
2650
+
2651
+ Let `ret` be a value of type `pair<Ret, rebind_t<int, Ret>>` that is the
2652
+ same value as the result of calling *`frexp-vec`*`(x)`.
2653
+
2654
+ *Effects:* Sets `*exp` to `ret.second`.
2655
+
2656
+ *Returns:* `ret.first`.
2657
+
2658
+ ``` cpp
2659
+ template<class V0, class V1>
2660
+ constexpr math-common-simd-t<V0, V1> remquo(const V0& x, const V1& y,
2661
+ rebind_t<int, math-common-simd-t<V0, V1>>* quo);
2662
+ ```
2663
+
2664
+ Let `Ret` be *`math-common-simd-t`*`<V0, V1>`. Let *`remquo-vec`*
2665
+ denote:
2666
+
2667
+ ``` cpp
2668
+ template<class V0, class V1>
2669
+ pair<Ret, rebind_t<int, Ret>> remquo-vec(const V0& x, const V1& y) {
2670
+ int r1[Ret::size()];
2671
+ Ret r0([&](simd-size-type i) {
2672
+ return remquo(make-compatible-simd-t<Ret, V0>(x)[i],
2673
+ make-compatible-simd-t<Ret, V1>(y)[i], &r1[i]);
2674
+ });
2675
+ return {r0, rebind_t<int, Ret>(r1)};
2676
+ }
2677
+ ```
2678
+
2679
+ Let `ret` be a value of type `pair<Ret, rebind_t<int, Ret>>` that is the
2680
+ same value as the result of calling *`remquo-vec`*`(x, y)`. If in an
2681
+ invocation of a scalar overload of `remquo` for index `i` in
2682
+ *`remquo-vec`* a domain, pole, or range error would occur, the value of
2683
+ `ret[i]` is unspecified.
2684
+
2685
+ *Effects:* Sets `*quo` to `ret.second`.
2686
+
2687
+ *Returns:* `ret.first`.
2688
+
2689
+ *Remarks:* It is unspecified whether `errno` [[errno]] is accessed.
2690
+
2691
+ ``` cpp
2692
+ template<class T, class Abi>
2693
+ constexpr basic_vec<T, Abi> modf(const type_identity_t<basic_vec<T, Abi>>& value,
2694
+ basic_vec<T, Abi>* iptr);
2695
+ ```
2696
+
2697
+ Let `V` be `basic_vec<T, Abi>`. Let *`modf-vec`* denote:
2698
+
2699
+ ``` cpp
2700
+ pair<V, V> modf-vec(const V& x) {
2701
+ T r1[Ret::size()];
2702
+ V r0([&](simd-size-type i) {
2703
+ return modf(V(x)[i], &r1[i]);
2704
+ });
2705
+ return {r0, V(r1)};
2706
+ }
2707
+ ```
2708
+
2709
+ Let `ret` be a value of type `pair<V, V>` that is the same value as the
2710
+ result of calling *`modf-vec`*`(value)`.
2711
+
2712
+ *Effects:* Sets `*iptr` to `ret.second`.
2713
+
2714
+ *Returns:* `ret.first`.
2715
+
2716
+ #### Bit manipulation <a id="simd.bit">[[simd.bit]]</a>
2717
+
2718
+ ``` cpp
2719
+ template<simd-vec-type V> constexpr V byteswap(const V& v) noexcept;
2720
+ ```
2721
+
2722
+ *Constraints:* The type `V::value_type` models `integral`.
2723
+
2724
+ *Returns:* A `basic_vec` object where the iᵗʰ element is initialized to
2725
+ the result of `std::byteswap(v[`i`])` for all i in the range \[`0`,
2726
+ `V::size()`).
2727
+
2728
+ ``` cpp
2729
+ template<simd-vec-type V> constexpr V bit_ceil(const V& v) noexcept;
2730
+ ```
2731
+
2732
+ *Constraints:* The type `V::value_type` is an unsigned integer
2733
+ type [[basic.fundamental]].
2734
+
2735
+ *Preconditions:* For every i in the range \[`0`, `V::size()`), the
2736
+ smallest power of 2 greater than or equal to `v[`i`]` is representable
2737
+ as a value of type `V::value_type`.
2738
+
2739
+ *Returns:* A `basic_vec` object where the iᵗʰ element is initialized to
2740
+ the result of `std::bit_ceil(v[`i`])` for all i in the range \[`0`,
2741
+ `V::size()`).
2742
+
2743
+ *Remarks:* A function call expression that violates the precondition in
2744
+ the *Preconditions:* element is not a core constant
2745
+ expression [[expr.const]].
2746
+
2747
+ ``` cpp
2748
+ template<simd-vec-type V> constexpr V bit_floor(const V& v) noexcept;
2749
+ ```
2750
+
2751
+ *Constraints:* The type `V::value_type` is an unsigned integer
2752
+ type [[basic.fundamental]].
2753
+
2754
+ *Returns:* A `basic_vec` object where the iᵗʰ element is initialized to
2755
+ the result of `std::bit_floor(v[`i`])` for all i in the range \[`0`,
2756
+ `V::size()`).
2757
+
2758
+ ``` cpp
2759
+ template<simd-vec-type V>
2760
+ constexpr typename V::mask_type has_single_bit(const V& v) noexcept;
2761
+ ```
2762
+
2763
+ *Constraints:* The type `V::value_type` is an unsigned integer
2764
+ type [[basic.fundamental]].
2765
+
2766
+ *Returns:* A `basic_mask` object where the iᵗʰ element is initialized to
2767
+ the result of `std::has_single_bit(v[`i`])` for all i in the range
2768
+ \[`0`, `V::size()`).
2769
+
2770
+ ``` cpp
2771
+ template<simd-vec-type V0, simd-vec-type V1>
2772
+ constexpr V0 rotl(const V0& v0, const V1& v1) noexcept;
2773
+ template<simd-vec-type V0, simd-vec-type V1>
2774
+ constexpr V0 rotr(const V0& v0, const V1& v1) noexcept;
2775
+ ```
2776
+
2777
+ *Constraints:*
2778
+
2779
+ - The type `V0::value_type` is an unsigned integer
2780
+ type [[basic.fundamental]],
2781
+ - the type `V1::value_type` models `integral`,
2782
+ - `V0::size() == V1::size()` is `true`, and
2783
+ - `sizeof(typename V0::value_type) == sizeof(typename V1::value_type)`
2784
+ is `true`.
2785
+
2786
+ *Returns:* A `basic_vec` object where the iᵗʰ element is initialized to
2787
+ the result of *`bit-func`*`(v0[`i`], static_cast<int>(v1[`i`]))` for all
2788
+ i in the range \[`0`, `V0::size()`), where *`bit-func`* is the
2789
+ corresponding scalar function from `<bit>`.
2790
+
2791
+ ``` cpp
2792
+ template<simd-vec-type V> constexpr V rotl(const V& v, int s) noexcept;
2793
+ template<simd-vec-type V> constexpr V rotr(const V& v, int s) noexcept;
2794
+ ```
2795
+
2796
+ *Constraints:* The type `V::value_type` is an unsigned integer
2797
+ type [[basic.fundamental]].
2798
+
2799
+ *Returns:* A `basic_vec` object where the iᵗʰ element is initialized to
2800
+ the result of *`bit-func`*`(v[`i`], s)` for all i in the range \[`0`,
2801
+ `V::size()`), where *`bit-func`* is the corresponding scalar function
2802
+ from `<bit>`.
2803
+
2804
+ ``` cpp
2805
+ template<simd-vec-type V>
2806
+ constexpr rebind_t<make_signed_t<typename V::value_type>, V> bit_width(const V& v) noexcept;
2807
+ template<simd-vec-type V>
2808
+ constexpr rebind_t<make_signed_t<typename V::value_type>, V> countl_zero(const V& v) noexcept;
2809
+ template<simd-vec-type V>
2810
+ constexpr rebind_t<make_signed_t<typename V::value_type>, V> countl_one(const V& v) noexcept;
2811
+ template<simd-vec-type V>
2812
+ constexpr rebind_t<make_signed_t<typename V::value_type>, V> countr_zero(const V& v) noexcept;
2813
+ template<simd-vec-type V>
2814
+ constexpr rebind_t<make_signed_t<typename V::value_type>, V> countr_one(const V& v) noexcept;
2815
+ template<simd-vec-type V>
2816
+ constexpr rebind_t<make_signed_t<typename V::value_type>, V> popcount(const V& v) noexcept;
2817
+ ```
2818
+
2819
+ *Constraints:* The type `V::value_type` is an unsigned integer
2820
+ type [[basic.fundamental]].
2821
+
2822
+ *Returns:* A `basic_vec` object where the iᵗʰ element is initialized to
2823
+ the result of *`bit-func`*`(v[`i`])` for all i in the range \[`0`,
2824
+ `V::size()`), where *`bit-func`* is the corresponding scalar function
2825
+ from `<bit>`.
2826
+
2827
+ #### Complex math <a id="simd.complex.math">[[simd.complex.math]]</a>
2828
+
2829
+ ``` cpp
2830
+ template<simd-complex V>
2831
+ constexpr rebind_t<simd-complex-value-type<V>, V> real(const V&) noexcept;
2832
+ template<simd-complex V>
2833
+ constexpr rebind_t<simd-complex-value-type<V>, V> imag(const V&) noexcept;
2834
+
2835
+ template<simd-complex V>
2836
+ constexpr rebind_t<simd-complex-value-type<V>, V> abs(const V&);
2837
+ template<simd-complex V>
2838
+ constexpr rebind_t<simd-complex-value-type<V>, V> arg(const V&);
2839
+ template<simd-complex V>
2840
+ constexpr rebind_t<simd-complex-value-type<V>, V> norm(const V&);
2841
+ template<simd-complex V> constexpr V conj(const V&);
2842
+ template<simd-complex V> constexpr V proj(const V&);
2843
+
2844
+ template<simd-complex V> constexpr V exp(const V& v);
2845
+ template<simd-complex V> constexpr V log(const V& v);
2846
+ template<simd-complex V> constexpr V log10(const V& v);
2847
+
2848
+ template<simd-complex V> constexpr V sqrt(const V& v);
2849
+ template<simd-complex V> constexpr V sin(const V& v);
2850
+ template<simd-complex V> constexpr V asin(const V& v);
2851
+ template<simd-complex V> constexpr V cos(const V& v);
2852
+ template<simd-complex V> constexpr V acos(const V& v);
2853
+ template<simd-complex V> constexpr V tan(const V& v);
2854
+ template<simd-complex V> constexpr V atan(const V& v);
2855
+ template<simd-complex V> constexpr V sinh(const V& v);
2856
+ template<simd-complex V> constexpr V asinh(const V& v);
2857
+ template<simd-complex V> constexpr V cosh(const V& v);
2858
+ template<simd-complex V> constexpr V acosh(const V& v);
2859
+ template<simd-complex V> constexpr V tanh(const V& v);
2860
+ template<simd-complex V> constexpr V atanh(const V& v);
2861
+ ```
2862
+
2863
+ *Returns:* A `basic_vec` object `ret` where the iᵗʰ element is
2864
+ initialized to the result of *`cmplx-func`*`(v[`i`])` for all i in the
2865
+ range \[`0`, `V::size()`), where *`cmplx-func`* is the corresponding
2866
+ function from `<complex>`. If in an invocation of *`cmplx-func`* for
2867
+ index i a domain, pole, or range error would occur, the value of
2868
+ `ret[`i`]` is unspecified.
2869
+
2870
+ *Remarks:* It is unspecified whether `errno` [[errno]] is accessed.
2871
+
2872
+ ``` cpp
2873
+ template<simd-floating-point V>
2874
+ rebind_t<complex<typename V::value_type>, V> polar(const V& x, const V& y = {});
2875
+
2876
+ template<simd-complex V> constexpr V pow(const V& x, const V& y);
2877
+ ```
2878
+
2879
+ *Returns:* A `basic_vec` object `ret` where the iᵗʰ element is
2880
+ initialized to the result of *`cmplx-func`*`(x[`i`], y[`i`])` for all i
2881
+ in the range \[`0`, `V::size()`), where *`cmplx-func`* is the
2882
+ corresponding function from `<complex>`. If in an invocation of
2883
+ *`cmplx-func`* for index i a domain, pole, or range error would occur,
2884
+ the value of `ret[`i`]` is unspecified.
2885
+
2886
+ *Remarks:* It is unspecified whether `errno` [[errno]] is accessed.
2887
+
2888
+ ### Class template `basic_mask` <a id="simd.mask.class">[[simd.mask.class]]</a>
2889
+
2890
+ #### Overview <a id="simd.mask.overview">[[simd.mask.overview]]</a>
2891
+
2892
+ ``` cpp
2893
+ namespace std::simd {
2894
+ template<size_t Bytes, class Abi> class basic_mask {
2895
+ public:
2896
+ using value_type = bool;
2897
+ using abi_type = Abi;
2898
+ using iterator = simd-iterator<basic_mask>;
2899
+ using const_iterator = simd-iterator<const basic_mask>;
2900
+
2901
+ constexpr iterator begin() noexcept { return {*this, 0}; }
2902
+ constexpr const_iterator begin() const noexcept { return {*this, 0}; }
2903
+ constexpr const_iterator cbegin() const noexcept { return {*this, 0}; }
2904
+ constexpr default_sentinel_t end() const noexcept { return {}; }
2905
+ constexpr default_sentinel_t cend() const noexcept { return {}; }
2906
+
2907
+ static constexpr integral_constant<simd-size-type, simd-size-v<integer-from<Bytes>, Abi>>
2908
+ size {};
2909
+
2910
+ constexpr basic_mask() noexcept = default;
2911
+
2912
+ // [simd.mask.ctor], basic_mask constructors
2913
+ constexpr explicit basic_mask(value_type) noexcept;
2914
+ template<size_t UBytes, class UAbi>
2915
+ constexpr explicit basic_mask(const basic_mask<UBytes, UAbi>&) noexcept;
2916
+ template<class G>
2917
+ constexpr explicit basic_mask(G&& gen);
2918
+ constexpr basic_mask(const bitset<size()>& b) noexcept;
2919
+ constexpr explicit basic_mask(unsigned_integral auto val) noexcept;
2920
+
2921
+ // [simd.mask.subscr], basic_mask subscript operators
2922
+ constexpr value_type operator[](simd-size-type) const;
2923
+ template<simd-integral I>
2924
+ constexpr resize_t<I::size(), basic_mask> operator[](const I& indices) const;
2925
+
2926
+ // [simd.mask.unary], basic_mask unary operators
2927
+ constexpr basic_mask operator!() const noexcept;
2928
+ constexpr basic_vec<integer-from<Bytes>, Abi> operator+() const noexcept;
2929
+ constexpr basic_vec<integer-from<Bytes>, Abi> operator-() const noexcept;
2930
+ constexpr basic_vec<integer-from<Bytes>, Abi> operator~() const noexcept;
2931
+
2932
+ // [simd.mask.conv], basic_mask conversions
2933
+ template<class U, class A>
2934
+ constexpr explicit(sizeof(U) != Bytes) operator basic_vec<U, A>() const noexcept;
2935
+ constexpr bitset<size()> to_bitset() const noexcept;
2936
+ constexpr unsigned long long to_ullong() const;
2937
+
2938
+ // [simd.mask.binary], basic_mask binary operators
2939
+ friend constexpr basic_mask
2940
+ operator&&(const basic_mask&, const basic_mask&) noexcept;
2941
+ friend constexpr basic_mask
2942
+ operator||(const basic_mask&, const basic_mask&) noexcept;
2943
+ friend constexpr basic_mask
2944
+ operator&(const basic_mask&, const basic_mask&) noexcept;
2945
+ friend constexpr basic_mask
2946
+ operator|(const basic_mask&, const basic_mask&) noexcept;
2947
+ friend constexpr basic_mask
2948
+ operator^(const basic_mask&, const basic_mask&) noexcept;
2949
+
2950
+ // [simd.mask.cassign], basic_mask compound assignment
2951
+ friend constexpr basic_mask&
2952
+ operator&=(basic_mask&, const basic_mask&) noexcept;
2953
+ friend constexpr basic_mask&
2954
+ operator|=(basic_mask&, const basic_mask&) noexcept;
2955
+ friend constexpr basic_mask&
2956
+ operator^=(basic_mask&, const basic_mask&) noexcept;
2957
+
2958
+ // [simd.mask.comparison], basic_mask comparisons
2959
+ friend constexpr basic_mask
2960
+ operator==(const basic_mask&, const basic_mask&) noexcept;
2961
+ friend constexpr basic_mask
2962
+ operator!=(const basic_mask&, const basic_mask&) noexcept;
2963
+ friend constexpr basic_mask
2964
+ operator>=(const basic_mask&, const basic_mask&) noexcept;
2965
+ friend constexpr basic_mask
2966
+ operator<=(const basic_mask&, const basic_mask&) noexcept;
2967
+ friend constexpr basic_mask
2968
+ operator>(const basic_mask&, const basic_mask&) noexcept;
2969
+ friend constexpr basic_mask
2970
+ operator<(const basic_mask&, const basic_mask&) noexcept;
2971
+
2972
+ // [simd.mask.cond], basic_mask exposition only conditional operators
2973
+ friend constexpr basic_mask simd-select-impl( // exposition only
2974
+ const basic_mask&, const basic_mask&, const basic_mask&) noexcept;
2975
+ friend constexpr basic_mask simd-select-impl( // exposition only
2976
+ const basic_mask&, same_as<bool> auto, same_as<bool> auto) noexcept;
2977
+ template<class T0, class T1>
2978
+ friend constexpr vec<see below, size()>
2979
+ simd-select-impl(const basic_mask&, const T0&, const T1&) noexcept; // exposition only
2980
+ };
2981
+ }
2982
+ ```
2983
+
2984
+ Every specialization of `basic_mask` is a complete type. The
2985
+ specialization of `basic_mask<Bytes, Abi>` is:
2986
+
2987
+ - disabled, if there is no vectorizable type `T` such that `Bytes` is
2988
+ equal to `sizeof(T)`,
2989
+ - otherwise, enabled, if there exists a vectorizable type `T` and a
2990
+ value `N` in the range \[`1`, `64`\] such that `Bytes` is equal to
2991
+ `sizeof(T)` and `Abi` is `deduce-abi-t<T,
2992
+ N>`,
2993
+ - otherwise, it is *implementation-defined* if such a specialization is
2994
+ enabled.
2995
+
2996
+ If `basic_mask<Bytes, Abi>` is disabled, the specialization has a
2997
+ deleted default constructor, deleted destructor, deleted copy
2998
+ constructor, and deleted copy assignment. In addition only the
2999
+ `value_type` and `abi_type` members are present.
3000
+
3001
+ If `basic_mask<Bytes, Abi>` is enabled, `basic_mask<Bytes, Abi>` is
3002
+ trivially copyable.
3003
+
3004
+ *Recommended practice:* Implementations should support implicit
3005
+ conversions between specializations of `basic_mask` and appropriate
3006
+ *implementation-defined* types.
3007
+
3008
+ [*Note 1*: Appropriate types are non-standard vector types which are
3009
+ available in the implementation. — *end note*]
3010
+
3011
+ #### Constructors <a id="simd.mask.ctor">[[simd.mask.ctor]]</a>
3012
+
3013
+ ``` cpp
3014
+ constexpr explicit basic_mask(value_type x) noexcept;
3015
+ ```
3016
+
3017
+ *Effects:* Initializes each element with `x`.
3018
+
3019
+ ``` cpp
3020
+ template<size_t UBytes, class UAbi>
3021
+ constexpr explicit basic_mask(const basic_mask<UBytes, UAbi>& x) noexcept;
3022
+ ```
3023
+
3024
+ *Constraints:* `basic_mask<UBytes, UAbi>::size() == size()` is `true`.
3025
+
3026
+ *Effects:* Initializes the iᵗʰ element with `x[`i`]` for all i in the
3027
+ range of \[`0`, `size()`).
3028
+
3029
+ ``` cpp
3030
+ template<class G> constexpr explicit basic_mask(G&& gen);
3031
+ ```
3032
+
3033
+ *Constraints:* The expression
3034
+ `gen(integral_constant<`*`simd-size-type`*`, i>())` is well-formed and
3035
+ its type is `bool` for all i in the range of \[`0`, `size()`).
3036
+
3037
+ *Effects:* Initializes the iᵗʰ element with
3038
+ `gen(integral_constant<`*`simd-size-type`*`, i>())` for all i in the
3039
+ range of \[`0`, `size()`).
3040
+
3041
+ *Remarks:* `gen` is invoked exactly once for each i, in increasing order
3042
+ of i.
3043
+
3044
+ ``` cpp
3045
+ constexpr basic_mask(const bitset<size()>& b) noexcept;
3046
+ ```
3047
+
3048
+ *Effects:* Initializes the iᵗʰ element with `b[`i`]` for all i in the
3049
+ range \[`0`, `size()`).
3050
+
3051
+ ``` cpp
3052
+ constexpr explicit basic_mask(unsigned_integral auto val) noexcept;
3053
+ ```
3054
+
3055
+ *Effects:* Initializes the first M elements to the corresponding bit
3056
+ values in `val`, where M is the smaller of `size()` and the number of
3057
+ bits in the value representation [[basic.types.general]] of the type of
3058
+ `val`. If M is less than `size()`, the remaining elements are
3059
+ initialized to zero.
3060
+
3061
+ #### Subscript operator <a id="simd.mask.subscr">[[simd.mask.subscr]]</a>
3062
+
3063
+ ``` cpp
3064
+ constexpr value_type operator[](simd-size-type i) const;
3065
+ ```
3066
+
3067
+ *Preconditions:* `i >= 0 && i < size()` is `true`.
3068
+
3069
+ *Returns:* The value of the iᵗʰ element.
3070
+
3071
+ *Throws:* Nothing.
3072
+
3073
+ ``` cpp
3074
+ template<simd-integral I>
3075
+ constexpr resize_t<I::size(), basic_mask> operator[](const I& indices) const;
3076
+ ```
3077
+
3078
+ *Effects:* Equivalent to: `return permute(*this, indices);`
3079
+
3080
+ #### Unary operators <a id="simd.mask.unary">[[simd.mask.unary]]</a>
3081
+
3082
+ ``` cpp
3083
+ constexpr basic_mask operator!() const noexcept;
3084
+ constexpr basic_vec<integer-from<Bytes>, Abi> operator+() const noexcept;
3085
+ constexpr basic_vec<integer-from<Bytes>, Abi> operator-() const noexcept;
3086
+ constexpr basic_vec<integer-from<Bytes>, Abi> operator~() const noexcept;
3087
+ ```
3088
+
3089
+ Let *op* be the operator.
3090
+
3091
+ *Returns:* A data-parallel object where the iᵗʰ element is initialized
3092
+ to the results of applying *op* to `operator[](`i`)` for all i in the
3093
+ range of \[`0`, `size()`).
3094
+
3095
+ #### Conversions <a id="simd.mask.conv">[[simd.mask.conv]]</a>
3096
+
3097
+ ``` cpp
3098
+ template<class U, class A>
3099
+ constexpr explicit(sizeof(U) != Bytes) operator basic_vec<U, A>() const noexcept;
3100
+ ```
3101
+
3102
+ *Constraints:* *`simd-size-v`*`<U, A> == `*`simd-size-v`*`<T, Abi>`.
3103
+
3104
+ *Returns:* A data-parallel object where the iᵗʰ element is initialized
3105
+ to `static_cast<U>(operator[](`i`))`.
3106
+
3107
+ ``` cpp
3108
+ constexpr bitset<size()> to_bitset() const noexcept;
3109
+ ```
3110
+
3111
+ *Returns:* A `bitset<size()>` object where the iᵗʰ element is
3112
+ initialized to `operator[](`i`)` for all i in the range \[`0`,
3113
+ `size()`).
3114
+
3115
+ ``` cpp
3116
+ constexpr unsigned long long to_ullong() const;
3117
+ ```
3118
+
3119
+ Let N be the width of `unsigned long long`.
3120
+
3121
+ *Preconditions:*
3122
+
3123
+ - `size() <= `N is `true`, or
3124
+ - for all i in the range \[N, `size()`), `operator[](`i`)` returns
3125
+ `false`.
3126
+
3127
+ *Returns:* The integral value corresponding to the bits in `*this`.
3128
+
3129
+ *Throws:* Nothing.
3130
+
3131
+ ### `basic_mask` non-member operations <a id="simd.mask.nonmembers">[[simd.mask.nonmembers]]</a>
3132
+
3133
+ #### Binary operators <a id="simd.mask.binary">[[simd.mask.binary]]</a>
3134
+
3135
+ ``` cpp
3136
+ friend constexpr basic_mask
3137
+ operator&&(const basic_mask& lhs, const basic_mask& rhs) noexcept;
3138
+ friend constexpr basic_mask
3139
+ operator||(const basic_mask& lhs, const basic_mask& rhs) noexcept;
3140
+ friend constexpr basic_mask
3141
+ operator& (const basic_mask& lhs, const basic_mask& rhs) noexcept;
3142
+ friend constexpr basic_mask
3143
+ operator| (const basic_mask& lhs, const basic_mask& rhs) noexcept;
3144
+ friend constexpr basic_mask
3145
+ operator^ (const basic_mask& lhs, const basic_mask& rhs) noexcept;
3146
+ ```
3147
+
3148
+ Let *op* be the operator.
3149
+
3150
+ *Returns:* A `basic_mask` object initialized with the results of
3151
+ applying *op* to `lhs` and `rhs` as a binary element-wise operation.
3152
+
3153
+ #### Compound assignment <a id="simd.mask.cassign">[[simd.mask.cassign]]</a>
3154
+
3155
+ ``` cpp
3156
+ friend constexpr basic_mask&
3157
+ operator&=(basic_mask& lhs, const basic_mask& rhs) noexcept;
3158
+ friend constexpr basic_mask&
3159
+ operator|=(basic_mask& lhs, const basic_mask& rhs) noexcept;
3160
+ friend constexpr basic_mask&
3161
+ operator^=(basic_mask& lhs, const basic_mask& rhs) noexcept;
3162
+ ```
3163
+
3164
+ Let *op* be the operator.
3165
+
3166
+ *Effects:* These operators apply *op* to `lhs` and `rhs` as a binary
3167
+ element-wise operation.
3168
+
3169
+ *Returns:* `lhs`.
3170
+
3171
+ #### Comparisons <a id="simd.mask.comparison">[[simd.mask.comparison]]</a>
3172
+
3173
+ ``` cpp
3174
+ friend constexpr basic_mask
3175
+ operator==(const basic_mask& lhs, const basic_mask& rhs) noexcept;
3176
+ friend constexpr basic_mask
3177
+ operator!=(const basic_mask& lhs, const basic_mask& rhs) noexcept;
3178
+ friend constexpr basic_mask
3179
+ operator>=(const basic_mask& lhs, const basic_mask& rhs) noexcept;
3180
+ friend constexpr basic_mask
3181
+ operator<=(const basic_mask& lhs, const basic_mask& rhs) noexcept;
3182
+ friend constexpr basic_mask
3183
+ operator>(const basic_mask& lhs, const basic_mask& rhs) noexcept;
3184
+ friend constexpr basic_mask
3185
+ operator<(const basic_mask& lhs, const basic_mask& rhs) noexcept;
3186
+ ```
3187
+
3188
+ Let *op* be the operator.
3189
+
3190
+ *Returns:* A `basic_mask` object initialized with the results of
3191
+ applying *op* to `lhs` and `rhs` as a binary element-wise operation.
3192
+
3193
+ #### Exposition-only conditional operators <a id="simd.mask.cond">[[simd.mask.cond]]</a>
3194
+
3195
+ ``` cpp
3196
+ friend constexpr basic_mask simd-select-impl(
3197
+ const basic_mask& mask, const basic_mask& a, const basic_mask& b) noexcept;
3198
+ ```
3199
+
3200
+ *Returns:* A `basic_mask` object where the iᵗʰ element equals
3201
+ `mask[`i`] ? a[`i`] : b[`i`]` for all i in the range of \[`0`,
3202
+ `size()`).
3203
+
3204
+ ``` cpp
3205
+ friend constexpr basic_mask
3206
+ simd-select-impl(const basic_mask& mask, same_as<bool> auto a, same_as<bool> auto b) noexcept;
3207
+ ```
3208
+
3209
+ *Returns:* A `basic_mask` object where the iᵗʰ element equals
3210
+ `mask[`i`] ? a : b` for all i in the range of \[`0`, `size()`).
3211
+
3212
+ ``` cpp
3213
+ template<class T0, class T1>
3214
+ friend constexpr vec<see below, size()>
3215
+ simd-select-impl(const basic_mask& mask, const T0& a, const T1& b) noexcept;
3216
+ ```
3217
+
3218
+ *Constraints:*
3219
+
3220
+ - `same_as<T0, T1>` is `true`,
3221
+ - `T0` is a vectorizable type, and
3222
+ - `sizeof(T0) == Bytes`.
3223
+
3224
+ *Returns:* A `vec<T0, size()>` object where the iᵗʰ element equals
3225
+ `mask[`i`] ? a : b` for all i in the range of \[`0`, `size()`).
3226
+
3227
+ #### Reductions <a id="simd.mask.reductions">[[simd.mask.reductions]]</a>
3228
+
3229
+ ``` cpp
3230
+ template<size_t Bytes, class Abi>
3231
+ constexpr bool all_of(const basic_mask<Bytes, Abi>& k) noexcept;
3232
+ ```
3233
+
3234
+ *Returns:* `true` if all boolean elements in `k` are `true`, otherwise
3235
+ `false`.
3236
+
3237
+ ``` cpp
3238
+ template<size_t Bytes, class Abi>
3239
+ constexpr bool any_of(const basic_mask<Bytes, Abi>& k) noexcept;
3240
+ ```
3241
+
3242
+ *Returns:* `true` if at least one boolean element in `k` is `true`,
3243
+ otherwise `false`.
3244
+
3245
+ ``` cpp
3246
+ template<size_t Bytes, class Abi>
3247
+ constexpr bool none_of(const basic_mask<Bytes, Abi>& k) noexcept;
3248
+ ```
3249
+
3250
+ *Returns:* `!any_of(k)`.
3251
+
3252
+ ``` cpp
3253
+ template<size_t Bytes, class Abi>
3254
+ constexpr simd-size-type reduce_count(const basic_mask<Bytes, Abi>& k) noexcept;
3255
+ ```
3256
+
3257
+ *Returns:* The number of boolean elements in `k` that are `true`.
3258
+
3259
+ ``` cpp
3260
+ template<size_t Bytes, class Abi>
3261
+ constexpr simd-size-type reduce_min_index(const basic_mask<Bytes, Abi>& k);
3262
+ ```
3263
+
3264
+ *Preconditions:* `any_of(k)` is `true`.
3265
+
3266
+ *Returns:* The lowest element index i where `k[`i`]` is `true`.
3267
+
3268
+ ``` cpp
3269
+ template<size_t Bytes, class Abi>
3270
+ constexpr simd-size-type reduce_max_index(const basic_mask<Bytes, Abi>& k);
3271
+ ```
3272
+
3273
+ *Preconditions:* `any_of(k)` is `true`.
3274
+
3275
+ *Returns:* The greatest element index i where `k[`i`]` is `true`.
3276
+
3277
+ ``` cpp
3278
+ constexpr bool all_of(same_as<bool> auto x) noexcept;
3279
+ constexpr bool any_of(same_as<bool> auto x) noexcept;
3280
+ constexpr simd-size-type reduce_count(same_as<bool> auto x) noexcept;
3281
+ ```
3282
+
3283
+ *Returns:* `x`.
3284
+
3285
+ ``` cpp
3286
+ constexpr bool none_of(same_as<bool> auto x) noexcept;
3287
+ ```
3288
+
3289
+ *Returns:* `!x`.
3290
+
3291
+ ``` cpp
3292
+ constexpr simd-size-type reduce_min_index(same_as<bool> auto x);
3293
+ constexpr simd-size-type reduce_max_index(same_as<bool> auto x);
3294
+ ```
3295
+
3296
+ *Preconditions:* `x` is `true`.
3297
+
3298
+ *Returns:* `0`.
3299
+