Как передать управление после цикла в сборке? - PullRequest
0 голосов
/ 08 октября 2019

Я хотел бы перевести приведенный ниже код C на язык ассемблера.

Однако я не вижу необходимости использовать стек в этом примере.

Более того, я бы хотелхотелось бы узнать, сохраняет ли «beq» адрес следующей инструкции в $ ra, как это делает «jal», поскольку, когда цикл заканчивается, я хотел бы вернуться к исходной функции foo и продолжить инструкции (которые здесьпросто возвращается.)

     int foo(int* a, int N) {
         if(N > 0) 
             {
             for(int i = 0; i != N; i = i + 1) 
                { 
                a[i] = bar(i << 4, a[i]);
                } 
             }
     return N & 7; 
     }
#assume *a in $a0, N $N in $a1
foo:
slt $t0, $zero, $a1 #put 1 in $t0 if 0 < N
li $t1,0 # use $t1 as loop counter
beq $t0, 1, loop  # enter loop if 0 < N
and $v0, $a1, 7 # do bitwise and on N and 7 and save in $v0 as return value

loop:
beq $t1, $a1, exit # exit loop when i = N
sll $t3, $t1, 2 # obtain 4 * i
add $t3, $a1, $t3 # obtain address of a[i] which is address of a plus 4i
lw $t3, o($t3)  # load a[i] into $t3
sll $t4, $t1, 4 #perform  i<< 4 and save in $t4
# the 2 previous load arguments for bar
jal bar # assume bar saves return value in $v2
sw $t3, 0($v1)
j loop

exit:
and $v0, $a1, 7

Ответы [ 2 ]

2 голосов
/ 08 октября 2019

beq - для условного ветвления, не для вызова - оно меняет PC (условно), но не $ra. Мы используем его для перевода структурированных операторов (например, if, for) в стиль ассемблера if-goto.

Однако я не вижу необходимости использовать стек в этом примере.

Вы должны использовать стек для этого кода, потому что вызов bar (как в jal bar) уничтожит foo s $ra, и хотя bar сможет вернуться обратно к foo, foo не сможет вернуться к своему вызывающему. Поскольку для этого требуется стек, вам потребуется пролог и эпилог для выделения и освобождения некоторого пространства стека.

Ваш код неправильно передает параметры, например, в bar, i << 4, должно быть передано в $a0, а a[i] должно быть передано в $a1.

У вас нет инструкции возврата в foo - отсутствует jr $ra.

0 голосов
/ 08 октября 2019

Если в какой-либо из ваших beq инструкций было установлено $ra, то возвращаться к ним было бы бесполезно. Но так как вы спросили:

IХотелось бы узнать, сохраняет ли "beq" адрес следующей инструкции в $ ra, как и "jal"

Если мнемоника инструкции не заканчивается на al (что означаетдля And Link), он не сохраняет адрес возврата в $ra.

Классические MIPS содержат следующие инструкции, которые ссылаются из этой несколько неполной ссылки (отсутствует nor иИДК что еще).

  • jal target (переход и ссылка)
  • BGEZAL $reg, target (условный переход, если> = 0 и ссылка)
  • BLTZAL $reg, target(условное ветвление, если <0 и ссылка) </li>

Обратите внимание, что условные ветви эффективно разветвляются на знаковый бит регистра.

bal является псевдонимом для bgezal $zero, target, полезно для выполнения вызова функции, относящейся к ПК. (В ветвях MIPS используется полностью относительное кодирование для смещения ветвей, в переходах MIPS используется кодирование абсолютной области, которое заменяет младшие 28 битов ПК + 4. Это важно для позиционно-независимого кода).


Нетэто особенно относится к вашему делу;ваш foo должен сохранить / восстановить $ra при входе / до jr $ra, потому что вам нужно позвонить bar с jal или bal. Использование связующей ветви в качестве ветви цикла ни на что не повлияет (за исключением того, что сделает ваш код еще менее эффективным и ухудшит производительность на реальных процессорах, которые выполняют предсказание обратного адреса с помощью специального предиктора, который предполагает, что jal и jr $ra являютсяв паре правильно).

Использование bal / jal не позволяет автоматически возвращать то, что вы прыгаете;это происходит только в том случае, если цель когда-либо использует jr $ra (возможно, после копирования $ra в другое место и его восстановления).

...