![](https://csdnimg.cn/release/download_crawler_static/88249552/bg4.jpg)
}
}
122
0
PPoPP’23,2023年2月25日至3月1日,加拿大蒙特利尔,魏尔斯∙莫西斯,伊万诺夫∙伊万诺夫,多姆克,遠藤,多尔夫特和齐年科。
00
parallel%i=0to10{
0
%x=loaddata[%i]%y
=loaddata[2*%i]%a
=fmul%x,%x%b=
fmul%y,%y%c=fsub
%x,ybarriercall@use(
%a,%b,%c)...
0
%x_cache=memref<10xf32
>%y_cache=memref<10x
f32>parallel%i=0to10{
0
%x=loaddata[%i]%y=
loaddata[2*%i]store
%x,%x_cache[%i]store
%y,%y_cache[%i]}
parallel%i=0to10{
0
%x=load%x_cache[%i
]%y=load%y_cache[
%i]%a=fmul%x,%y
%b=fsub%y,%zcall
@use(%a,%b)...
0
图4.
在屏障周围进行并行循环拆分:将屏障上方的代码放在一个
单独的并行“for”循环中,将屏障后面的代码放在另一个循
环中。该转换消除了屏障,同时保持了语义。最小剪切算法
存储了%x和%y,然后在第二个循环中用于重新计算%a、%
b和%c。
0
R:→.
然后,我们组合相关操作的直接和逆关系,获得访问相同下标
的线程索引之间的关系,D=R−1◦R:→′.
最后,我们减去恒等关系D\I:→′.如果非空,D≠
,不同的线程可能访问相同的地址,需要barrier。对于非仿射
访问或非静态控制流,我们保守地假设整个数组维度都被访问
。在实践中,这在GPU代码中很少需要,其循环通常具有参数
化/静态边界。当涉及多个基地址时,必须检查别名保证。考
虑图3(右)中的代码。由于访问的地址集不重叠,即A∩
A=,可以允许跨barrier进行代码移动。相反,如果对A
的加载或存储进行了1的偏移,那么barrier是必要的,因为在
barrier之后加载的数据将由不同的线程存储。
0
3.2屏障降低
0
为了使GPU程序在CPU上运行,我们必须有效地模拟GPU程
序的同步行为。而第3.1节的内存语义使我们能够在优化过程
中保持barrier的正确性,本节讨论如何在CPU上实现barrier
。CPU体系结构没有线程块的概念,也没有等待该概念中的
线程组的barrier指令。相反,我们使用常规的CPU线程和工
作共享来将线程块循环迭代分配给它们。从概念上讲,这与
GPU执行模型不同,其中线程每次执行一个迭代。工作共享
要求每个线程按顺序执行多个迭代,这使得在迭代中间进行
同步是不可能的,只能在循环结束时进行同步。为了解决这
个问题,我们在我们的MLIR表示中开发了一种新的barrier消
除技术。我们的方法是