繁体   English   中英

循环遍历阵列时,MIPS组装

[英]While loop through array, MIPS assembly

我想转换(w [i] == x)i + = j; 转换为MIPS汇编代码。 假设整数i,j和x在$ 3,$ 4和$ 5中。 还要假设i = 0最初在while循环之前。 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来优化此代码,并摆脱多条分支指令? 因为我不知道该怎么做。

提前致谢!

为了摆脱多个分支指令,可以使用以下技巧:
警告:不完全等同于您的代码

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条指令。

为了使比较容易,我编写了一个小的虚拟函数:

#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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM