4

特别是对于 SPARC 程序集,已取消的分支与常规分支有何不同?

我一直认为,当我需要填充分支指令的 nop 延迟槽时,需要取消分支指令。但是,我认为我在这部分上是不正确的,因为您可以在不取消分支的情况下填充 nop。

4

2 回答 2

8

如果不采用分支,则被取消的分支指令会导致延迟槽中的指令(分支之后的指令)被忽略。

为什么这很重要?因为通常情况下,分支之后的指令都会被执行,即使是分支被取走。这是因为有两个程序计数器,PC 和 NPC。表示正在执行的指令的PC被更新为NPC,即PC+4,同时NPC被更新为分支指令的目标。因此,由于这些事件的时间安排,必须加载下一条指令。如果可以的话,使用这个循环比直接扔掉那个循环更有利可图。然后,我们只需将该指令作为循环的一部分。

loop:   someOp                
        someOtherOp
        branch      loop      ;
        delayslotOp           ; will actually be executed, before someOp, after branch

如果我们不能在分支之后使用指令槽,那么我们会在其中插入一个 nop,并且在那个循环中什么都不做。

那么为什么会有不同的指令与取消和非取消分支选项?让我们选择退出循环时会发生什么。如果我们将延迟槽作为循环活动的一部分,我们可能不希望在离开循环时执行该操作。因此,我们将在分支指令的末尾添加“,a”。

这个页面有一些很好的例子。

于 2009-03-08T18:44:55.773 回答
3

根据SPARC 架构手册 (v9)

3.2.3 控制转移

[...]

大多数控制转移指令都有延迟;即,在控制转移到目标地址完成之前,按逻辑顺序紧跟在控制转移指令之后的指令被调度。

[...]

延迟控制转移指令之后的指令称为延迟指令。如果不采用分支,延迟控制转移指令中的位(取消位)会导致延迟指令被取消(即无效)。

6.3.4 控制转移指令(CTI)

[...]

编程注意事项:annul 位增加了编译器在分支后找到有用指令来填充延迟槽的可能性,从而减少了程序执行的指令数量。例如,annul 位可用于从循环中移动指令以填充关闭循环的分支的延迟槽。同样,annul 位可用于将指令从“ifthen-else”程序块的“else”或“then”分支移动到在它们之间进行选择的分支的延迟槽。由于提供了全套条件,编译器可以安排代码(可能颠倒条件的意义),以便可以将来自“else”分支或“then”分支的指令移动到延迟槽。

以下代码显示了两个分支,在第一个中,延迟指令始终执行,在第二个中,如果未采用分支,则延迟指令被取消:

cmp   %i3, %i0
ble   %icc, -0x5c
ld    [%l0 - 0x4], %i5  ; executed whether the branch is taken or not

...

cmp   %l1, 0x80
bl,a  %icc, +0x40
ld    [%fp + 0x7c7], %g2    ; annulled if the branch is not taken, executed otherwise
于 2013-04-28T21:31:12.043 回答