【问题标题】:How to vectorize with gcc?如何使用 gcc 进行矢量化?
【发布时间】:2010-09-29 09:17:18
【问题描述】:

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

【问题讨论】:

  • “这是如何完成的”,您的意思是如何启用 gcc 的自动向量化支持,或者编译器如何实际识别可向量化代码并实现该支持?

标签: gcc compiler-optimization simd auto-vectorization vector-processing


【解决方案1】:

原始页面提供了有关让 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 在 -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 数学视为关联和矢量化。 Example on the Godbolt compiler explorer with -O3 -march=native -ffast-math 包括一个没有-ffast-math 的标量减少(数组总和)。 (好吧,GCC8 及更高版本进行 SIMD 加载,然后将其解压缩为标量元素,这与简单展开相比毫无意义。addss 依赖链的延迟循环瓶颈。)

有时您不需要-ffast-math,只需-fno-math-errno 可以帮助gcc 内联数学函数并将涉及sqrt 和/或rint / nearbyint 的内容向量化。

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

【讨论】:

  • -ftree-vectorizer-verbose=5 是旧语法,现在需要使用较新的语法see
  • GCC 是否有更多关于矢量化的更新文档?
  • 那个标志和@malat给出的链接中指定的标志在gcc 8.3中不再存在。试图确定 gcc 提供的标志有点困难。我原帖中的链接也已经 8 年没有更新了。
  • GCC 在-O3 启用自动矢量化。更喜欢那个。(现在默认情况下它不启用循环展开;理想情况下使用-fprofile-generate + -fprofile-use 来展开热循环。)在仅为您自己的计算机编译时也更喜欢-O3 -march=native -ffast-math。另请参阅C loop optimization help for final assignment,了解 GCC 自动矢量化和非古代 gcc 自动并行化的一些示例。
  • @PeterCordes 我不知道-march=native,它确实很好用。只需指定标志made my code 1.19 times faster。谢谢。
【解决方案2】:

有一个 gimple(GCC 的中间表示)通过 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 启用矢量化。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-06
    • 2017-05-29
    • 2011-12-08
    • 2016-02-24
    • 2015-08-25
    • 1970-01-01
    • 2010-12-22
    相关资源
    最近更新 更多