20

v4 系列编译器可以使用一些现代 CPU 上的SIMDgcc处理器自动矢量化循环,例如 AMD Athlon 或 Intel Pentium/Core 芯片。这是怎么做到的?

4

2 回答 2

28

原始页面提供了有关让 gcc 自动矢量化循环的详细信息,包括一些示例:

http://gcc.gnu.org/projects/tree-ssa/vectorization.html

虽然这些示例很棒,但事实证明,使用最新 GCC 调用这些选项的语法似乎发生了一些变化,现在看:

总之,以下选项将适用于具有 SSE2 的 x86 芯片,给出已矢量化的循环日志:

gcc -O2 -ftree-vectorize -msse2 -mfpmath=sse -ftree-vectorizer-verbose=5

请注意,-msse 也是一种可能,但它只会使用浮点数对循环进行矢量化,而不是双精度数或整数。(SSE2 是 x86-64 的基线。也适用于 32 位代码-mfpmath=sse。这是 64 位的默认设置,但不是 32 位。)


现代版本的 GCC 启用-ftree-vectorize-O3所以只需在 GCC4.x 及更高版本中使用它

gcc   -O3 -msse2 -mfpmath=sse  -ftree-vectorizer-verbose=5

(Clang 启用自动矢量化-O2。ICC 默认启用优化 + 快速数学。)


以下大部分内容是由彼得·科德斯(Peter Cordes)撰写的,他本可以写一个新的答案。随着时间的推移,随着编译器的变化,选项和编译器输出也会发生变化。我不完全确定是否值得在这里详细跟踪它。评论? - 作者

要同时使用您正在编译的硬件支持的指令集扩展并对其进行调整,请使用-march=native.

归约循环(如数组的总和)将需要 OpenMP 或-ffast-math将 FP 数学视为关联和矢量化。 Godbolt 编译器资源管理器上的示例,-O3 -march=native -ffast-math其中包含一个没有-ffast-math. (好吧,GCC8 及更高版本执行 SIMD 加载,然后将其解压缩为标量元素,这与简单展开相比毫无意义。一个addss依赖链延迟的循环瓶颈。)

有时你不需要-ffast-math,只是可以帮助 gcc 内联数学函数并对涉及和/或/的-fno-math-errno东西进行矢量化。sqrtrintnearbyint

其他有用的选项包括-flto(用于跨文件内联、常量传播等的链接时间优化)和/或-fprofile-generate使用实际输入的测试运行的配置文件引导优化/ -fprofile-use。PGO 为“热”循环启用循环展开;在现代 GCC 中,即使在 -O3 时也默认关闭。

于 2009-01-03T16:24:39.503 回答
10

有一个 gimple(GCC 的中间表示) pass pass_vectorize。此通道将在 gimple 级别启用自动矢量化。

为了启用自动矢量化(GCC V4.4.0),我们需要执行以下步骤:

  1. 根据目标架构提及向量中的单词数。这可以通过定义宏来完成UNITS_PER_SIMD_WORD
  2. 可能的矢量模式通常需要在单独的文件中定义<target>-modes.def。该文件必须位于包含机器描述的其他文件所在的目录中。(根据配置脚本。如果您可以更改脚本,您可以将文件放在您希望它所在的任何目录中)。
  3. 根据目标体系结构要考虑用于矢量化的模式。例如,4 个字将构成一个向量,或者 8 个半字将构成一个向量,或者两个双字将构成一个向量。这个细节需要在<target>-modes.def文件中提及。例如:

    VECTOR_MODES (INT, 8);     /*       V8QI V4HI V2SI /
    VECTOR_MODES (INT, 16);    /
    V16QI V8HI V4SI V2DI /
    VECTOR_MODES (FLOAT, 8);   /
               V4HF V2SF */

  4. 建造港口。可以使用命令行选项启用矢量化-O2 -ftree-vectorize

于 2009-11-03T12:10:05.090 回答