0.前言
通过这篇文章,可以了解编译器是如何针对GPU单指令多数据流进行编译优化的。也能够理解为什么GPU更适合多数据并行处理,但不如CPU适合处理复制的逻辑。
1.单指令多数据流
首先来看一段简单的if-else语句:
if(A)
{
B = 1;//Instruction S1
C = 2;//Instruction S2
}
else
{
B = 3;//Instruction S3
C = 4;//Instruction S4
}
假设代码中每条语句转换成指令后分别是S1、S2、S3、S4.
如果在CPU的单指令单数据流中,A=true时会取指令S1和S2执行,A=false时会取指令S3和S4执行,不存在A=true和A=false同时存在的这种情况。
但是在GPU的单指令多数据流(SIMD)中却存在A=true和A=false同时存在的情况。
如下图所示是GPU单指令多数据流的执行情况:
GPU单指令多数据流
从图中可以看到,GPU共有4个通道lane1、lane2、lane3、lane4,分别对应4笔不同的数据。这四个通道共享同一组指令S1、S2、S3、S4(如图中左边所示)。但是在4个不同的lane中,A的值在不同的lane中有时是true,有时是false。红色表示执行该指令,橙色表示不执行该指令。
如果按照CPU单指令单数据流的方式去编译,生成的汇编指令是大概这样的:
goto !A , Labe1;//如果A为false,跳转
mov B , 1;//指令S1
mov C , 2;//指令S2
Lable1:
mov B , 3;//指令S3
mov C , 4;//指令S4
可以看到goto指令会根据A的值进行跳转,GPU中A的值在不同的lane中取值不同,不同的lane根据自己的A值进行跳转是行不通的。因为所有的lane共享同一组指令,不可能有的lane在执行S1、S2语句,有的lane在执行S3、S4语句。
所以GPU的指令应该转换成顺序执行,类似与下面这种。
(p0) mov B , 1;//指令S1
(p0) mov C , 2;//指令S2
(p1) mov B , 3;//指令S3
(p1) mov C , 4;//指令S4
此时不同的lane都会按照顺序取值S1,S2,S3,S4,但是具体的lane中会根据前面的p寄存器的取值确定是否执行该指令。例如对于同一条指令S1,根据A的输入,有的lane是执行的(红色ÿ