SIMD 库

来自cppreference.com


 
 
实验性
技术规范
文件系统库 (文件系统 TS)
库基础 (库基础 TS)
库基础 2 (库基础 TS v2)
库基础 3 (库基础 TS v3)
并行扩展 (并行 TS)
并行扩展 2 (并行 TS v2)
并发扩展 (并发 TS)
并发扩展 2 (并发 TS v2)
概念 (概念 TS)
范围 (范围 TS)
反射 (反射 TS)
数学特殊函数 (特殊函数 TR)
实验性非 TS 功能特性
模式匹配
线性代数
std::execution
契约
2D 图形
 
 
 

SIMD 库为显式表达数据并行操作和让数据并行操作更高效提供了便捷的类型。

一个 simd<T> 类型的对象行为和 T 类型的对象相似。然而 T 储存和操纵一个值,simd<T> 储存和操纵多个值(被称为 宽度 但为了与其它标准库一致,被命名为 size,参见 simd_size)。

每个在 simd<T> 上的运算符和操作 都表现为逐元素操作(除了被明确标注为水平的操作)。这个简单的规则传达了数据并行的语义并会被编译器用来生成数据并行向量指令(SIMD 指令)和 / 或独立的执行流程。

simd<T>native_simd<T> 类型的宽度在编译时由实现决定。相反,fixed_size_simd<T, N> 类型的宽度是由开发者决定的一个特定的固定的值。

要想混用 SIMD 类型,一种推荐的高效的模式是使用 native_simdrebind_simd

#include <experimental/simd>
namespace stdx = std::experimental;
 
using floatv  = stdx::native_simd<float>;
using doublev = stdx::rebind_simd_t<double, floatv>;
using intv    = stdx::rebind_simd_t<int, floatv>;

这样可以确保这些类型都有相同的宽度,因而可以相互转换。不同宽度类型的转换是未定义的,因为那样会丢弃或凭空创造一些值。若要改变大小,可以使用 SIMD 库提供的 splitconcat 函数。

在标头 <experimental/simd> 定义

主类

(并行 TS v2)
数据并行向量类型
(类模板)
(并行 TS v2)
元素类型为 bool 的数据并行类型
(类模板)

ABI 标签

在命名空间 std::experimental::simd_abi 定义
(并行 TS v2)
存储单个元素的标签类型
(typedef)
(并行 TS v2)
存储指定数量元素的标签类型
(别名模板)
(并行 TS v2)
确保 ABI 兼容性的标签类型
(别名模板)
(并行 TS v2)
最有效率的标签类型
(别名模板)
(并行 TS v2)
保证支持的固定最大元素数
(常量)
(并行 TS v2)
获得给定的元素类型及元素数的 ABI 类型
(类模板)

对齐标签

指示元素对齐的标签类型
(类)
指示向量类型对齐的标签类型
(类)
指示实参的加载/存储地址按照指定的对齐进行对齐
(类模板)

where_expression

以非修改操作选择的元素
(类模板)
(并行 TS v2)
以修改操作选择的元素
(类模板)
(并行 TS v2)
产生 const_where_expression 和 where_expression
(函数模板)

转型

逐元素 static_cast
(函数模板)
逐元素 ABI 转型
(函数模板)
(并行 TS v2)
分割单个 simd 对象为多个
(函数模板)
(并行 TS v2)
连接多个 simd 对象为单个
(函数模板)

算法

(并行 TS v2)
逐元素 min 操作
(函数模板)
(并行 TS v2)
逐元素 max 操作
(函数模板)
(并行 TS v2)
逐元素 minmax 操作
(函数模板)
(并行 TS v2)
逐元素 clamp 操作
(函数模板)

规约

(并行 TS v2)
规约向量为单个元素
(函数模板)

掩码规约

归约 simd_maskbool
(函数模板)
(并行 TS v2)
归约 simd_masktrue 值的数量
(函数模板)
归约 simd_mask 为其首个或最末 true 值的索引
(函数模板)

特征

(并行 TS v2)
检查类型是否为 simdsimd_mask 类型
(类模板)
(并行 TS v2)
检查类型是否为 ABI 标签类型
(类模板)
(并行 TS v2)
检查类型是否为 simd 标志类型
(类模板)
(并行 TS v2)
获得给定的元素类型及 ABI 的元素数
(类模板)
(并行 TS v2)
获得 vector_aligned 的适当对齐
(类模板)
更改 simdsimd_mask 的元素数或元素类型
(类模板)

数学函数

<cmath> 中除特殊数学函数之外的所有函数,都为 simd 提供了重载。

示例

#include <experimental/simd>
#include <iostream>
#include <string_view>
namespace stdx = std::experimental;
 
void println(std::string_view name, auto const& a)
{
    std::cout << name << ": ";
    for (std::size_t i{}; i != std::size(a); ++i)
        std::cout << a[i] << ' ';
    std::cout << '\n';
}
 
template<class A>
stdx::simd<int, A> my_abs(stdx::simd<int, A> x)
{
    where(x < 0, x) = -x;
    return x;
}
 
int main()
{
    const stdx::native_simd<int> a = 1;
    println("a", a);
 
    const stdx::native_simd<int> b([](int i) { return i - 2; });
    println("b", b);
 
    const auto c = a + b;
    println("c", c);
 
    const auto d = my_abs(c);
    println("d", d);
 
    const auto e = d * d;
    println("e", e);
 
    const auto inner_product = stdx::reduce(e);
    std::cout << "inner product: " << inner_product << '\n';
 
    const stdx::fixed_size_simd<long double, 16> x([](int i) { return i; });
    println("x", x);
    println("cos²(x) + sin²(x)", stdx::pow(stdx::cos(x), 2) + stdx::pow(stdx::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 Section 9 "Data-Parallel Types" 的实现 — github.com
2.  GCC/libstdc++ 的 TS 实现达成(GCC-11 提供 std::experimental::simd) — gcc.gnu.org