编译器通常会在没有明确告知的情况下发出向量(SIMD)指令吗?

Ber*_*ard 5 parallel-processing simd vectorization auto-vectorization c++17

C++ 17为标准库添加了并行扩展(例如std::sort(std::execution::par_unseq, arr, arr + 1000),允许使用多个线程和向量指令进行排序).

我注意到微软的实验性实现提到VC++编译器缺乏对这里做矢量化的支持,这让我感到惊讶 - 我认为现代C++编译器能够推断出循环的可矢量化,但显然VC++编译器/优化器无法生成SIMD代码即使明确告知这样做.看似缺乏自动矢量化支持与2011年关于Quora的问题的答案相矛盾,这表明编译器将在可能的情况下进行矢量化.

也许,编译器只会对非常明显的情况进行矢量化,例如a std::array<int, 4>,而且只不过是这样,因此C++ 17的显式并行化会很有用.

因此我的问题是:当没有明确告知这样做时,当前的编译器会自动向量化我的代码吗?(为了使这个问题更具体,让我们将其缩小到支持SIMD的Intel x86 CPU,以及最新版本的GCC,Clang,MSVC和ICC.)

作为扩展:其他语言的编译器是否可以做更好的自动矢量化(可能是由于语言设计)(因此C++标准委员会认为它对于显式(C++ 17风格)矢量化是必要的)?

Tim*_*Tim 7

用于自动发现SIMD样式矢量化的最佳编译器(当被告知它可以生成适当指令集的操作码当然)是英特尔编译器的经验(如果需要,它可以生成代码根据实际CPU进行动态调度),其次是GCC和Clang,MSVC最后(你的四个).

我意识到这一点也许并不令人惊讶 - 英特尔在帮助开发人员利用他们为其产品添加的最新功能方面确实有一定的兴趣.

我正在与英特尔密切合作,虽然他们热衷于演示他们的编译器如何发现自动矢量化,但他们也非常正确地指出使用他们的编译器还允许你使用pragma simd结构来进一步显示编译器的假设,可以或者无法制作(从纯粹的语法层面不清楚),因此允许编译器进一步矢量化代码而无需借助内在函数.

我认为,这个问题指出了编译器(对于C++或其他语言)将完成所有向量化工作...如果你有简单的向量处理循环(例如,通过标量乘以向量中的所有元素)然后是的,你可以预期4个编译器中的3个会发现它.

但是对于更复杂的代码,可以产生的矢量化增益不是来自简单的循环展开和组合迭代,而是来自实际使用不同的或经过调整的算法,并且即使不是不可能,编译器也可以完全单独完成.然而,如果您了解矢量化如何应用于算法,并且您可以构建代码以允许编译器查看机会,也许使用pragma simd构造或OpenMP,那么您可以获得所需的结果.

当代码对底层CPU和内存总线有一定的机械同情时,就会出现矢量化 - 如果你有,那么我认为英特尔编译器将是你最好的选择.没有它,改变编译器可能没什么区别.

我可以推荐Matt Godbolt的编译器资源管理器来实际测试这个 - 把你的c ++代码放在那里,看看不同的编译器实际生成了什么?非常方便......它不包括旧版本的MSVC(我认为它目前支持VC++ 2017及更高版本),但会向您展示ICC,GCC,Clang和其他版本的不同版本的代码...

  • Godbolt的编译器资源管理器*包括MSVC.它从一开始就没有,但它现在确实存在,并且持续了几个月. (3认同)