assembly - 分支延迟:如果分支更改了分支延迟槽中的指令使用的值怎么办
问题描述
我刚刚开始了解branch delay slot
on 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
解决方案
是的,正如您所怀疑 的,分支延迟槽通过使其在架构上可见,将隐藏分支延迟的责任卸载给编译器。为什么 MIPS 使用一个延迟槽而不是两个?(- 因为第一代 MIPS 设法将分支延迟降低到 1 个周期)。
这就是重点,以及为什么具有分支预测功能的未来 CPU 不能仅仅摆脱延迟槽,所以 MIPS 一直背负着它,直到MIPS32r6 打破了向后二进制兼容并重新组织了操作码,引入了没有延迟槽的分支。
正如 EOF 在评论中提到的,延迟槽使异常处理显着复杂化,因为将可能出错的指令放入延迟槽是合法的。对于异常返回,CPU 需要知道要运行哪条指令,以及该指令之后的地址,该地址可能紧随其后,也可能不紧随其后。
延迟槽中的指令确实在分支目标地址处的代码之前执行,包括它对内存或寄存器的影响。如果延迟槽指令在写入$ra
后读取jal
,那么是的,延迟槽指令会看到分支本身所做的更改。
但是我认为您是在询问被调用函数,这是一个单独的问题;不,返回地址将是延迟槽之后的指令,因为延迟槽指令已经在j
orb
本身之后运行,而 CPU 正在从目标地址获取代码;这就是重点。
因此,当您为具有延迟槽的机器编程时,您需要了解指令执行的顺序,并尝试用比 NOP 更有用的东西来填充延迟槽。(尽管如果您只使用过 NOP,那么您的代码将在有或没有延迟槽的机器上运行。例如,在 MARS 中,如果您单击复选框以在模拟具有延迟槽的 MIPS 或不带延迟槽的假简化 MIPS 之间切换.)
经典 MIPS 汇编器显然会尝试为您填充延迟槽,除非您使用.noreorder
,如See MIPS Run中所述。即他们会让你的asm源看起来像你的问题说你“期望”(或至少想要),即没有分支延迟槽,并寻找可以在不影响正确性的情况下移动的独立指令。
(编译器生成的代码将使用.noreorder
并且必须编译器“预期”实际会发生什么。人类也可以使用它,如果他们知道预期机器实际上会做什么。)
推荐阅读
- jmeter - 分布式模式下的 Jmeter:JVM 不会因为 BeanShell 服务器而停止
- statistics - H2O 中的平均残差公式
- python - Can't find Element with Selenium
- java - 回到主要活动
- javascript - Webpack stop working after switch to different branch then switch back
- c++ - 以递归方式从文件中提升 C++ 序列化和反序列化对象
- arrays - Finding the first and last rows that contain a black pixel, in a numpy array
- node.js - Azure Function automatic retry on failure UnhandledPromiseRejectionWarning
- php - Wordpress:分层标签端点的问题
- php - Symfony 4 在控制器中设置 Twig 模板路径