Порядок выполнения ветки MIPS (beqz)

У меня возникли проблемы с пониманием порядка инструкций в этом коде. Скажем, Beqz истинно, и он переходит к метке next, заканчивается ли программа на этом или метка next2 также выполняется? Поскольку для завершения программы нет системного вызова.

add $t0,$t1,$t2

beqz $t0, next

b next2

addi $t0,$t0,2

next: 
   addi $t2,$t0,3

next2: 
    addi $t1,$t1,2

5 166
2

Ответы:

Программа продолжится с next2. Я предполагаю, что вы хотите пропустить next2, когда ветка истинна, поэтому вы можете сделать следующее, чтобы исправить это:

add $t0,$t1,$t2

beqz $t0, next

b next2

addi $t0,$t0,2

next: 
   addi $t2,$t0,3
   b cont

next2: 
    addi $t1,$t1,2

cont:
    # The rest of your program ...

Решено

Ярлыки - это просто способ дать вам ссылку на адрес из другой инструкции. Они не блокируют исполнение. Выполнение всегда продолжается до следующей инструкции, независимо от пробелов или меток в источнике.

Помните, что исходный код asm - это просто язык для встраивания машинного кода в файл; метки не появляются в машинном коде.


Ваш код странный. У вас есть addi $t0,$t0,2 сразу после инструкции b, поэтому он никогда не может быть достигнут с отключенными слотами задержки ветвления. (По умолчанию для MARS / SPIM). На нем нет ярлыка, поэтому это не цель ветки, к которой вы переходите откуда-то еще.

Но если вы находитесь на реальном MIPS со слотами задержки ветвления (инструкция после ветвления выполняется, даже если ветвление выполнено), тогда b в слоте задержки ветвления beqприводит к непредсказуемому поведению. то есть b будет работать независимо от того, была ли ветка взята, что делает его бессмысленным. Так что ваш код в любом случае не имеет смысла.


Вы делаете свой if намного сложнее, чем он должен быть (или это if/else?). Вместо beq / b, чтобы всегда куда-то прыгать, просто используйте bne, чтобы прыгать или проваливаться. Также используйте значимые имена меток.

 ## MIPS without branch-delay slots

    add  $t0, $t1,$t2
    bnez $t0, sum_nonzero

    # addi $t0,$t0,2     # was unreachable, or was that supposed to be a branch-delay slot?

# sumzero:               # not really a branch target, only reached via fallthrough
    addi $t2, $zero, 3   # only reached with t0 = 0, might as well not even read it

    # execution falls through to the next instruction like always
sum_nonzero: 
    addi $t1,$t1,2       # runs whether bnez was taken or not

    ... execution continues

Или на MIPS со слотами задержки перехода, предполагая, что addi $t0,$t0,2 должен был работать, только если $t0 был ненулевым.

Я заполняю слот задержки ветвления addi $t1,$t1,2 из проходного пути, потому что он всегда работал в вашем исходном источнике. Я предполагаю, что это было задумано.

    add  $t0, $t1,$t2
    bnez $t0, sum_nonzero
    addi $t1,$t1,2       # branch-delay: runs whether bnez was taken or not

# Fall through when sum == zero
    addi  $t2, $zero, 3
    addiu $t0,$zero, -2     # instead of branching to avoid addi  $t0,$t0,2 on this path, do its inverse

sum_nonzero: 
    addi  $t0,$t0,2         # produces $t0 = 0 if $t1+$t2 == 0, otherwise $t0 = $t1+$t2+2

    ... execution continues

Если вы делаете if / else, вы можете поместить код для одной стороны в другое место (после возврата jr $ra), чтобы вам не пришлось перепрыгивать через него. Итак, у одного пути есть одна непроработанная ветвь; у другой стороны есть взятый beq и безусловный b для повторного присоединения к другому пути.