问题描述
这似乎不起作用/编译
void vec(size_t n) {
typedef char v4si __attribute__((vector_size(n)));
v4si t={1};
}
解决方法
不,那没有意义。这就像在运行时根据某个变量的值尝试选择 uint32_t 与 uint64_t。
手动矢量化不会通过将整个数组视为一个巨大的 SIMD 向量来工作,它通过告诉编译器确切地如何使用固定大小的短向量来工作。如果自动矢量化不适用于普通数组,这也无济于事。
如果您不想手动执行循环,要让 GCC“更努力地”自动矢量化循环,#pragma omp SIMD
和 gcc -fopenmp
可以在 {{1} 处自动矢量化}.或者使用 -O2
进行编译会将每个循环视为自动矢量化的候选对象。 (也是关于单个结构的内容;clang 通常比 gcc 更擅长在非循环代码中查找 SIMD 用例。clang 有时可能过于激进,花更多的时间将数据混洗在一起,而不是单独进行标量工作.)
但请注意 GCC 和 clang 的自动向量化只有在第一次迭代之前可以计算循环行程计数时才能工作。它可以是运行时变量计数,但根据数据随时触发的 -O3
退出条件将使它们失效。所以例如他们无法自动矢量化使用 if()break;
的幼稚循环 strlen
或 strchr
实现。 ICC可以做到这一点。
此外,如果您需要任何类型的改组,您通常需要使用 GNU C 本机向量或特定于目标的内在函数(如 x86 的 SSE/AVX、ARM 的 NEON/AdvSIMD、Power 的 AltiVec 等)自己完成.
Cray 机器显然具有 SIMD,它通过给硬件一个指针 + 长度并让它在它想要的任何块中“循环”(也许就像现代 x86 while(*p++ != 0){...}
实际上可以在其微代码中使用更大的块一样)来工作。但是现代 CPU 具有固定宽度的短向量 SIMD 指令,例如可以执行 16 或 32 个字节。
(ARM SVE 介于两者之间,允许代码向前兼容,以便在未来的硬件上利用更宽的向量,而不是在向量宽度中完全烘焙。不过,它仍然是您无法控制的固定大小。你仍然需要循环使用它,并通过硬件的向量宽度增加你的指针.它有屏蔽的东西来忽略超过你想要处理的内容的末尾的元素,这样你就可以将它用于任意短的数组,我认为,以及数组的剩余部分。但是对于任意长的数组,您仍然需要循环。此外,很少有 CPU 支持 SVE。顺便说一句,SVE 是与 Agner Fog's ForwardCom 蓝天纸架构中的 SIMD 类似的概念,它也旨在让代码利用未来更广泛的硬件,而无需重新编译或重新进行手动矢量化。)
当针对具有固定宽度 SIMD 向量的机器(例如 16 或 32 的选择)时,您希望从 运行时 可变大小的“向量”获得什么样的 asm 代码生成字节,将选择作为指令编码的一部分?