【问题标题】:Mips-Assembly beq andMips-Assembly beq 和
【发布时间】:2019-10-28 21:30:57
【问题描述】:

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

【问题讨论】:

  • 用 C 中的单个条件 ifgoto 重写。如果你能做到这一点,你可以在汇编中遵循相同的逻辑。或者,画一个流程图(这里也是单个条件)。提示:尝试否定条件

标签: assembly mips


【解决方案1】:

从根本上说,我们将控制流与我们正在测试的条件的逻辑相结合。正如@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,在该条件为false时,我们围绕then-part 和@987654331 进行分支@。由于我们在条件 false 上进行分支,因此当条件为 true 时,我们无法分支并运行我们在条件测试后立即编程的 then-part

由于我们在条件 false 上进行分支,因此出于所有实际目的,我们以 C 中的“if-goto”样式编写:if (x!=y) goto ElseLabel;,然后是 then-part 翻译...


供参考,请参阅以下帖子:

【讨论】:

    【解决方案2】:

    不,beq 需要 2 个寄存器并比较它们,仅此而已。请记住,汇编语言反映了机器代码在一条指令中可以做什么。做更复杂的事情通常需要更多的指令。

    要将&&多个条件加在一起,你需要任一

    • 多个beq 和/或bne 指令;一串树枝

    • 或在一个寄存器中创建一个值,该值表示分支前多个条件的逻辑和。例如,分别用'a''b''c' 加载所有3 个字节和xori。 (为匹配生成0)。然后or 将这些结果放在一起,看看最终结果是否为0(带有bnebeq$zero)如果是这样,则3 个字节中的任何一个都没有不匹配的位,所以条件是是的。

    第二种方式优化了 C 逻辑具有的短路评估。请注意,在 C 表达式中,如果 a[0] != 'a' 甚至不会访问 a[1],因此即使 a 是指向页面最后一个字节的指针并且下一页未映射,它也不会出错。 (假设a[0] == 0 或其他东西,一个以0 结尾的空字符串)。

    但如果你确实知道你可以安全地访问字符串/数组的所有 3 个字节,这是一个选项。

    当条件类似于 if (x < 5 && y < 10) 时,作为优化更容易/更有效,您可以使用 2x slti 指令来比较寄存器,然后将这些 reg 放在一起,然后 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 可能值得使用。

    或者lhu+lbu分别加载16位和8位,如果我们有2字节对齐;如果我们仍然想合并一个分支,我们可以使用xori 一次检查 16 位,利用立即数的全宽。或者只是li/beq

    在寄存器中构造 'abc' &lt;&lt; 8 需要 2 条指令(lui + addiuori

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-03
      • 1970-01-01
      • 2012-12-15
      • 1970-01-01
      • 2014-03-04
      • 2011-11-03
      • 2020-10-23
      • 2021-04-07
      相关资源
      最近更新 更多