优化此汇编代码
我现在正在参加计算机体系结构课程,我们将回顾基本的R型和I型指令(也是RISC架构)等等。我似乎无法弄清楚如何优化这个码。
说明:该代码在数组中添加单词(由$ s1指向),直到达到零。 结果存储在$ t1中。 $ t0包含当前单词。
add $t1, $zero, $zero # Initialize result to zero
again:
lw $t0, 0($s1) # Load the word from the array
beq $t0, $zero, done # Terminate if current word is a zero
add $t1, $t1, $t0 # Add current word to result
addi $s1, $s1, 4 # Point to the next word in the array
beq $t1, $t1, again # Loop again
done:
nop # Do nothing
我在优化代码方面遇到了困难。 我beq $t1, $t1, again
感受到beq $t1, $t1, again
(因为它总是真的)是不必要的,但我不知道如何删除它。 这是我的尝试,但我现在意识到我的代码不会终止。
add $t1, $zero, $zero # Initialize result to zero
again:
lw $t0, 0($s1) # Load the word from the array
add $t1, $t1, $t0 # Add current word to result
addi $s1, $s1, 4 # Point to the next word in the array
bne $t1, $zero, again # If result is not zero, loop
done:
nop # Do nothing
我从不检查终止零点并跳转到完成状态。 但是如果我再添加一张支票,那么代码是否与以前一样?
通常,您想要将顶部循环的测试转换为底部循环的测试。 要做到这一点,你经常需要跳到(或多或少)第一次迭代的循环体中间。 在伪代码中,你现在所拥有的基本上是:
initialize sum
beginning:
load a word
if (done) goto end
add to sum
increment pointer
goto beginning
end:
为了优化,我们希望将结构更改为如下所示:
initialize sum
goto start_loop
beginning:
add to sum
increment pointer
start_loop:
load a word
if (!done) goto beginning
这样每个循环只有一个跳转而不是两个(这是一个很短的向后跳转,因此目标几乎总是在缓存中)。
也就是说,我应该补充一点,这种优化实际上已经过时 - 通过合适的分支预测,无条件跳转通常基本上是免费的。
编辑:由于循环展开已被提及,我会添加我的两分钱。 分支预测通常会使循环展开过时,除非您可以使用它来并行执行更多指令。 这不是一个问题,但在现实生活中通常很有用。 例如,如果我们假设CPU有两个独立的加法器,我们可以展开循环的两个迭代,并将这些迭代的结果添加到两个单独的目标寄存器中,所以我们利用两个加法器的相同优势时间。 然后,当循环终止时,我们将这两个寄存器相加以得到最终值。 在类似C的伪代码中,会出现这样的情况:
odds = 0
evens = 0
do {
evens += pointer[0];
odds += pointer[1];
pointer += 2;
while (pointer[0] && pointer[1]);
total = odds + evens;
正如所写的,这增加了两个连续的零的小额外要求来终止序列而不是一个,并且要添加的数组中至少有两个项目。 但是,请注意,这不是真正的循环展开,它提供了这里的主要优点,而是并行执行。
没有这一点,如果一个没有被采用的分支比一个被采用的分支便宜(即使两者都被正确预测),我们真的只能看到循环展开的好处。 在较早的分支机构(例如,较早的英特尔公司),分支机构相对于未采用的分支机构处罚。 与此同时,展开的循环将使用更多的缓存空间。 因此,在现代处理器上,它通常是一个全面的损失(除非像我之前所说的那样,我们可以使用展开来获得并行性)。
展开你的循环:
add $t1, $zero, $zero # Initialize result to zero
again:
lw $t0, 0($s1) # Load the word from the array
beq $t0, $zero, done # Terminate if current word is a zero
add $t1, $t1, $t0 # Add current word to result
addi $s1, $s1, 4 # Point to the next word in the array
lw $t0, 0($s1) # Load the word from the array
beq $t0, $zero, done # Terminate if current word is a zero
add $t1, $t1, $t0 # Add current word to result
addi $s1, $s1, 4 # Point to the next word in the array
lw $t0, 0($s1) # Load the word from the array
beq $t0, $zero, done # Terminate if current word is a zero
add $t1, $t1, $t0 # Add current word to result
addi $s1, $s1, 4 # Point to the next word in the array
lw $t0, 0($s1) # Load the word from the array
beq $t0, $zero, done # Terminate if current word is a zero
add $t1, $t1, $t0 # Add current word to result
addi $s1, $s1, 4 # Point to the next word in the array
# and so on to a reasonable amount, 4-8 times are common.
b again # Loop again
done:
nop
链接地址: http://www.djcxy.com/p/10355.html