Data-parallel types (SIMD) (since C++26)
The library provides data-parallel types and operations on these types: portable types for explicitly stating data-parallelism and structuring data through data-parallel execution resources where available, such as SIMD
All standard integer types, character types, and most floating-point types are vectorizable types. Vectorizable floating-point types include float, double, and the selected extended floating-point types std::float16_t, std::float32_t, and std::float64_t
A data-parallel type consists of one or more elements of an underlying vectorizable type, called the element type. The number of elements, called the width, is constant for each data-parallel type.
The data-parallel type refers to all enabled specializations of the class templates basic_simd
and basic_simd_mask
.
A data-parallel object of data-parallel type behaves analogously to objects of type T
. But while T
stores and manipulates a single value, the data-parallel type with the element type T
Every operation on a data-parallel object acts element-wise
All operations (except non-constexpr math function overloads) on data-parallel objects are constexpr
Alias templates simd
and simd_mask
are defined to allow users to specify the width to a certain size. The default width is determined by the implementation at compile-time.
Defined in header
<simd> |
Main classes
(C++26)
|
data-parallel vector type (class template) |
(C++26)
|
convenience alias template for basic_simd that can specify its width(alias template) |
(C++26)
|
data-parallel type with the element type bool (class template) |
(C++26)
|
convenience alias template for basic_simd_mask that can specify its width(alias template) |
Load and store flags
(C++26)
|
load and store flags for data-parallel types (class template) |
(C++26)
|
default flag used on load and store operations (constant) |
(C++26)
|
flag enabling conversions that are not value-preserving on load and store operations (constant) |
(C++26)
|
flag indicating alignment of the load-store address to some specified storage to the value of simd_alignment (constant) |
(C++26)
|
flag indicating alignment of the load-store address to some specified storage to the specified alignment (variable template) |
Load and store operations
loads elements from a contiguous range to basic_simd (function template) |
|
stores elements from basic_simd to a contiguous range (function template) |
Casts
(C++26)
|
splits single data-parallel object to multiple ones (function template) |
(C++26)
|
concatenates multiple data-parallel objects into a single one (function template) |
Algorithms
(C++26)
|
element-wise min/max operations for basic_simd (function template) |
(C++26)
|
element-wise clamp operation for basic_simd (function template) |
(C++26)
|
element-wise selection using conditional operator (function template) |
Reductions
(C++26)
|
reduces all values in basic_simd over a specified binary operation to a single value (function template) |
(C++26)
|
reductions of basic_simd_mask to bool (function template) |
(C++26)
|
reduction of basic_simd_mask to number of true values (function template) |
(C++26)
|
reductions of basic_simd_mask to the index of first or last true value (function template) |
Traits
(C++26)
|
obtains an appropriate alignment for simd_flag_aligned (class template) |
(C++26)
|
changes element type of the data-parallel type (class template) |
(C++26)
|
changes the width of the data-parallel type (class template) |
Math functions
All functions in <cmath> are overloaded for basic_simd
.
This section is incomplete Reason: description |
Implementation details
ABI tags
The data-parallel types basic_simd
and basic_simd_mask
are associated with ABI tags
The ABI tag remains independent of machine instruction set selection. The chosen machine instruction set limits the usable ABI tag types. The ABI tags enable users to safely pass objects of data-parallel type across translation unit boundaries.
This section is incomplete |
Exposition-only entities
using /*simd-size-type*/ = /* see description */;
|
(1) | (exposition only*) |
template
<
std::size_t Bytes >
using /*integer-from*/ = /* see description */ ; |
(2) | (exposition only*) |
template
<
class T, class Abi >
constexpr /*simd-size-type*/ /*simd-size-v*/ = /* see description */ ; |
(3) | (exposition only*) |
template
<
class T >
constexpr std::size_t /*mask-element-size*/ = /* see description */ ; |
(4) | (exposition only*) |
template
<
class T >
concept /*constexpr-wrapper-like*/ = /* see description */ ; |
(5) | (exposition only*) |
template
<
class T >
using /*deduced-simd-t*/ = /* see description */ ; |
(6) | (exposition only*) |
template
<
class V, class T >
using /*make-compatible-simd-t*/ = /* see description */ ; |
(7) | (exposition only*) |
T
such that sizeof(T) equals Bytes
basic_simd<T, Abi>
, or 0
T
denotes std::basic_simd_mask<Bytes, Abi>, /*mask-element-size*/<T> equals Bytes
template< class T > concept /*constexpr-wrapper-like*/ = std::convertible_to<T, decltype(T::value)> && std::equality_comparable_with<T, decltype(T::value)> && std::bool_constant<T() == T::value>::value && std::bool_constant<static_cast<decltype(T::value)>(T()) == T::value>::value;
-
decltype(x + x), if the type of x + x is an enabled specialization of
basic_simd
- void.
- /*deduced-simd-t*/<T>, if that type is not void
- std:: simd <decltype(x + x), V::size( ) >
Math functions requirements |
||
template
<
class V >
concept /*simd-floating-point*/ = /* see description */ ; |
(8) | (exposition only*) |
template
<
class... Ts
>
concept /*math-floating-point*/ = /* see description */ ; |
(9) | (exposition only*) |
template
<
class... Ts
>
requires /*math-floating-point*/<Ts...> |
(10) | (exposition only*) |
template
<
class BinaryOp, class T >
concept /*reduction-binary-operation*/ = /* see description */ ; |
(11) | (exposition only*) |
template< class V > concept /*simd-floating-point*/ = std::same_as<V, std::basic_simd<typename V::value_type, typename V::abi_type>> && std::is_default_constructible_v<V> && std::floating_point<typename V::value_type>;
template< class... Ts > concept /*math-floating-point*/ = (/*simd-floating-point*/</*deduced-simd-t*/<Ts>> || ...);
T0
denote Ts...[0], T1
denote Ts...[1], and TRest
denote a pack such that T0, T1, TRest... is equivalent to Ts.... Then, /*math-common-simd-t*/<Ts...> is an alias equivalent to:
- /*deduced-simd-t*/<T0>, if sizeof...(Ts) == 1 is true
- otherwise, std::common_type_t < /*deduced-simd-t*/ <T0>, /*deduced-simd-t*/ <T1>> , if sizeof...(Ts) == 2 is true and /*math-floating-point*/ <T0> && /*math-floating-point*/ <T1> is true
- otherwise, std::common_type_t < /*deduced-simd-t*/ <T0>, T1> if sizeof...(Ts) == 2 is true and /*math-floating-point*/<T0> is true
- otherwise, std::common_type_t <T0, /*deduced-simd-t*/ <T1>> if sizeof...(Ts) == 2 is true
- otherwise, std::common_type_t < /*math-common-simd-t*/ <T0, T1>, TRest...> , if /*math-common-simd-t*/<T0, T1>
- otherwise, std::common_type_t < /*math-common-simd-t*/ <TRest...>, T0, T1>
template< class BinaryOp, class T > concept /*reduction-binary-operation*/ = requires (const BinaryOp binary_op, const std::simd<T, 1> v) { { binary_op(v, v) } -> std::same_as<std::simd<T, 1>>; };
/*reduction-binary-operation*/<BinaryOp, T> is modeled only if:
-
BinaryOp
is a binary element-wise operation that is commutative, and- An object of type
BinaryOp
is invocable with two arguments of type std::basic_simd<T, Abi> for unspecified ABI tagAbi
that returns a std::basic_simd<T, Abi>
SIMD ABI tags |
||
template
<
class T >
using /*native-abi*/ = /* see description */ ; |
(12) | (exposition only*) |
template
<
class T, /*simd-size-type*/ N >
using /*deduce-abi-t*/ = /* see description */ ; |
(13) | (exposition only*) |
- /*simd-size-v*/<T, /*deduce-abi-t*/<T, N>> equals N
- std:: basic_simd <T, /*deduce-abi-t*/ <T, N>>
- std:: basic_simd_mask <sizeof(T), /*deduce-abi-t*/ < /*integer-from*/ <sizeof(T) >, N>>
T
is a vectorizable type, and N > 0 && N <= M is true, where M is an implementation-defined maximum that is at least 64 and can differ depending on T
Load and store flags |
||
struct /*convert-flag*/; |
(14) | (exposition only*) |
struct /*aligned-flag*/; |
(15) | (exposition only*) |
template
<
std::size_t N >
struct /*overaligned-flag*/ ; |
(16) | (exposition only*) |
Notes
Feature-test macro | Value | Std | Feature |
---|---|---|---|
__cpp_lib_simd |
202411L |
(C++26) | Data-parallel types and operations |
Example
#include <iostream> #include <simd> #include <string_view> void println(std::string_view name, auto const& a) { std::cout << name << ": "; for (std::size_t i{}; i != a.size(); ++i) std::cout << a[i] << ' '; std::cout << '\n'; } template<class A> constexpr std::basic_simd<int, A> my_abs(std::basic_simd<int, A> x) { return std::simd_select(x < 0, -x, x); } int main() { constexpr std::simd<int> a = 1; println("a", a); constexpr std::simd<int> b([](int i) { return i - 2; }); println("b", b); constexpr auto c = a + b; println("c", c); constexpr auto d = my_abs(c); println("d", d); constexpr auto e = d * d; println("e", e); constexpr auto inner_product = std::reduce(e); std::cout << "inner product: " << inner_product << '\n'; constexpr std::simd<double, 16> x([](int i) { return i; }); println("x", x); // overloaded math functions are defined in <simd> println("cos²(x) + sin²(x)", std::pow(std::cos(x), 2) + std::pow(std::sin(x), 2)); }
Output:
a: 1 1 1 1 b: -2 -1 0 1 c: -1 0 1 2 d: 1 0 1 2 e: 1 0 1 4 inner product: 6 x: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 cos²(x) + sin²(x): 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
See also
numeric arrays, array masks and array slices (class template) |
External links
1. | The implementation of ISO/IEC TS 19570:2018 Section 9 "Data-Parallel Types" — github.com |
2. | TS implementation reach for GCC/libstdc++ (std::experimental::simd
|