跳转至

同步与内存依赖

为什么需要同步

Vector、Cube、MTE1、MTE2、MTE3 和 Fixpipe 可以并行推进。汇编文本的先后顺序首先约束发射顺序,并不自动保证前一条异步指令的数据已经对另一执行域可见。

典型生产者—消费者关系:

MTE2 搬入 -> Vector 计算 -> MTE3 搬出
MTE2/MTE1 搬入 -> Cube 计算 -> Fixpipe/MTE 搬出

SET_FLAG 与 WAIT_FLAG

已确认的基本形式:

SET_FLAG.S.V #2
WAIT_FLAG.S.V #2

两个后缀表示事件的源执行域与目标执行域,立即数表示事件槽。其他后缀组合应从 bisheng 生成代码取得,不要根据名称自行拼接。

概念性依赖序列:

MOV_OUT_TO_UB [X0], [X1], X2
// 发布 MTE2 -> Vector 事件
// 等待同一事件
VADD.s16 [X3], [X0], [X4], X5, MASK

事件槽应在旧事件已被消费后再复用。仅仅重用相同编号不能建立正确的一一对应关系。

屏障

指令 用途
BAR 指定执行域的屏障类操作
BAR_SET/BAR_WAIT 分离的屏障发布与等待形式
DSB 数据同步屏障
HSET_FLAG/HWAIT_FLAG 层次化事件
WAIT_FLAG_DEV/DEVI 设备侧等待形式
SET_CROSS_CORE 跨 Core 事件形式

屏障解决的是顺序和可见性问题,不修正地址越界、错误 stride、未对齐访问或错误的矩阵形状。

Scalar 与 Vector 条件

Scalar CMP -> 标量条件状态 -> JUMPC/SEL
Vector VCMP -> 比较掩码 -> VSEL/后续 Vector 操作

硬件循环的回边也不自动等待循环体中的异步搬运或矩阵计算;需要在循环内正确布置依赖。

编程规则

  1. 标记每条异步指令属于哪个执行域。
  2. 为每个读操作找到最近的数据生产者。
  3. 跨执行域时保留编译器生成的事件边。
  4. 只有在确认旧事件已消费后才复用事件槽。
  5. 内联汇编读写内存或不可见硬件状态时使用 volatile 和适当的 memory clobber。
  6. 不确定同步后缀时,先用对应 Ascend C builtin 生成参考序列。