Mips-Assembly beq и - PullRequest
       15

Mips-Assembly beq и

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

У меня есть вопрос об условных выражениях Mips. Могу ли я использовать оператор beq? Например, в CI можно написать if (arr [0] == 'a' && arr [1] == 'b' && arr [2] == 'c'), но как мне написать такой код в сборке mips?

Ответы [ 2 ]

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

По сути, мы объединяем поток управления с логикой условий, которые мы тестируем. Как говорит @Jester, мы можем сделать / наблюдать это в C, который часто более дружественен для этих преобразований, чем сборка.

Вы можете видеть, что:if(arr[0]=='a' && arr[1]=='b' && arr[2]=='c') { ... }

эквивалентно:

if (arr[0]=='a') {
    if (arr[1] == 'b') {
        if (arr[2] == 'c') {
            ...
        }
    }
}

Итак, если вы знаете, как это сделать if (x == y) { ... }, просто примените это три раза.


На языке ассемблера наша единственная конструкция потока управления принятием решений - это if-goto", и, конечно, могут быть проверены только простые условия.

Итак, чтобы выполнить if (x==y) { then-part } else { else-part }, используя стиль" if-goto ", мы проверяем x==y, и при этом условии false мы разветвляемся вокруг then-part и до else-part. Так как мы выполняем ветвление с условием false, то, когда условие истинно, мы не можем выполнить ветвление и запустить then-part, который мы программируем сразу после проверки условия.

Поскольку мы выполняем ветвление с условием false, тодля практических целей мы пишем в стиле "if-goto" на C: if (x!=y) goto ElseLabel;, за которым следует перевод then-part ...


. Для справки см. следующие сообщения:

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

Нет, beq берет 2 регистра и сравнивает их, вот и все. Помните, что язык ассемблера отражает то, что машинный код может выполнять в одной инструкции. Для выполнения чего-то более сложного часто требуется больше инструкций.

Для && нескольких условий вместе, вам нужно либо

  • несколько beq и / или bne инструкций;цепочка ветвей

  • или создайте значение в одном регистре, которое представляет логические и множественные условия перед ветвлением. Например, загрузите все 3 байта и xori их с 'a', 'b' и 'c' соответственно. (Производство 0 для матча). Затем or эти результаты вместе и посмотрите, будет ли окончательный результат 0bne или beq против $zero). Если так, то ни в одном из 3 байтов не было несовпадающих битов, поэтому условиеtrue.

2-й способ оптимизирует устранение короткого замыкания, которое имеет логика C. Обратите внимание, что в выражении C a[1] даже не доступен, если a[0] != 'a', поэтому он не будет ошибаться, даже если a был указателем на последний байт страницы, а следующая страница не отображалась. (Предполагая, что a[0] == 0 или что-то еще, пустая строка с нулем в конце).

Но если вы do знаете, что можете безопасно получить доступ ко всем 3 байтам строки / массива, это вариант.

Это проще / эффективнее в качестве оптимизации, когда условие что-то наподобие if (x < 5 && y < 10), которое вы можете реализовать с помощью инструкций 2x slti для сравнения в регистры И этих регистров вместе, затем beq $t0, $zero, skip_if_body


В этом особом случае, когда вы проверяете 3 смежных байта, это в основном memcmp(a, "abc", 3).

Если вы знаете, что a выровнено по словам,Вы можете выполнить загрузку слов, чтобы получить 3 байта, которые вы хотите, плюс один байт мусора, который мы должны игнорировать.

MARS моделирует систему MIPS с прямым порядком байтов, поэтому 3 байта, которые мы хотим, - это 3 наименеезначащие байты в слове. (В общем случае MIPS может работать с большим или младшим порядковым номером.)

# assuming a[] is a word-aligned static array
# and little-endian MIPS

    lw   $t0,  a             # pseudo-instruction for lui / lw to construct the full address
    li   $t1,  'abc' << 8    # 0x63626100  if your assemble doesn't like multi-char literals

    sll  $t0, $t0, 8         # shift out the 4th byte which we need to ignore
    bne  $t0, $t1, skip_if_body
         # if body: a[0] == 'a' && a[1] == 'b' && a[2] == 'c'
         ...
skip_if_body:
    ...
    jr $ra

Конечно, вы также можете использовать это, если a на самом деле указатель в регистре, который, как известно, выровнен по словам. lw $t0, ($a0).

Я переместил нежелательный байт из нагрузки вместо того, чтобы маскировать его с помощью AND, потому что andi не может кодировать 0x00FFFFFF.

Если a не былокак известно, выровнены, возможно, lwl / lwr для не выровненной нагрузки стоило бы использовать.

или lhu + lbu для загрузки 16 бит и 8 бит отдельно, если у нас есть 2-выравнивание байтов;мы можем проверить 16 битов одновременно с xori, используя всю ширину немедленного, если мы все еще хотим объединить для одной ветви. Или просто с помощью li / beq.

Для построения 'abc' << 8 в регистре требуется 2 инструкции (lui + addiu или ori)

...