assembly Mips-装配工单和

tct7dpnv  于 2022-11-13  发布在  其他
关注(0)|答案(3)|浏览(127)

我有一个关于Mips条件语句的问题。我可以在beq中使用and运算符吗?例如,在C语言中,我可以写if(arr[0]=='a' && arr[1]=='b' && arr[2]=='c'),但在Mips汇编中,我如何写这样的代码呢?

kse8i1jr

kse8i1jr1#

从根本上说,我们将控制流与测试条件的逻辑结合起来。正如@Jester告诉你的,我们可以在C中做到/观察到这一点,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时分支,因此当条件为true时,我们无法分支并立即运行我们在条件测试后编写的then-part
因为我们是在条件为假的情况下进行分支,所以出于所有实际目的,我们用C语言以“if-goto”的形式编写:if (x!=y) goto ElseLabel;,然后是then-part翻译...
请参考以下帖子:

hec6srdp

hec6srdp2#

不,beq取2个寄存器并比较它们,就这样。记住,汇编语言反映了机器代码在一条指令中可以做什么。做一些更复杂的事情通常需要更多的指令。
要将&&多个条件组合在一起,你需要

  • 多个beq和/或bne指令;一串树枝
  • 或者在一个寄存器中创建一个值,该值代表分支前多个条件的逻辑与。例如,将所有3个字节和xori加载为'a''b''c'中的至少一个。(产生0进行匹配)。然后将这些结果or在一起,看看最终结果是否为0(使用bnebeq$zero)如果是,则在3个字节中的任何一个中都没有不匹配的位,因此条件为真。

第二种方法优化了C逻辑中的求值短路。注意,在C表达式中,如果a[0] != 'a',则甚至不访问a[1],因此即使a是指向页面最后一个字节的指针,并且下一个页面未Map,也不会出错。(假设a[0] == 0或类似的东西,一个以0结尾的空字符串)。
但是如果你 * 确实 * 知道你可以安全地访问字符串/数组的所有3个字节,这是一个选择。
当条件类似于if (x < 5 && y < 10)时,优化会更容易/更有效,您可以使用2x slti指令来实现该条件,以便在寄存器中进行比较,然后将这些寄存器进行AND运算,最后得到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)
因为andi不能对0x00FFFFFF进行编码,所以我将不需要的字节移出负载,而不是使用AND对其进行掩码。
如果不知道a是对齐的,那么对于未对齐的加载,可能值得使用lwl/lwr
或者lhu + lbu,如果我们有2字节对齐,则分别加载16位和8位;如果我们还想合并一个分支,我们可以用xori一次检查16位,利用立即数的全宽度,或者只用li/beq
在寄存器中构造'abc' << 8需要2条指令(lui + addiuori

8wigbo56

8wigbo563#

不,您只需执行两条beq指令就可以解决这两种情况。

相关问题