Data-parallel types (SIMD) (since C++26)
该库提供数据并行类型及对这些类型的操作:通过可移植类型显式声明数据并行性,并在可用时通过数据并行执行资源(例如 SIMD 寄存器和指令,或由通用指令解码器驱动的执行单元)来构建数据结构。
可向量化类型的集合包括:
- 所有标准整数和字符类型;
- 大多数浮点类型,包括 float 、 double 以及选定的扩展浮点类型: std:: float16_t 、 std:: float32_t 和 std:: float64_t (若已定义);以及
-
std::
complex
<
T
>
,其中
T是可向量化的浮点类型。
一个 数据并行类型 由基础可向量化类型(称为 元素类型 )的一个或多个元素组成。元素数量(称为 宽度 )对于每个数据并行类型都是恒定的。
数据并行类型指代所有已启用的类模板
basic_simd
与
basic_simd_mask
的特化形式。
一个数据并行类型的
数据并行对象
的行为类似于类型
T
的对象。但
T
存储和操作单个值,而具有元素类型
T
的数据并行类型则存储和操作多个值。
对数据并行对象的每个操作都采用 逐元素 方式执行(水平操作除外,例如归约操作会明确标注),这些操作会作用于对象的每个元素或两个对象的对应元素。每个此类应用相对于其他应用都是非顺序执行的。这一简单规则体现了数据并行性,编译器将利用该规则生成SIMD指令和/或独立执行流。
所有对数据并行对象的操作(除非常量表达式数学函数重载外)都是 constexpr :可以在常量表达式求值过程中创建和使用数据并行对象。
别名模板
simd
和
simd_mask
的定义允许用户指定特定大小的宽度。默认宽度由实现在编译时确定。
|
定义于头文件
<simd>
|
|
|
定义于命名空间
std::datapar
|
目录 |
主要类
|
(C++26)
|
数据并行向量类型
(类模板) |
|
(C++26)
|
可指定宽度的
basic_simd
便捷别名模板
(别名模板) |
|
(C++26)
|
元素类型为
bool
的数据并行类型
(类模板) |
|
(C++26)
|
可指定宽度的
basic_simd_mask
便捷别名模板
(别名模板) |
加载和存储标志
|
(C++26)
|
数据并行类型的加载和存储标志
(类模板) |
|
(C++26)
|
加载和存储操作使用的默认标志
(常量) |
|
(C++26)
|
在加载和存储操作中启用非值保留转换的标志
(常量) |
|
(C++26)
|
指示加载-存储地址与某些指定存储对齐到
datapar::alignment
值的标志
(常量) |
|
(C++26)
|
指示加载-存储地址与某些指定存储对齐到指定对齐值的标志
(变量模板) |
加载和存储操作
从连续范围加载元素到
basic_simd
(函数模板) |
|
将元素从
basic_simd
存储到连续范围
(函数模板) |
类型转换
|
(C++26)
|
将单个数据并行对象拆分为多个对象
(函数模板) |
|
(C++26)
|
将多个数据并行对象连接为单个对象
(函数模板) |
算法
basic_simd
的逐元素最小/最大操作
(函数模板) |
|
|
(C++26)
|
basic_simd
的逐元素钳制操作
(函数模板) |
|
(C++26)
|
使用条件运算符的逐元素选择
(函数模板) |
归约操作
将
basic_simd
中的所有值通过指定的二元操作归约为单个值
(函数模板) |
|
将
basic_simd_mask
归约为
bool
值
(函数模板) |
|
|
(C++26)
|
将
basic_simd_mask
归约为
true
值的数量
(函数模板) |
将
basic_simd_mask
归约为首个或最后一个
true
值的索引
(函数模板) |
特性
|
(C++26)
|
获取适用于
datapar::flag_aligned
的对齐方式
(类模板) |
|
(C++26)
|
更改数据并行类型的元素类型
(类模板) |
|
(C++26)
|
更改数据并行类型的宽度
(类模板) |
数学函数
<cmath>
和
<complex>
中的所有函数均已针对
basic_simd
进行了重载。
|
本节内容尚不完整
原因:描述缺失 |
位操作函数
<bit>
头文件中的所有位操作函数均针对
basic_simd
进行了重载。
|
本节内容尚不完整
原因:描述缺失 |
实现细节
ABI标签
数据并行类型
basic_simd
和
basic_simd_mask
与
ABI 标签
相关联。这些标签是用于指定数据并行对象大小和二进制表示形式的类型。该设计旨在使大小和二进制表示形式根据目标架构和编译器标志而变化。ABI 标签与元素类型共同决定了宽度。
ABI标签保持与机器指令集选择无关。所选机器指令集会限制可用的ABI标签类型。ABI标签使用户能够安全地在翻译单元边界传递数据并行类型的对象。
| 本节内容尚不完整 |
仅用于说明的实体
|
本节内容不完整
原因:需要更新 |
|
using
/*simd-size-type*/
=
/* 见描述 */
;
|
(1) | ( 仅用于说明* ) |
|
template
<
std::
size_t
Bytes
>
using /*integer-from*/ = /* 见描述 */ ; |
(2) | ( 仅用于说明* ) |
|
template
<
class
T,
class
Abi
>
constexpr /*simd-size-type*/ /*simd-size-v*/ = /* 见描述 */ ; |
(3) | ( 仅用于说明* ) |
|
template
<
class
T
>
constexpr std:: size_t /*mask-element-size*/ = /* 见描述 */ ; |
(4) | ( 仅用于说明* ) |
|
template
<
class
T
>
concept /*constexpr-wrapper-like*/ = /* 见描述 */ ; |
(5) | ( 仅用于说明* ) |
|
template
<
class
T
>
using /*deduced-simd-t*/ = /* 见描述 */ ; |
(6) | ( 仅用于说明* ) |
|
template
<
class
V,
class
T
>
using /*make-compatible-simd-t*/ = /* 见描述 */ ; |
(7) | ( 仅用于说明* ) |
T
的别名,其满足
sizeof
(
T
)
等于
Bytes
。
basic_simd<T, Abi>
的宽度,否则为
0
。
T
表示
std
::
datapar
::
basic_simd_mask
<
Bytes, Abi
>
,则
/*mask-element-size*/
<
T
>
等于
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
)
,若
x
+
x
的类型是
basic_simd的已启用特化;否则 - void 。
- /*deduced-simd-t*/ < T > (若该类型非 void ),否则
- std :: datapar :: simd < decltype ( x + x ) , V :: size ( ) > 。
|
数学函数要求
|
||
|
template
<
class
V
>
concept /*simd-floating-point*/ = /* see description */ ; |
(8) | ( 仅用于说明* ) |
|
template
<
class
...
Ts
>
concept /*math-floating-point*/ = /* see description */ ; |
(9) | ( 仅用于说明* ) |
|
template
<
class
...
Ts
>
requires
/*math-floating-point*/
<
Ts...
>
|
(10) | ( 仅用于说明* ) |
|
template
<
class
BinaryOp,
class
T
>
concept /*reduction-binary-operation*/ = /* see description */ ; |
(11) | ( 仅用于说明* ) |
template< class V > concept /*simd-floating-point*/ = std::same_as<V, std::datapar::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
表示
Ts...
[
0
]
,
T1
表示
Ts...
[
1
]
,
TRest
表示满足
T0, T1, TRest...
等价于
Ts...
的包。则
/*math-common-simd-t*/
<
Ts...
>
是等价于以下类型的别名:
- 当 sizeof... ( Ts ) == 1 为 true 时,对应 /*deduced-simd-t*/ < T0 >
- 否则,当 sizeof... ( Ts ) == 2 为 true 且 /*math-floating-point*/ < T0 > && /*math-floating-point*/ < T1 > 为 true 时,对应 std:: common_type_t < /*deduced-simd-t*/ < T0 > , /*deduced-simd-t*/ < T1 >>
- 否则,当 sizeof... ( Ts ) == 2 为 true 且 /*math-floating-point*/ < T0 > 为 true 时,对应 std:: common_type_t < /*deduced-simd-t*/ < T0 > , T1 >
- 否则,当 sizeof... ( Ts ) == 2 为 true 时,对应 std:: common_type_t < T0, /*deduced-simd-t*/ < T1 >>
- 否则,当 /*math-common-simd-t*/ < T0, T1 > 是有效类型时,对应 std:: common_type_t < /*math-common-simd-t*/ < T0, T1 > , TRest... >
- 否则,对应 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::datapar::simd<T, 1> v) { { binary_op(v, v) } -> std::same_as<std::datapar::simd<T, 1>>; };
/*reduction-binary-operation*/ < BinaryOp, T > 仅在满足以下条件时被建模:
-
-
BinaryOp是一个满足交换律的二元逐元素操作,且 -
BinaryOp类型的对象可被调用,其参数为两个 std :: datapar :: basic_simd < T, Abi > 类型(其中Abi为未指定的 ABI 标签),并返回 std :: datapar :: basic_simd < T, Abi > 类型。
-
|
SIMD ABI 标签
|
||
|
template
<
class
T
>
using /*native-abi*/ = /* see description */ ; |
(12) | ( 仅用于说明* ) |
|
template
<
class
T,
/*simd-size-type*/
N
>
using /*deduce-abi-t*/ = /* see description */ ; |
(13) | ( 仅用于说明* ) |
- /*simd-size-v*/ < T, /*deduce-abi-t*/ < T, N >> 等于 N ,
- std :: datapar :: basic_simd < T, /*deduce-abi-t*/ < T, N >> 是一个已启用的特化,且
- std :: datapar :: basic_simd_mask < sizeof ( T ) , /*deduce-abi-t*/ < /*integer-from*/ < sizeof ( T ) > , N >> 是一个已启用的特化。
T
是可向量化类型且
N
>
0
&&
N
<=
M
为
true
时被定义,其中
M
是实现定义的最大值,该值至少为
64
且可能因
T
而异。
|
加载与存储标志
|
||
|
struct
/*convert-flag*/
;
|
(14) | ( 仅用于说明* ) |
|
struct
/*aligned-flag*/
;
|
(15) | ( 仅用于说明* ) |
|
template
<
std::
size_t
N
>
struct /*overaligned-flag*/ ; |
(16) | ( 仅用于说明* ) |
注释
| 功能测试 宏 | 值 | 标准 | 功能特性 |
|---|---|---|---|
__cpp_lib_simd
|
202411L
|
(C++26) | 数据并行类型与操作 |
__cpp_lib_simd_complex
|
202502L
|
(C++26) |
在
std::datapar::simd
中支持交错存储的复数值
|
示例
#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::datapar::basic_simd<int, A> my_abs(std::datapar::basic_simd<int, A> x) { return std::datapar::select(x < 0, -x, x); } int main() { constexpr std::datapar::simd<int> a = 1; println("a", a); constexpr std::datapar::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::datapar::reduce(e); std::cout << "inner product: " << inner_product << '\n'; constexpr std::datapar::simd<double, 16> x([](int i) { return i; }); println("x", x); // 重载的数学函数定义在 <simd> 中 println("cos²(x) + sin²(x)", std::pow(std::cos(x), 2) + std::pow(std::sin(x), 2)); }
输出:
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
另请参阅
|
数值数组、数组掩码和数组切片
(类模板) |
外部链接
| 1. | ISO/IEC TS 19570:2018 第9节“数据并行类型”的实现 — github.com |
| 2. |
TS实现已进入
GCC/libstdc++
(
std::experimental::simd
已随GCC-11发布) — gcc.gnu.org
|