簡體   English   中英

Mips-Assembly beq 和

[英]Mips-Assembly beq and

我有一個關於 Mips 條件語句的問題。我可以在 beq 中使用 and 運算符嗎? 例如在 C 我可以寫 if(arr[0]=='a' && arr[1]=='b' && arr[2]=='c') 但是我怎么能在 mips 程序集中寫這樣的代碼?

從根本上說,我們將控制流與我們正在測試的條件的邏輯相結合。 正如@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) {... }那么只需應用 3 次。


在匯編語言中,我們唯一的決策控制流結構是“if-goto”,當然只能測試簡單的條件。

因此,要執行if (x==y) { then-part } else { else-part } ,使用“if-goto”樣式,我們測試x==y並且在該條件為時,我們圍繞then-partelse-part 由於我們在條件 false 上進行分支,因此當條件為真時,我們無法分支並運行我們在條件測試之后立即編寫的then-part

由於我們在條件 false 上進行分支,因此出於所有實際目的,我們在 C 中以“if-goto”樣式編寫: if (x;=y) goto ElseLabel; 然后是then-part翻譯......


供參考,請參閱以下帖子:

不, beq需要 2 個寄存器並比較它們,僅此而已。 請記住,匯編語言反映了機器代碼在一條指令中可以做什么。 做更復雜的事情通常需要更多的指令。

要將&&多個條件放在一起,您需要

  • 多個beq和/或bne指令; 一串樹枝

  • 或在一個寄存器中創建一個值,該值表示分支前多個條件的邏輯和。 例如,加載所有 3 個字節並分別用'a''b''c'對它們進行xori處理。 (為匹配產生0 )。 然后or將這些結果放在一起,看看最終結果是否為0bnebeq針對$zero )如果是,則 3 個字節中的任何一個都沒有不匹配的位,因此條件為真。

第二種方式優化了 C 邏輯具有的短路評估。 請注意,在 C 表達式中,如果a[0] != 'a'甚至不會訪問a[1] ,因此即使a是指向頁面最后一個字節的指針,它也不會出錯,並且下一個頁面未映射。 (假設a[0] == 0或其他東西,一個空的以 0 結尾的字符串)。

但是,如果您確實知道可以安全地訪問字符串/數組的所有 3 個字節,那么這是一個選項。

當條件類似於if (x < 5 && y < 10)時,它作為優化更容易/更有效,您可以使用 2x slti指令實現以比較寄存器,並將這些 regs 放在一起,然后beq $t0, $zero, skip_if_body


在這種檢查 3 個連續字節的特殊情況下,它基本上是memcmp(a, "abc", 3)

如果你知道a是字對齊的,你可以做一個字加載來得到你想要的 3 個字節,加上一個我們需要忽略的垃圾字節。

MARS 模擬了一個 little-endian 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

或者如果我們有 2 字節 alignment,則lhu + lbu分別加載 16 位和 8 位; 如果我們仍然想合並一個分支,我們可以使用xori一次檢查 16 位,利用立即數的全寬。 或者只是使用li / beq

在寄存器中構造'abc' << 8需要 2 條指令( lui + addiuori

不,您只需執行兩個beq指令來考慮這兩種情況。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM