分支延迟:如果分支更改了分支延迟槽中指令使用的值怎么办
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 地址将是延迟槽之后的指令,因为延迟槽指令已经 运行 紧跟在 j
或 b
本身之后,而 CPU 正在从目标地址获取代码;这就是重点。
因此,当您为带有延迟槽的机器编程时,您需要了解指令执行的顺序,并尝试用比 NOP 更有用的东西来填充延迟槽。 (虽然如果你只使用 NOP,那么你的代码将 运行 在有或没有延迟槽的机器上相同。例如,在 MARS 中,如果你单击复选框以在模拟带有延迟槽的 MIPS 或模拟 MIPS 之间切换假的简化 MIPS 没有。)
经典 MIPS 汇编程序显然会尝试为您填充延迟槽,除非您使用 .noreorder
,如 See MIPS Run 中所述。也就是说,他们会让你的 asm 源看起来像你的问题说你“期望”(或至少想要),即没有 b运行ch 延迟槽,并寻找可以在不影响正确性的情况下移动的独立指令。
(编译器生成的代码将使用 .noreorder
并且编译器必须“预期”实际将要发生的事情。人类也可以使用它,如果他们知道预期机器将实际做什么。)
我刚刚开始了解 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 延迟的责任卸载给编译器,因为你怀疑。
这就是重点,为什么带有 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 地址将是延迟槽之后的指令,因为延迟槽指令已经 运行 紧跟在 j
或 b
本身之后,而 CPU 正在从目标地址获取代码;这就是重点。
因此,当您为带有延迟槽的机器编程时,您需要了解指令执行的顺序,并尝试用比 NOP 更有用的东西来填充延迟槽。 (虽然如果你只使用 NOP,那么你的代码将 运行 在有或没有延迟槽的机器上相同。例如,在 MARS 中,如果你单击复选框以在模拟带有延迟槽的 MIPS 或模拟 MIPS 之间切换假的简化 MIPS 没有。)
经典 MIPS 汇编程序显然会尝试为您填充延迟槽,除非您使用 .noreorder
,如 See MIPS Run 中所述。也就是说,他们会让你的 asm 源看起来像你的问题说你“期望”(或至少想要),即没有 b运行ch 延迟槽,并寻找可以在不影响正确性的情况下移动的独立指令。
(编译器生成的代码将使用 .noreorder
并且编译器必须“预期”实际将要发生的事情。人类也可以使用它,如果他们知道预期机器将实际做什么。)