明确的向量化

Explicit vectorization

本文关键字:向量化      更新时间:2023-10-16

据我所知,如果设置相应的编译器标志,大多数现代编译器会在适当的地方自动使用SIMD循环指令。因为编译器只能使用向量化,如果它可以确定这样做不会改变程序的语义,它不会使用向量化的情况下,我实际上知道它是安全的,但编译器出于各种原因认为它不是。

是否有明确的向量化指令,我可以在没有库的普通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]);
}

普通c++ ?不。std::valarray可以引导你的编译器到SIMD水,但不能让它喝水。

OpenMP是最小的"库"库:与其说它是一个库,不如说是一个语言扩展,所有主要的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];
}

为了完成最后一英里的低精度操作,多通道聚合,无分支屏蔽等,确实需要显式连接到底层指令集,这是不可能的任何接近"普通c++"。不过,OpenMP可以让你走得更远。

TL;DR不能保证,但是KISS和您可能会得到高度优化的代码。在修改生成的代码之前,对其进行测量和检查。

你可以在在线编译器上使用它,例如gcc。godbolt将用-O3

向量化gcc 5.2中对std::transform的直接调用
#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;
    });    
}

本周早些时候有一个类似的问题。总的主题似乎是,在现代处理器和编译器上,代码越直接(普通算法调用),就越有可能得到高度优化(矢量化、展开)的代码。