DMB和DSB指令需要带一个参数,该参数指定了屏障指令的访问类型和应用的共享域范围,如下表。参数的前缀字母表示DSB或DMB的作用域,比如OSH表示outer shareable,ISH表示inner shareable,后缀的两个字母表示DSB或DMB的访问方向,比如LD表示load,其含义是屏障指令后面的load和store指令必须要等前面的load指令完成;ST表示store,其含义是屏障指令后面的store指令必须要等前面的store指令执行完,但是屏障指令后面的load指令不受约束;如果没有后缀,则表示屏障指令之后的任何load/store指令必须要等屏障指令之前的load/store指令完成。
表中的Load - Load/Store表示在屏障之前完成所有load,但不需要完成store,程序顺序中出现在屏障之后的load和store都必须等待屏障完成。;Store – Store表示屏障仅影响store访问,load仍然可以绕过屏障自由重新排序;Any – Any表示load和store必须在屏障之前完成,程序顺序中出现在屏障之后的load和store都必须等待屏障完成。
除了上述的ISB,DMB和DSB,还有几个不常见的屏障指令。
SB(Speculation Barrier)指令阻止指令的推测性执行,直到屏障完成后。在SB完成之前,程序顺序中出现的任何指令的推测性执行都晚于SB指令。
CSDB(Consumption of Speculative Data Barrier)指令用于控制推测执行和数据值预测,包括:任何指令的数据值预测;任何指令的PSTATE.{N,Z,C,V}预测;SVE预测。
SSBB(Speculative Store Bypass Barrier)指令在某些情况下,可以防止推测性加载绕过早期存储到同一虚拟地址。
PSB CSYNC(Profiling Synchronization Barrier)它确保当前PE的所有现有分析数据(profiling data)都已格式化,并且分析缓冲区地址已转换,以便启动对分析缓冲区的所有写入操作。
PSSBB (Physical Speculative Store Bypass Barrier)指令在某些情况下,可以防止推测性加载绕过早期存储,到达相同的物理地址。
TSB CSYNC (Trace Synchronization Barrier)指令保留了对系统寄存器的内存访问的相对顺序。
这几条屏障指令在Armv8-A架构文档中的描述不多,感兴趣的可以再去查查其它文档,看看是否有相关的描述。
Armv8-A还提供了一组Load-Acquire(LDAR)和Store-Release(STLR)指令,可以用于支持释放一致性(Release Consistency)模型。释放一致性模型是对弱序一致性模型的改进,它把同步操作进一步分成获取(acquire)操作和释放(release)操作。
根据上述,可以看出来LDAR和STLR是单向的屏障。LDAR指令仅保证之后的任何内存访问指令在LDAR后可见,不限制LDAR之前的内存访问指令向后重排序。STLR仅保证在所有早期的内存访问在STLR之前都是可见的,不限制后面的内存访问指令向前重排序。所以LDAR和STLR的限制比DMB和DSB要宽松。这一段的英文描述比较绕,转成汉语更不好表达,有点像绕口令了,还是参考下图吧。
上图中的LDAR和STLR组成了一个临界区。灰色区域的load/store指令不能向前或向后重排序,但是LDAR上面的load/store指令可以先后重排序,STLR下面的load/store指令可以向前重排序。
总结一下,由于多种原因,高性能处理器支持指令重新排序。如果内存访问指令间有数据或者地址依赖关系,指令重排序不会打乱这种关系,如果没有依赖关系,内存访问指令就可能会被重新排序,因此内存访问顺序与程序预期顺序可能不符。对于并行程序而言,可能就会导致错误。通过内存屏障指令,可以强制内存访问指令的执行顺序,虽然会对性能造成影响,但是可以保证某些内存访问顺序符合程序预期。
原作者: 老秦谈芯