数据级并行(Data Level Parallel,DLP)是指处理器能够同时处理多条数据,属于SIMD模型,即单指令流多数据流模型
继续挖掘传统ILP的缺陷:
并且SIMD模型有以下优点:
因此近年来DLP发展迅速,特别是在超级计算机领域
DLP思想:一条指令处理长度为N的一组向量元素的计算
书上引入VMIPS向量体系结构作为MIPS体系结构的向量扩展
向量指令后缀VV表示两个向量寄存器操作、VS表示一个向量寄存器和一个标量寄存器操作(交换顺序是SV),.D仍然是双精度浮点的后缀,常用指令用:
ADDVV.D V1,V2,V3
ADDSV.D V1,F0,V2
MULVS.D V1,V2,F0
LV V1,R1
SV R1,V1
DaXPY是Linpack的某项标准测试,表示双精度a乘以向量X加上向量Y这一计算过程,用VMIPS表示为:
L.D F0,a
LV V1,Rx
MULVS.D V2,V1,F0
LV V3,Ry
ADDVV.D V4,V2,V3
SV Ry,V4
如果没有循环间相关,编译器可以为一段程序序列生成其VMIPS代码,称这段程序是可向量化的(可以用类似之前提到的代码调度消除循环间相关再向量化)
若处理下面DaXPY循环:
for (i = 0; i < n; i++) {
Y[i] = a * X[i] + Y[i];
}
其中n可以不等于向量寄存器最大长度MVL(VMIPS中MVL=64)也可以是根据前面程序动态确定的,此时需要引入一个向量长度寄存器VLR来实现条带挖掘版本的循环来适应MVL
VLR控制所有向量操作(包括运算和载入存储)的向量长度,当然VLR不能超过MVL
此时可以根据MVL把数据划分为条状,一条一条的处理,称之为条带挖掘:
low = 0;
VL = n % MVL;
for (j = 0; j < n / MVL; j++) {
for (i = low; i < low + VL; i++) {
Y[i] = a * X[i] + Y[i];
}
low += VL;
VL = MVL;
}
上述划分策略为先处理长度不足MVL的单个条带,再处理n / MVL - 1
条长度为MVL的整齐条带
如果可向量化的循环中存在if语句,那么有些向量元素执行操作而有些不执行,难以直接向量化:
for (i = 0; i < n; i++) {
if (X[i] != 0) {
X[i] -= Y[i];
}
}
VMIPS中引入向量遮罩寄存器VM来处理if语句,VM用测试语句来测试每位向量元素,元素X[i]满足条件时置VM[i] = 1
,否则置0(遮罩寄存器默认全1)
在遮罩寄存器的遮罩下,后续的向量指令只有VM[i] == 1
的对应元素才执行
基本块的代码为:
LV V1,Rx
Lv V2,Ry
L.D F0,#0
SNEVS.D V1,F0 ; 若V1[i] != F0,则置VM[i]为1否则为0
SUBVV.D V1,V1,V2
SV V1,Rx
见另外两篇博文:
第五章中介绍过循环依赖(循环间相关)和消除循环依赖的办法,循环级并行不仅要消除循环间相关还需要消除名称相关(输出相关、反相关)
GCD(最大公约数)能够检测一个循环中,对数组的两次访问是否存在相关
假设一个循环中,以索引a * i + b
存储一个数组元素,并以索引c * i + d
载入同一个数组中的元素,GCD测试表示为:
若GCD(a,c)能够整除d-b,则存在循环间相关
如循环为X[2 * i + 3] = X[2 * i] * 5.0;
,GCD(a,c) == 2
而d-b == -3
不能整除即不存在循环间相关
GCD测试最大公约数计算就是为了检测某一次循环中load的元素会不会是其他某次循环中store的元素
注:由于GCD测试没有考虑循环范围,因此某些时候GCD测试表明存在相关但实际却没有(比如刚好重合的时候已经不在数组界限范围内了),但可以证明:GCD测试能够确保不存在相关
消除名称相关的主要方法还是之前介绍的重命名方法,如下面的循环存在输出相关和反相关:
for (i = 0; i < 100; i++) {
Y[i] = X[i] / c;
X[i] = X[i] + c;
Z[i] = Y[i] + c;
Y[i] = c - Y[i];
}
重命名为:
for (i = 0; i < 100; i++) {
T[i] = X[i] / c; // Y -> T,消除输出相关
X1[i] = X[i] + c; // X -> X1,消除反相关
Z[i] = T[i] + c; // Y -> T,消除反相关
Y[i] = c - T[i];
}