对 MIPS 中的 if 跳转感到困惑

Confused by the if Jumps in MIPS

我很难理解为什么我的 bge 语句中的跳转会跳转到标签,然后在其他两个执行标签和 return 时结束。我对此有些陌生,希望有一个 link 或另一个 post 有我找不到的类似问题。我在 nop 末尾对它在我看来的样子和代码的结果留下了评论,我可能是错的,如果我有希望的话,我可以得到它应该如何工作的指导。

.globl main
.data
.text
main:

    li $t5, 8
    li $t6, 9 
    blt $t6,$t5, L1 // if (9 < 8) goto L1
    addi $t1, $t1, 2 // $t1 = 2
L1: 
    addi $t1, $t1, 1 // $t1 = 3
    nop // $t1 = 3 
    li $t7, 2
    li $t3, 2
    bne $t7,$t3, L2 // if ( 2 == 2) goto L2
    addi $t3, $t3, 2 // $t3 = 9
L2: 
    addi $t3, $t3, 5 // $t3 = 7
    nop // $t3 = 9
    li $t6, 4
    li $t5, 1
    bge $t6,$t5, L3 // if (4 >= 1) goto L3
    add $t6, $t6, $t5
    addi $t6, $t6, 3  
L3: 
    addi $t6, $t6, 5 // $t6 = 9
    nop // $t6 = 9

首先,术语:

标签不执行。它们在汇编代码中,但 take/get 没有机器代码,处理器永远看不到它们。因此,标签本身不能改变控制流,只有处理器指令可以做到这一点。

汇编代码中有标签,它们用于通知汇编程序在机器代码指令中为引用它们的汇编指令(标签)选择什么偏移量。

此代码中没有任何内容包含“returns”。通常我们保留术语 return 用于子例程 return 通过间接分支返回其调用者。

就结束而言,您没有程序指令序列的有效结束,因此它在完成时只是简单地结束。

第一个分支,blt不应该开火(应该倒下)b/c9确实不少于8。

您对 bne 的评论与用汇编编写的操作相反,也许这会澄清一些事情。该分支也不会触发,因为 2 确实等于 2。

最后一个分支将触发,因为 4 >= 1,因此将跳过前面的几条指令。

您应该在开始时将 $t1 初始化为零,而不是依赖模拟器将其清零。

你是正确的 $t6 将以 9 = 4+5 结束。

可能让您感到困惑的是 MIPS 有 branch delay slots——这意味着无论何时您有一个分支(条件或无条件,都无关紧要),分支指令之后的指令将始终在分支实际分支之前执行。所以在这段代码中:

    blt $t6,$t5, L1 // if (9 < 8) goto L1
    addi $t1, $t1, 2 // $t1 = 2
L1: 

即使条件为真,分支似乎也没有任何效果,因为分支之后的指令(这是它与目标之间的唯一指令)无论如何都会被执行。

代码中

    li $t6, 4
    li $t5, 1
    bge $t6,$t5, L3 // if (4 >= 1) goto L3
    add $t6, $t6, $t5
    addi $t6, $t6, 3  
L3: 
    addi $t6, $t6, 5 // $t6 = 9

add $t6, $t6, $t5指令会一直执行,所以当分支条件为真时,只会跳过addi $t6, $t6, 3指令。

处理此问题的最简单方法是始终在分支后放置一条 nop 指令。这会工作但效率低下(浪费了一个指令槽和周期),所以如果你能弄清楚如何在那里放置一条有用的指令会更好。请注意,分支后的指令直到条件分支计算其测试后才会执行,因此您不能仅将分支前的指令移动到分支后。

最近的 MIPS 实现有 'compact' 个没有延迟槽的分支指令版本。您可以通过在指令

中添加 c 来使用它们
bgec $t6,$t5, L3 // if (4 >= 1) goto L3

如果您的 simulator/system 支持它们