编译器通常会在未明确告知时发出向量 (SIMD) 指令吗?
Do compilers usually emit vector (SIMD) instructions when not explicitly told to do so?
C++17 向标准库添加了并行性扩展(例如 std::sort(std::execution::par_unseq, arr, arr + 1000)
,这将允许使用多线程和向量指令完成排序)。
我注意到微软的实验性实现提到 VC++ 编译器不支持在 Quora 上进行矢量化 over here, which surprises me - I thought that modern C++ compilers are able to reason about the vectorizability of loops, but apparently the VC++ compiler/optimizer is unable to generate SIMD code even if explicitly told to do so. The seeming lack of automatic vectorization support contradicts the answers for this 2011 question,这表明编译器将尽可能进行矢量化。
也许,编译器只会矢量化非常明显的情况,例如 std::array<int, 4>
,仅此而已,因此 C++17 的显式并行化会很有用。
因此我的问题是:当前的编译器是否会在未明确告知时自动矢量化我的代码? (为了使这个问题更具体,让我们将问题缩小到支持 SIMD 的 Intel x86 CPU,以及最新版本的 GCC、Clang、MSVC 和 ICC。)
作为扩展:其他语言的编译器是否能更好地自动矢量化(可能是由于语言设计)(因此 C++ 标准委员会决定有必要进行显式(C++17 风格)矢量化)?
根据我的经验,自动发现 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 的不同版本其他人可以使用代码...
C++17 向标准库添加了并行性扩展(例如 std::sort(std::execution::par_unseq, arr, arr + 1000)
,这将允许使用多线程和向量指令完成排序)。
我注意到微软的实验性实现提到 VC++ 编译器不支持在 Quora 上进行矢量化 over here, which surprises me - I thought that modern C++ compilers are able to reason about the vectorizability of loops, but apparently the VC++ compiler/optimizer is unable to generate SIMD code even if explicitly told to do so. The seeming lack of automatic vectorization support contradicts the answers for this 2011 question,这表明编译器将尽可能进行矢量化。
也许,编译器只会矢量化非常明显的情况,例如 std::array<int, 4>
,仅此而已,因此 C++17 的显式并行化会很有用。
因此我的问题是:当前的编译器是否会在未明确告知时自动矢量化我的代码? (为了使这个问题更具体,让我们将问题缩小到支持 SIMD 的 Intel x86 CPU,以及最新版本的 GCC、Clang、MSVC 和 ICC。)
作为扩展:其他语言的编译器是否能更好地自动矢量化(可能是由于语言设计)(因此 C++ 标准委员会决定有必要进行显式(C++17 风格)矢量化)?
根据我的经验,自动发现 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 的不同版本其他人可以使用代码...