如何使用gcc进行向量化?

21

gcc编译器的v4系列可以自动使用一些现代CPU(如AMD Athlon或Intel Pentium/Core芯片)上的SIMD处理器对循环进行矢量化。这是如何实现的呢?


14
“how is this done” 指的是如何启用gcc的自动向量化支持,还是编译器如何识别可向量化代码并实现该支持? - Mihai Limbășan
2个回答

31

这个页面详细介绍了如何让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也是一个选项,但它只能使用浮点数来矢量化循环,不能使用双精度或整数。(对于x86-64,SSE2是基线。对于32位代码,请同时使用-mfpmath=sse。这是64位的默认值,但不是32位的默认值。)
现代版本的GCC在-O3下启用-ftree-vectorize,所以在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,只需要-fno-math-errno就可以帮助gcc内联数学函数并对涉及sqrt和/或rint/nearbyint的矢量化进行优化。

其他有用的选项包括-flto(链接时优化,用于交叉文件内联、常量传播等)和/或使用-fprofile-generate /测试运行(s)进行基于性能分析的优化/-fprofile-use。PGO使“热”循环展开; 在现代GCC中,即使在-O3级别下也默认关闭此功能。


3
"-ftree-vectorizer-verbose=5" 是旧的语法,现在需要使用更新的语法 - malat
2
GCC是否有关于矢量化更更新的文档? - Royi
那个标志和链接@malat给出的标志在gcc 8.3中已不再存在。试图确定gcc提供的标志有点困难。我原始帖子中的链接也已经8年没有更新了。 - casualcoder
4
GCC在-O3级别下启用自动向量化,请优先选择该选项。现在默认情况下不会启用循环展开。理想情况下,可以使用-fprofile-generate-fprofile-use来让编译器自动展开热点循环。当仅为您的计算机编译时,请优先选择-O3 -march=native -ffast-math选项。此外,参见 C loop optimization help for final assignment 以获取一些GCC自动向量化和自动并行化的示例,这些示例适用于较新版本的GCC。 - Peter Cordes
1
@PeterCordes 我不知道-march=native,它确实非常有效。只是指定标志让我的代码快了1.19倍。谢谢。 - ynn
显示剩余2条评论

10

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

要启用自动向量化(GCC V4.4.0),需要执行以下步骤:

  1. 根据目标架构指定向量中单词的数量。可以通过定义宏UNITS_PER_SIMD_WORD来完成此操作。
  2. 可能的矢量模式需要在一个单独的文件中进行定义,通常是<target>-modes.def。此文件必须位于其他包含机器描述文件的目录中。(根据配置脚本。如果您可以更改脚本,则可以将文件放置在任何目录中)。
  3. 按目标架构考虑进行矢量化的模式。例如:4个单词将构成一个向量或8个半字将构成一个向量或2个双字将构成一个向量。这些细节需要在<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启用矢量化。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接