数据并行类型 (SIMD) (自 C++26)
该库提供了数据并行类型以及对这些类型的操作:可移植类型,用于显式声明数据并行性,并通过数据并行执行资源(如 SIMD 寄存器和指令或由通用指令解码器驱动的执行单元)来构建数据。
所有标准整数类型、字符类型和大多数浮点类型都是可向量化类型。可向量化浮点类型包括 float、 double 和选定的扩展浮点类型 std::float16_t、 std::float32_t 和 std::float64_t (如果已定义)。
数据并行类型由一个或多个底层可向量化类型的元素组成,称为元素类型。元素的数量,称为宽度,对于每个数据并行类型都是恒定的。
数据并行类型指的是类模板 basic_simd
和 basic_simd_mask
的所有已启用的特化。
数据并行类型的数据并行对象的行为类似于 T
类型的对象。但是,当 T
存储和操作单个值时,元素类型为 T
的数据并行类型存储和操作多个值。
对数据并行对象的每个操作都按元素执行(水平操作除外,例如归约,这些操作已明确标记),应用于对象的每个元素或两个对象的对应元素。每个这样的应用相对于其他应用都是无序的。这个简单的规则表达了数据并行性,编译器将使用它来生成 SIMD 指令和/或独立的执行流。
数据并行对象上的所有操作(非 constexpr 数学函数重载除外)都是 constexpr 的:可以在常量表达式的求值中创建和使用数据并行对象。
定义了别名模板 simd
和 simd_mask
,以允许用户将宽度指定为特定大小。默认宽度由实现方式在编译时确定。
本节不完整 原因
|
定义于头文件
<simd> |
目录 |
[编辑] 主要类
(C++26) |
数据并行向量类型 (类模板) |
(C++26) |
可以指定其宽度的 basic_simd 的便捷别名模板(别名模板) |
(C++26) |
元素类型为 bool 的数据并行类型 (类模板) |
(C++26) |
可以指定其宽度的 basic_simd_mask 的便捷别名模板(别名模板) |
[编辑] 加载和存储标志
(C++26) |
数据并行类型的加载和存储标志 (类模板) |
(C++26) |
加载和存储操作上使用的默认标志 (常量) |
(C++26) |
在加载和存储操作上启用非保值转换的标志 (常量) |
(C++26) |
指示加载-存储地址与 simd_alignment 值指定的存储对齐的标志(常量) |
(C++26) |
指示加载-存储地址与指定对齐方式指定的存储对齐的标志 (变量模板) |
[编辑] 加载和存储操作
从连续范围加载元素到 basic_simd (函数模板) | |
将 basic_simd 中的元素存储到连续范围(函数模板) |
[编辑] 转换
(C++26) |
将单个数据并行对象拆分为多个对象 (函数模板) |
(C++26) |
将多个数据并行对象连接成一个对象 (函数模板) |
[编辑] 算法
(C++26) |
basic_simd 的逐元素最小值/最大值运算(函数模板) |
(C++26) |
basic_simd 的逐元素 clamp 运算(函数模板) |
(C++26) |
使用条件运算符的逐元素选择 (函数模板) |
[编辑] 归约
(C++26) |
将 basic_simd 中的所有值通过指定的二元运算归约为单个值(函数模板) |
(C++26) |
basic_simd_mask 归约为 bool(函数模板) |
(C++26) |
basic_simd_mask 归约为 true 值的数量(函数模板) |
basic_simd_mask 归约为第一个或最后一个 true 值的索引(函数模板) |
[编辑] 特性
(C++26) |
为 simd_flag_aligned 获取适当的对齐方式(类模板) |
(C++26) |
更改数据并行类型的元素类型 (类模板) |
(C++26) |
更改数据并行类型的宽度 (类模板) |
[编辑] 数学函数
<cmath> 中的所有函数都为 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::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::simd<decltype(x + x), V::size()>.
数学函数要求 |
||
template< class V > concept /*simd-floating-point*/ = /* 参见描述 */; |
(8) | (仅供展示*) |
template< class... Ts > concept /*math-floating-point*/ = /* 参见描述 */; |
(9) | (仅供展示*) |
template< class... Ts > requires /*math-floating-point*/<Ts...> |
(10) | (仅供展示*) |
template< class BinaryOp, class T > concept /*reduction-binary-operation*/ = /* 参见描述 */; |
(11) | (仅供展示*) |
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
表示 Ts...[0],T1
表示 Ts...[1],TRest
表示一个包,使得 T0, T1, TRest... 等效于 Ts...。然后,/*math-common-simd-t*/<Ts...> 是等效于以下的别名- /*deduced-simd-t*/<T0>,如果 sizeof...(Ts) == 1 为 true
- 否则,std::common_type_t</*deduced-simd-t*/<T0>, /*deduced-simd-t*/<T1>>,如果 sizeof...(Ts) == 2 为 true 且 /*math-floating-point*/<T0> && /*math-floating-point*/<T1> 为 true,
- 否则,std::common_type_t</*deduced-simd-t*/<T0>, T1> 如果 sizeof...(Ts) == 2 为 true 且 /*math-floating-point*/<T0> 为 true,
- 否则,std::common_type_t<T0, /*deduced-simd-t*/<T1>> 如果 sizeof...(Ts) == 2 为 true,
- 否则,std::common_type_t</*math-common-simd-t*/<T0, T1>, TRest...>,如果 /*math-common-simd-t*/<T0, T1> 是有效类型,
- 否则,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> 仅在以下情况下建模:
-
BinaryOp
是可交换的二元逐元素操作,并且 - 类型为
BinaryOp
的对象可以使用类型为 std::basic_simd<T, Abi> 的两个参数(对于未指定的 ABI 标签Abi
)调用,并返回 std::basic_simd<T, Abi>。
-
SIMD ABI 标签 |
||
template< class T > using /*native-abi*/ = /* 参见描述 */; |
(12) | (仅供展示*) |
template< class T, /*simd-size-type*/ N > using /*deduce-abi-t*/ = /* 参见描述 */; |
(13) | (仅供展示*) |
- /*simd-size-v*/<T, /*deduce-abi-t*/<T, N>> 等于 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
是可向量化类型,并且 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) | (仅供展示*) |
[编辑] 注释
特性测试 宏 | 值 | Std | 特性 |
---|---|---|---|
__cpp_lib_simd |
202411L |
(C++26) | 数据并行类型和操作 |
[编辑] 示例
#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)); }
输出
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 |