5

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

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

也许,编译器只会向量化非常明显的情况,例如std::array<int, 4>,仅此而已,因此 C++17 的显式并行化将很有用。

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

作为扩展:其他语言的编译器是否可以更好地进行自动矢量化(可能是由于语言设计)(以便 C++ 标准委员会决定显式(C++ 17 风格)矢量化是必要的)?

4

1 回答 1

10

根据我的经验,自动识别 SIMD 风格矢量化的最佳编译器(当被告知它可以为适当的指令集生成操作码时)是英特尔编译器(如果需要,它可以生成代码以根据实际 CPU 进行动态调度),密切相关其次是 GCC 和 Clang,最后是 MSVC(在你的四个中)。

我意识到这可能并不令人惊讶——英特尔确实有既得利益,可以帮助开发人员利用他们添加到产品中的最新功能。

我正在与英特尔密切合作,虽然他们热衷于展示他们的编译器如何发现自动矢量化,但他们也非常正确地指出,使用他们的编译器还允许您使用 pragma simd 构造来进一步展示编译器假设可以或无法制作(从纯粹的句法层面上不清楚),因此允许编译器在不诉诸内在函数的情况下进一步矢量化代码。

我认为,这指出了希望编译器(对于 C++ 或其他语言)能够完成所有矢量化工作的问题......如果你有简单的矢量处理循环(例如,将矢量中的所有元素乘以标量)那么是的,您可以预期 4 个编译器中有 3 个会发现这一点。

但是对于更复杂的代码,可能获得的矢量化收益不是来自简单的循环展开和组合迭代,而是来自实际使用不同或调整过的算法,如果编译器完全单独完成的话,这将很难。然而,如果您了解如何将矢量化应用于算法,并且您可以构建代码以允许编译器看到这样做的机会,也许使用 pragma simd 构造或 OpenMP,那么您可能会得到您想要的结果。

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

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

于 2017-06-04T10:10:12.313 回答