


本文主要介绍循环级向量化。实验环境是CentOS7 + LLVM。
自动向量化是指编译器自动地将串行代码转化为向量代码的一种优化变换。LLVM支持两种自动向量化方法,分别是循环级向量化和基本块级向量化。循环级向量化通过扩大循环中的指令以获得多个连续迭代中操作的向量执行,在LLVM中通过编译选项-fvectorize开启循环向量化,并且当打开-O2选项及高于-O2优化级别的选项即自动开启循环向量化优化。
循环向量化的编译选项及其功能如下所示:
(1)-fvectorize:开启循环向量化。默认情况下,循环矢量化器处于启用状态。
(2)-Rpass=loop-vectorize:在编译器的输出信息中查看向量化成功的信息。
-Rpass-missed=loop-vectorize:显示循环向量化失败的语句。LLVM会先对代码中的循环进行合法性分析,当识别到循环中因存在依赖关系而无法向量化时,会中断编译的向量化过程,并显示导致向量化失败的原因。
-Rpass-analysis=loop-vectorize:显示循环向量化失败的多个原因。
(3)-force-vector-width=<参数>控制向量化宽度(因子),即vectorization width的数值。
-force-vector-interleave= 控制循环展开因子(循环内语句展开次数),即interleave count的值。
在进行循环向量化时,LLVM编译器先对代码中的循环进行向量合法性分析,当识别到循环中因存在依赖关系而影响向量化情况时,会中断编译的循环向量化过程,并显示导致循环向量化失败的原因。
2. 示例分析
示例一是一个简单的数组赋值以及求和的程序,代码如下所示,将其命名为loop_vectorize.c.

运行命令:
(1)clang -O2 loop_vectorize.c -emit-llvm -S -Rpass=loop-vectorize
可以通过命令(1)自动开启循环向量化。

(2)clang loop_vectorize.c -emit-llvm -S -o loop_vectorize-before.ll
可以通过命令(2)查看开启循环向量化前生成的中间代码。

(3)clang -O2 loop_vectorize.c -emit-llvm -S -o loop_vectorize-after.ll
可以通过命令(3)查看开启循环向量化后生成的中间代码。

(4)clang -O2 loop_vectorize.c -mllvm -force-vector-width=8 -Rpass=loop-vectorize
可以通过命令(4)控制循环向量化宽度为8。

(5)clang loop_vectorize.c -emit-llvm -S -o loop_vectorize-before.ll
可以通过命令(5)查看设置循环向量化宽度为8前的中间代码。优化前一次只存一个数据。

(6)clang -O2 loop_vectorize.c -force-vector-width=8 -emit-llvm -S -o loop_vectorize-after.ll
可以通过命令(6)查看设置循环向量化宽度为8后的中间代码。优化后一次可以存8个数据。

(7)clang -O2 loop_vectorize.c -mllvm -force-vector-interleave=4 -Rpass=loop-vectorize
可以通过命令(7)控制循环展开因子为4。

(8)clang loop_vectorize.c -emit-llvm –S -o loop_vectorize-before.ll
可以通过命令(8)查看设置循环展开因子为4前的中间代码。

(9)clang -O2 loop_vectorize.c -force-vector-interleave=4 -emit-llvm -S -o loop_vectorize-after.ll
可以通过命令(9)查看设置循环展开因子为4后的中间代码。

之后通过如下命令来分析开启循环向量化优化前后程序的执行时间。
(10)clang loop_vectorize.c -o loop_vectorize-before
(11)./loop_vectorize-before
(12)clang loop_vectorize.c -O2 -fvectorize -o loop_vectorize-after
(13)./loop_vectorize-after

可以看出,开启循环向量化优化前后,得到的计算结果都是一样的,但是经过循环向量化优化后,程序的执行时间明显要比优化前的执行时间短,达到了优化的效果。
示例二是一个无法进行向量化的例子,因为在第三个循环存在循环携带依赖。其代码如下所示,将其命名为loop_vectorize_miss.c.

运行命令:
clang -O2 loop_vectorize_miss.c -Rpass-missed=loop-vectorize -Rpass-analysis=loop-vec torize
运行该命令可以看出该程序无法进行循环向量化,并给出了循环向量化优化失败的原因。

循环级向量化通过扩大循环中的指令以获得多个连续迭代中操作的向量执行,在LLVM中通过编译选项-fvectorize开启循环向量化,并且当打开-O2选项及高于-O2优化级别的选项即自动开启循环向量化优化。
(1)零基础入门循环分布变换和自动向量化 - 知乎 (zhihu.com)
(2)编译器优化那些事儿(12):LLVM 自动向量化-CSDN博客


