[英]C to MIPS assembly while loop
C语言
while (save[i] == k)
i += 1;
i→ $s3
k → $s5
base addr of save → $s6
sll $t1, $s3, 2 #$t1 = 4*$s3
add $t1, $t1, $s6 #$t1 = address of save[i]
lw $t0, 0($t1) #t0 = save[i]
bne $t0, $s5, Exit #$t0!=$s5 Exit
Loop: addi $s3, $s3, 1 #i+=1
addi $t1, $t1, 4 #point to next cell
lw $t0, 0($t1) #t0 = save[i]
beq $t0, $s5, Loop #$t0==$s5 loop again
Exit:
我想问的是,是否需要addi $s3, $s3, 1行?
因为,无论如何 $ t1 增加了 4。
C 代码和汇编代码实际上不匹配。 汇编代码已被优化为使用指针而不是数组引用,并且循环的退出条件也已在循环外复制一次,从而允许循环结构使用更有效的 do while 循环(在迭代期间更有效,因为它与 while 循环的直接代码相比,在末尾保存了一个无条件分支)。
请注意,这些优化不仅在装配中是可能的,而且在 C 中也是可行的。
C版本总成如下:
int *sp = save + i; // in C this addition is automatically scaled by 4
if ( *sp == k ) {
do {
i++;
sp++; // this C +1 is scaled so really is +4
} while ( *sp == k );
}
当然,这在逻辑上等价于另一个。
你的问题是:我们需要i++;
?
一个答案是:不,不在循环中。 您是正确的,循环不使用i
并且会访问数组的相同元素,并在与原始更简单的 C 循环相同的点退出。
另一个答案是:是的,如果在循环之后使用i
! 这个循环做的很少,但会检查一些 memory。 我们不得不问:循环的目的是什么,如果不是为循环后面的一些代码设置i
? 在这里,循环的目的可能是计算重复项,这将导致i
成为循环的“输出”/所需结果:在结束时包含重复项的计数,然后运行下一条语句。
这就是为什么很难对一小段代码进行推理的原因之一——本质上我们无法判断接下来会发生什么以及是否会使用i
。 但是如果i
没有被使用,那么循环就没有价值了..
如果我们尝试将其放入编译器中,我们将被迫将代码片段更改为完整的 function。 编译器不会接受小于 function 的代码语句。
整个 function 定义是您可以提供给编译器的最小代码段(function 定义之外的代码片段不是 C 语言中的合法声明,并且环境为代码片段提供了清晰的包装)
(当然也有副作用,例如排序比 function 更持久的东西,或者创建比 function 更持久的堆对象。)
包裹在 function 中,然后我们可以确定地观察循环后是否使用了局部变量i
。
当然,还有另一种方法可以在循环之后计算i
的值,而无需在循环期间增加它。 在循环之后,以下语句将恢复i
应该拥有的值:
i = sp - save; // NB: C pointer subtraction automatically descales
在汇编中,这将是减法,然后右移 2 以从字节差值到 integer 索引值去缩放。
(请注意,这些优化和转换很容易被淘汰,因此请检查工作。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.