我想将 while(w [i] == x)i + = j; 转换为MIPS汇编代码。 假设INTEGERS i,j和x分别为3美元,4美元和5美元。还假设在while循环之前最初i = 0。 w =>整数数组及其基地址存储在$ 6中。到目前为止,我有这个。
Loop:
sll $10, $3, 2 # $10 = i* 4
add $10, $6, $10 # $10 has address of w[i]
lw $11, 0($10) # $11 = w[i]
bne $11, $5, Exit # exit from loop if w[i]!= x
add $3, $3, $4 # i= i+ j
j Loop
Exit:
是否可以通过j * 4移动基址本身来优化此代码,并且还可以删除多个分支指令?因为我不清楚如何做到这一点。
提前致谢!
答案 0 :(得分:0)
为了摆脱多分支指令,可以使用这个技巧:
警告:不完全等同于您的代码
Loop:
sll $10, $3, 2 # $10 = i* 4
add $10, $6, $10 # $10 has address of w[i]
lw $11, 0($10) # $11 = w[i]
add $3, $3, $4 # i = i + j
beq $11, $5, Loop # keep looping if w[i] == x
Exit:
sub $3, $3, $4 # i = i - j
诀窍是在测试保持循环之前执行i += j
这确实会引入一个问题:当你的代码没有时,可能会触发一个额外的整数溢出。
这就像重写一样:
while (some_condition())
do_something();
进入这个:
do
do_something();
while (some_condition());
undo_something();
好吧,让我试着“这次用j * 4将指针从基地址移动”:)
Start:
sll $11, $3, 2 # $11 = i * 4
add $10, $11, $6 # Let $10 be a "cursor" pointing to w[i]
Loop:
lw $11, 0($10) # $11 = w[i]
sll $12, $4, 2 # $12 = j * 4
add $10, $10, $12 # update $10 by 4 * j
add $3, $3, $4 # update i by j
beq $11, $5, Loop # keep looping if w[i] == x
Exit:
sub $3, $3, $4 # i = i - j
然而,它并没有比上面给出的版本更优化:它们都在循环体内使用了5条指令。
答案 1 :(得分:0)
为了使比较更容易,我写了一个小的虚函数:
#include <stdint.h>
#include <stdlib.h>
uint32_t fun1(uint32_t const *in, uint32_t cmp, size_t j)
{
size_t i = 0;
while (in[i] == cmp)
{
i += j;
}
return in[i];
}
这可以编译,输出可以与等效函数进行比较:
uint32_t fun2(uint32_t const *in, uint32_t cmp, size_t j)
{
while (*in == cmp)
{
in += j;
}
return *in;
}
对于两个函数,gcc
(x86-64上的4.8)生成一个只有4条指令的循环。
对于第二个功能,它基本上是:
temp1 = (in)
compare temp1, cmp
if not equal, return temp1
temp2 = j*sizeof(uint32_t)
loop:
in += temp2 #\
temp1 = (in) # \
compare temp1, cmp # - 4 instructions loop
if equal, goto loop # /
return temp1
这样的伪装配可以像MIPS
那样实现:
lw $v0, 0($a0)
beq $a1, $v0, end
sll $t1, $a2, 2
loop:
add $a0, $a0, $t1 #\
lw $v0, 0($a0) # - only 3 instructions in loop, due to test-and-branch
bne $a1, $v0, loop #/
end:
jr $ra