分支延迟:如果分支更改了分支延迟槽中指令使用的值怎么办

branch delay: What if the branch changes the value that is used by the instruction in the branch delay slot

我刚刚开始了解 branch delay slot on mips 的概念。

//  contains 1
jal flag
sw , 0()
...
flag: addi , [=10=], 5

在我的理解中,指令sw会在PC跳转到flag标签之前执行,该标签将值1从$1存储到$2中的地址。但是对于预期的顺序,sw 将在 flag 标签之后执行,并且存储到内存中的值为 5.

我是否误解了分支延迟的工作原理?如果不是那是不是我们在写代码的时候就要考虑分支延迟的影响?

更新 我以“通用编程风格”编写了汇编代码,所以 expected order 是:

1. jump to the method flag()
2. execute flag()
3. store the value in  to the memory

是的,b运行ch-delay 插槽通过使其架构可见,将隐藏 b运行ch 延迟的责任卸载给编译器,因为你怀疑。 (- 因为第一代 MIPS 设法将 b运行ch 延迟降低到 1 个周期)。

这就是重点,为什么带有 b运行ch 预测的未来 CPU 不能仅仅摆脱延迟槽,所以 MIPS 一直背负着它,直到 MIPS32r6 broke backwards binary compat and reorganized the opcodes, 介绍 b运行ches 没有延迟插槽。

正如 EOF 在评论中提到的那样,延迟槽使异常处理变得非常复杂,因为将可能出错的指令放入延迟槽是合法的。对于异常 return,CPU 需要知道哪个指令指向 运行、 之后的地址,该地址可能紧随其后,也可能不紧随其后.


延迟槽中的指令在b运行ch目标地址处的代码之前执行,包括其对内存或寄存器的影响。如果延迟槽指令在 jal 写入后读取 $ra,那么是的,延迟槽指令会看到 b运行ch 本身所做的更改。

但我认为你问的是被调用函数,这是一个单独的问题;不,return 地址将是延迟槽之后的指令,因为延迟槽指令已经 运行 紧跟在 jb 本身之后,而 CPU 正在从目标地址获取代码;这就是重点。


因此,当您为带有延迟槽的机器编程时,您需要了解指令执行的顺序,并尝试用比 NOP 更有用的东西来填充延迟槽。 (虽然如果你只使用 NOP,那么你的代码将 运行 在有或没有延迟槽的机器上相同。例如,在 MARS 中,如果你单击复选框以在模拟带有延迟槽的 MIPS 或模拟 MIPS 之间切换假的简化 MIPS 没有。)

经典 MIPS 汇编程序显然会尝试为您填充延迟槽,除非您使用 .noreorder,如 See MIPS Run 中所述。也就是说,他们会让你的 asm 源看起来像你的问题说你“期望”(或至少想要),即没有 b运行ch 延迟槽,并寻找可以在不影响正确性的情况下移动的独立指令。

(编译器生成的代码将使用 .noreorder 并且编译器必须“预期”实际将要发生的事情。人类也可以使用它,如果他们知道预期机器将实际做什么。)