背景
向量化是一种将程序中标量代码转换为向量代码的优化手段。当前很多芯片架构都拥有向量计算单元,架构指令本身支持单指令多数据(SIMD)的并行计算,一条指令同时计算多个数据。使用向量化优化后,可以实现一个cycle计算多个标量数据,从而带来巨大的性能提升。
在LLVM框架中有两个自动向量化pass:循环向量化(Loop Vectorizer)和 SLP向量化(Superword-level Parallelism)。其中循环向量化关注循环迭代间的向量化机会,会使循环的迭代次数减少,单次迭代的计算数据量增大。而SLP向量化关注迭代内的向量化机会,会将单次迭代中的相似标量计算/访存等操作合并为一条向量指令,也就是减少单次迭代内的指令生成数量。
这两个向量化pass都在LLVM中端opt部分执行,其中SLP向量化位置更靠后一些,在循环向量化完成且控制流图简化(CFG Simplify)后执行。
循环向量化
循环向量化扩展循环中的指令,转换的逻辑如下图所示。这个优化在LLVM中是默认开启状态,如果想要关闭可以使用 -fno-vectorize 选项。
#pragma clang loop vectorize_width(2)
for (…) {
}
1. 优化诊断
实际用户代码中,会有很多循环因为各种原因(比如:过于复杂的控制流、数据类型不支持等)无法完成向量化。LLVM提供了打印诊断信息的能力方便开发者调试,这些信息会提示一个循环向量化是否成功以及失败原因,不过失败原因可能不会非常细节。
以下方循环为例,这个循环使用 #pragma 指定要做向量化,但是循环中有个向量化不支持的switch语句,所以会向量化失败。
#pragma clang loop vectorize(enable)
for (int i = 0; i < 128; i++) {
switch (A[i])
}
LLVM提供的的优化诊断有三种:
(1)-Rpass=loop-vectorize&#x