type
status
date
slug
summary
tags
icon
password
一、什么是自动向量化?
自动向量化是将串行代码转化成向量代码的一种优化变化。循环级向量化通过扩大循环中的指令以获得多个连续迭代中操作的向量执行;基本块级向量化将挖掘代码中的多个标量操作将其合并为向量操作。(读起来可能比较抽象,下面会细讲)
二、向量化计算和之前有关于循环优化的差别?
在写这篇文章之前我已经学习了循环优化的相关内容,并且学习了一部分循环级向量化的内容。在学习循环级向量化的过程中,我感觉循环级向量化和之前学习的循环优化有关内容十分相似,甚至感觉一模一样的。但是看到了这篇文章之后感觉恍然大悟。文章链接
其实向量化的核心就是:将串行代码变成并行代码。比如像之前的循环展开虽然将步数从1变为4,但是在一个循环内,还是需要给1赋值->给2赋值->……这样一个一个赋值。但是对于向量化来说一次就可以同时给1、2、3、4赋值(假定向量化的宽度为4)。

向量化的实现全依赖于CPU的SIMD指令集。
三、循环级向量化(Loop Vectorization)
循环级向量化存在于循环语句里面,并且循环语句中的依赖都不是真依赖才行。
为了搞清楚无优化、循环优化和循环向量化之间的优化差别,我将使用两个示例、三个优化来说明他们之间的差别。第一个代码命名为loop_unroll.c文件,主要是展示循环展开下的优化效果。第二个代码命名为vector_loop.c主要是用来做循环级向量优化实验的,这个文件会分别做优化,一个是-O0优化(不进行向量化优化),另外一个是-O2优化(会进行向量化优化和其他优化)。
代码1:loop_unroll.c
代码2:vector_loop.c
首先来看代码1:
loop_unroll1函数:在一个循环内一次能赋值4个数(相当于一个循环展开的优化)
在编译代码1的时候不使用任何的优化选项
命令:clang loop_unroll.c -O0 -o loop_unroll
得到的结果如下所示:

再来看看代码2:
loop_unroll1函数每次赋值一个数,在相加的时候也是一个个相加,如果不进行任何的优化,效率一定会是最低的。
首先看不进行任何优化的命令:clang vector_loop.c -O0 -o vector_loop_O0
得到的结果如下所示:

其次是进行向量化优化的命令:clang vector_loop.c -O2 -o vector_loop_O2
得到的结果如下所示:

从可视编译文件上看:
O0产生的只有body和循环指令(就是不会产生vector)。
如图所示:

O2产生的就会有vector。
如图所示:

使用-Rpass=loop-vectorize来查看一下循环向量化的信息。

出现vectorized loop且向量化的宽度为4,基本块内语句的展开次数为2。
LLVM编译器先对代码中的循环进行合法性的分析,当不存在真依赖的时候就进行循环向量化。
四、基本块级向量化(basic block vectorization)
基本块级向量化也可以称作超字节并行(Superword Level Parallelism)。基本块内可以同时执行的多个标量打包(pack)成向量的操作来实现并行,基本是在基本块内发掘并行指令。
SLP的核心算法为以下4步:
- Identifying Adjacent Memory References(识别临近内存引用)
- Extending the PackSet(扩大打包集,打包就是标量变成向量的一个过程)
- Combination(组合)
- Scheduling(安排向量化)
- 作者:JucanaYu
- 链接:https://jucanayu.top/article/9aa1d30c-ee89-4715-80e6-9506c4b4cd0a
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。