首页 > 解决方案 > 分支延迟:如果分支更改了分支延迟槽中的指令使用的值怎么办

问题描述

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

// $1 contains 1
jal flag
sw $1, 0($2)
...
flag: addi $1, $0, 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 $1 to the memory

标签: assemblymips

解决方案


是的,正如您所怀疑 的,分支延迟槽通过使其在架构上可见,将隐藏分支延迟的责任卸载给编译器。为什么 MIPS 使用一个延迟槽而不是两个?(- 因为第一代 MIPS 设法将分支延迟降低到 1 个周期)。

这就是重点,以及为什么具有分支预测功能的未来 CPU 不能仅仅摆脱延迟槽,所以 MIPS 一直背负着它,直到MIPS32r6 打破了向后二进制兼容并重新组织了操作码,引入了没有延迟槽的分支。

正如 EOF 在评论中提到的,延迟槽使异常处理显着复杂化,因为将可能出错的指令放入延迟槽是合法的。对于异常返回,CPU 需要知道要运行哪条指令,以及该指令之后的地址,该地址可能紧随其后,也可能不紧随其后。

为什么分支延迟槽被弃用或过时?


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

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


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

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

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


推荐阅读