v4 系列编译器可以使用一些现代 CPU 上的SIMDgcc
处理器自动矢量化循环,例如 AMD Athlon 或 Intel Pentium/Core 芯片。这是怎么做到的?
2 回答
原始页面提供了有关让 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
东西进行矢量化。sqrt
rint
nearbyint
其他有用的选项包括-flto
(用于跨文件内联、常量传播等的链接时间优化)和/或-fprofile-generate
使用实际输入的测试运行的配置文件引导优化/ -fprofile-use
。PGO 为“热”循环启用循环展开;在现代 GCC 中,即使在 -O3 时也默认关闭。
有一个 gimple(GCC 的中间表示) pass pass_vectorize
。此通道将在 gimple 级别启用自动矢量化。
为了启用自动矢量化(GCC V4.4.0),我们需要执行以下步骤:
- 根据目标架构提及向量中的单词数。这可以通过定义宏来完成
UNITS_PER_SIMD_WORD
。 - 可能的矢量模式通常需要在单独的文件中定义
<target>-modes.def
。该文件必须位于包含机器描述的其他文件所在的目录中。(根据配置脚本。如果您可以更改脚本,您可以将文件放在您希望它所在的任何目录中)。 根据目标体系结构要考虑用于矢量化的模式。例如,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 */建造港口。可以使用命令行选项启用矢量化
-O2 -ftree-vectorize
。