ARM架构下依赖型前/后增量内存访问性能咨询
ARM后增量寻址的指令依赖与并行调度规则
首先从ARMv8/v9指令集的架构语义来看,对同一基址寄存器执行连续后增量加载时,逻辑上存在写后读(RAW)依赖:
以两条连续指令为例:
ldr x0, [x1], #8 // 从x1指向的地址加载数据到x0,之后x1自增8 ldr x2, [x1], #8 // 从更新后的x1指向的地址加载数据到x2,之后x1再自增8
第二条指令的寻址基址,是第一条指令执行完成后写回的x1值,按照串行执行逻辑,第二条必须等第一条执行完才能启动。但现代乱序执行ARM核心基本都具备依赖消除能力,是否能并行执行完全取决于核心的AGU(地址生成单元)设计,以及增量操作数的类型。
Apple Firestorm/Icestorm架构(A14、M1系列核心)处理逻辑
你使用的Firestorm/Icestorm是目前消费级领域AGU设计最强的ARM核心之一,针对这类固定步长的增量寻址做了专门优化:
- 解码器识别到连续对同一基址寄存器、增量为立即数的后/前增量加载时,会直接在指令重命名阶段完成地址折叠,不需要等待前一条指令写回基址寄存器,就可以直接计算出后续所有加载的目标地址:以上面的代码为例,第一条加载地址是初始x1值,第二条加载地址是初始x1+8,两个地址完全不需要依赖x1的中间写回结果就能算出。
- 两个加载操作会被同时派发到核心的两个独立加载端口,完全并行执行,不会产生流水线阻塞,基址寄存器的最终写回结果(初始x1+16)也会在重命名阶段直接标记,不需要等待两次加载依次完成。
- 只有当增量操作数是通用寄存器(比如
ldr x0, [x1], x3)而非固定立即数时,核心无法提前预判增量值,才会保留真实的RAW依赖,两次加载必须串行执行。
其他代表性ARM核心的处理机制
- ARM公版Cortex性能核(A76及以后、X系列全代):从A76架构开始公版性能核就搭载了类似的立即数步长依赖消除逻辑,连续固定步长的后增量加载可以并行派发到2个加载端口执行,但地址折叠的深度不如Apple核心,超过3条连续同类型加载时就会出现等待。
- ARM公版Cortex小核(A55/A510/A520等)、Cortex-M系列微控制器核心:这类核心为顺序执行架构,没有乱序依赖消除能力,所有对同一基址的增量寻址操作都必须严格串行,等前一条指令写回基址后才能计算下一条的加载地址,完全无法并行。
- 高通自研Oryon核心(骁龙8 Gen2/8 Gen3搭载的自研核心):AGU依赖消除能力接近Firestorm/Icestorm,最多支持4个连续固定步长后增量加载并行派发,执行效率和Apple核心基本持平。
- 高通半定制Kryo核心、三星Mongoose核心:这类半定制/早期自研核心的AGU设计和同期ARM公版性能核基本一致,支持2个连续固定步长加载的并行执行。
注意:无论哪款ARM核心,如果后增量的步长是存在通用寄存器里的动态值,而非编译期确定的立即数,都无法消除依赖,两次加载必须串行执行。
内容的提问来源于stack exchange,提问作者Moonchild
相关产品推荐
相关产品推荐

