据我所知,如果我设置相应的编译器标志,大多数现代编译器会在适当的情况下自动使用SIMD指令进行循环。由于编译器只能使用向量化,如果它可以确保这样做不会改变程序的语义,它就不会在我真正知道它是安全的情况下使用向量化,但编译器出于各种原因认为它不是。 / p>
我是否可以在没有库的普通C ++中使用显式向量化指令,这让我自己处理矢量化数据而不是依赖于编译器?我想它看起来像这样:
double* dest;
const double* src1, src2;
// ...
for (uint32 i = 0; i < n; i += vectorization_size / sizeof(double))
{
vectorized_add(&dest[i], &src1[i], &src2[i]);
}
答案 0 :(得分:2)
纯C ++?不,std::valarray
可以让你的编译器进入SIMD水,但它不能让它饮用。
OpenMP是最少的&#34;库&#34;库那里:它更像是一个语言扩展而不是一个库,所有主要的C ++编译器都支持它。虽然主要和历史上用于多核并行,但OpenMP 4.0引入了SIMD特定的构造,它至少可以敦促你的编译器向某些可清晰矢量化的程序进行矢量化,甚至是具有明显标量子程序的程序。它还可以帮助您识别阻止编译器进行矢量化的代码方面。 (除此之外......你还不想多核并行吗?)
double* dest;
const double* src1, src2;
#pragma omp simd
for (int i = 0; i < n; i++)
{
dest[i] = src1[i] + src2[i];
}
使用精度降低的操作进行最后一英里,多通道聚合,无分支掩蔽等确实需要与底层指令集明确连接,并且对于接近&#34;的任何内容都是不可能的。普通的C ++&#34;。不过,OpenMP可以让你走得很远。
答案 1 :(得分:0)
TL; DR 无保证,但KISS和您可能会获得高度优化的代码。在修补之前测量并检查生成的代码。
你可以在在线编译器上玩这个,例如gcc.godbolt will vectorize以下直接调用std::transform
gcc 5.2 with -O3
#include <algorithm>
const int sz = 1024;
void f(double* src1, double* src2, double* dest)
{
std::transform(src1 + 0, src1 + sz, src2, dest,
[](double lhs, double rhs){
return lhs + rhs;
});
}
本周早些时候有一个similar Q&A。一般主题似乎是在现代处理器和编译器上,代码越简单(普通算法调用),您就越有可能获得高度优化(矢量化,展开)代码。