# 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
3条答案
按热度按时间kse8i1jr1#
从根本上说,我们将控制流与测试条件的逻辑结合起来。正如@Jester告诉你的,我们可以在C中做到/观察到这一点,C通常比汇编更适合这些转换。
您可以看到:
if(arr[0]=='a' && arr[1]=='b' && 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
翻译...请参考以下帖子:
hec6srdp2#
不,
beq
取2个寄存器并比较它们,就这样。记住,汇编语言反映了机器代码在一条指令中可以做什么。做一些更复杂的事情通常需要更多的指令。要将
&&
多个条件组合在一起,你需要beq
和/或bne
指令;一串树枝xori
加载为'a'
、'b'
和'c'
中的至少一个。(产生0
进行匹配)。然后将这些结果or
在一起,看看最终结果是否为0
(使用bne
或beq
对$zero
)如果是,则在3个字节中的任何一个中都没有不匹配的位,因此条件为真。第二种方法优化了C逻辑中的求值短路。注意,在C表达式中,如果
a[0] != 'a'
,则甚至不访问a[1]
,因此即使a
是指向页面最后一个字节的指针,并且下一个页面未Map,也不会出错。(假设a[0] == 0
或类似的东西,一个以0结尾的空字符串)。但是如果你 * 确实 * 知道你可以安全地访问字符串/数组的所有3个字节,这是一个选择。
当条件类似于
if (x < 5 && y < 10)
时,优化会更容易/更有效,您可以使用2xslti
指令来实现该条件,以便在寄存器中进行比较,然后将这些寄存器进行AND运算,最后得到beq $t0, $zero, skip_if_body
在此特殊情况下,您要检查3个连续字节,基本上是
memcmp(a, "abc", 3)
。如果你知道
a
是字对齐的,你可以执行一个字加载来得到你想要的3个字节,加上一个我们需要忽略的垃圾字节。MARS模拟一个小端MIPS系统,所以我们想要的3个字节是字中最低有效的3个字节。(通常MIPS可以运行为大端或小端。)
当然,如果
a
实际上是一个已知为字对齐的寄存器中的指针,也可以使用此方法。lw $t0, ($a0)
。因为
andi
不能对0x00FFFFFF
进行编码,所以我将不需要的字节移出负载,而不是使用AND对其进行掩码。如果不知道
a
是对齐的,那么对于未对齐的加载,可能值得使用lwl
/lwr
。或者
lhu
+lbu
,如果我们有2字节对齐,则分别加载16位和8位;如果我们还想合并一个分支,我们可以用xori
一次检查16位,利用立即数的全宽度,或者只用li
/beq
。在寄存器中构造
'abc' << 8
需要2条指令(lui + addiu
或ori
)8wigbo563#
不,您只需执行两条
beq
指令就可以解决这两种情况。