首页 > 解决方案 > 序列重新排序以解决 RISC-V 汇编中的数据危害

问题描述

对于以下 RISC-V 代码序列,我试图识别无法通过数据转发解决的数据危害。是否可以通过重新排序代码序列来克服危险?如果是,任何人都可以显示新序列吗?

这是我的代码:

loop: slli  s2, s1, 2
      add   s3, s2, s0
      lw    t0, 0(s3)
      add   t1, t2, t0
      sw    t1, 20(s3)
      addi  s1, s1, 1
      beq   s1, s5, loop

标签: computer-scienceriscv

解决方案


可以通过转发解决哪些数据危害完全取决于您使用的 RISC-V 架构的特定实现。我将假设 Patterson & Hennessey 教科书中介绍的具有转发功能的传统 5 阶段 RISC-V 管道,并尝试回答您的问题。

该流水线具有指令获取 (IF)、指令解码 (ID)、执行 (EX)、内存 (MEM) 和回写 (WB) 阶段。执行阶段计算寄存器寄存器和寄存器立即操作的值,并计算内存(lw/sw)和控制传输(分支/跳转)操作的地址,内存阶段读取 lw 的数据并写入 sw 的数据。数据可以从执行、内存或回写阶段的末尾转发到前一阶段的开头,以用于后续指令。

在您包含的代码片段中,将有 5 个数据危害:

(1)slli s2, s1, 2add s3, s2, s0, 用于注册s2

在这里,寄存器s2由 写入slli和读取add。新值是在第一条指令的 EX 阶段结束时计算的,并且在下一条指令的 EX 阶段开始时需要,因此可以通过转发来解决。

(2)add s3, s2, s0lw t0, 0(s3)注册s3

在这里,寄存器s3由 写入add和读取lw。新值是在第一条指令的 EX 阶段结束时计算的,并且在下一条指令的 EX 阶段开始时需要,因此可以通过转发来解决。

(3)lw t0, 0(s3)add t1, t2, t0登记t0

在这里,寄存器t0由 写入lw和读取add。新值是在第一条指令的 MEM 阶段结束时计算的,并且在下一条指令的 EX 阶段开始时需要,因此无法通过 forwarding 解决

(4)add t1, t2, t0sw t1, 20(s3)进行登记t1

在这里,寄存器t1由 写入add和读取sw。新值在第一条指令的 EX 阶段结束时计算,并且在下一条指令的 MEM 阶段开始时需要,因此可以通过转发来解决。

(5)addi s1, s1, 1beq s1, s5, loop进行登记s1

在这里,寄存器s1由 写入addi和读取beq。新值在第一条指令的 EX 阶段结束时计算。通常对于没有针对控制风险进行任何优化的 RISC-V 流水线,对于分支指令,在 EX 期间将寄存器与程序计数器 + 偏移量的计算并行进行比较以获得分支目标。这里的控制风险是一个单独的问题,但数据风险可以通过转发来解决。

所以在这 5 种危害中,只有一种不能通过数据转发来解决。可以通过指令重新排序来解决吗?是的。看看addi s1, s1, 1。在 之前addi,s1在 first 之后 是 不 被 任何 指令 读取 或 写入 的slli. 如果我们移动该指令,则生成的代码如下所示:

loop: slli  s2, s1, 2
      add   s3, s2, s0
      lw    t0, 0(s3)
      addi  s1, s1, 1
      add   t1, t2, t0
      sw    t1, 20(s3)
      beq   s1, s5, loop

这样,lw检索要写入的数据的指令将在指令需要t0新值时完成 MEM 阶段。t0add t1, t2, t0

通过这种重新排序,所有数据危害都可以通过转发来解决,并且不需要停顿。


推荐阅读