У меня возникли проблемы с пониманием порядка инструкций в этом коде. Скажем, 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
Программа продолжится с 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
для повторного присоединения к другому пути.