MIPS 中的嵌套循环演示
Nested Loop Demonstration in MIPS
我在这个网站上找到了一个代码片段作为问题的答案。该代码使用 MIPS 中的嵌套循环。
代码如下:
.data
prompt: .asciiz "Please enter the edge length of the base of right
triangle: "
newLine: .asciiz "\n"
star: .asciiz "*"
.text
main:
li $v0, 4 # print the prompt
la $a0, prompt
syscall
li $v0,5 #take user input
syscall
move $s0, $v0 # move the input to $s0
li $t0, 0 # load 0 at t0
outerLoop:
beq $t0, $s0, end #(for i=0;i<=baseLength;i++)
#if t0=s0 branch to end
addi $t0, $t0, 1 # increment i
li $t1, 1 #load 1 at t1
jal changeLine #jump to changeLine
innerLoop:
bgt $t1, $t0, outerLoop #(for j=0;j<=i;j++)
# if t1=t0 branch to outerLoop
li $v0, 4 # print star
la $a0, star
syscall
addi $t1, $t1, 1 # increment j
j innerLoop # jump to innerLoop
changeLine:
li $v0, 4 # new line
la $a0, newLine
syscall
jr $ra # jump to after the call instruction
end:
li $v0, 10 # end of program
syscall
代码运行完美,但我无法理解外循环是如何迭代的,即使没有像 j outerLoop
.
这样的显式命令
感谢任何帮助。
答案是innerLoop的第一条语句:
innerLoop:
bgt $t1, $t0, outerLoop #(for j=0;j<=i;j++)
# if t1=t0 branch to outerLoop
当innerLoop的总迭代次数结束时,代码跳回到outerLoop标签。
事情是这样的:外循环已经被“优化”,不再直接反映评论中所述的 for 循环。 C 等价物看起来更像这样:
for ( i = 0; i <= baseLength; /* empty increment */ ) {
i++;
<loop-body> // includes inner loop
}
通常是这样的 for 循环:
for ( i = 0; i < N; i++ ) { <loop-body> }
根据 for 循环结构的定义,将展开如下:
i = 0;
while ( i < N ) {
<loop-body>
i++;
}
但是,如您所见,在您显示的代码中,i++
增量已从 loop-body
之后移动到 loop-body
之前。
因此,在执行完内循环后,外循环没有增量代码执行——因此,内循环的退出位置可以直接从top继续外循环。
但是,在进行这些更改时,我们必须小心 b/c 现在 loop-body
执行时 i
的值比翻译自的 C 代码大 1现在显示在评论中。如果 i
在 loop-body
中使用,这是一个问题。
而这里i
确实是在循环体内使用的,作为内循环迭代控制的一部分。因为i
大了一个,所以这个内循环会比注释中写的C代码多迭代一次。
如果没有应用“优化”,内循环可能会通过向前跳到属于外循环的 i++
增量退出,然后 j outerLoop
(向后跳) 如您所料,继续外循环。
初级汇编程序员通常热衷于修改他们在翻译成汇编期间开始使用的 C 代码或伪代码,但这些更改通常是在不了解它们在逻辑上或算法上不等效的情况下完成的。例如,将 while 循环更改为 do-while 循环;将数组引用更改为指针操作——在这种情况下更改操作顺序。由于 C 可以表达所有这些(do-while、指针等)我主张首先在 C 中进行优化,然后验证等效行为,并将其用于汇编。
是的,还有其他优化仅在汇编中有意义(即在 C 中不可能或不实用),但建议将这些优化留到效率是主要主题时,直到那时遵循 C 起始代码而不是字面意思。
我在这个网站上找到了一个代码片段作为问题的答案。该代码使用 MIPS 中的嵌套循环。
代码如下:
.data
prompt: .asciiz "Please enter the edge length of the base of right
triangle: "
newLine: .asciiz "\n"
star: .asciiz "*"
.text
main:
li $v0, 4 # print the prompt
la $a0, prompt
syscall
li $v0,5 #take user input
syscall
move $s0, $v0 # move the input to $s0
li $t0, 0 # load 0 at t0
outerLoop:
beq $t0, $s0, end #(for i=0;i<=baseLength;i++)
#if t0=s0 branch to end
addi $t0, $t0, 1 # increment i
li $t1, 1 #load 1 at t1
jal changeLine #jump to changeLine
innerLoop:
bgt $t1, $t0, outerLoop #(for j=0;j<=i;j++)
# if t1=t0 branch to outerLoop
li $v0, 4 # print star
la $a0, star
syscall
addi $t1, $t1, 1 # increment j
j innerLoop # jump to innerLoop
changeLine:
li $v0, 4 # new line
la $a0, newLine
syscall
jr $ra # jump to after the call instruction
end:
li $v0, 10 # end of program
syscall
代码运行完美,但我无法理解外循环是如何迭代的,即使没有像 j outerLoop
.
感谢任何帮助。
答案是innerLoop的第一条语句:
innerLoop:
bgt $t1, $t0, outerLoop #(for j=0;j<=i;j++)
# if t1=t0 branch to outerLoop
当innerLoop的总迭代次数结束时,代码跳回到outerLoop标签。
事情是这样的:外循环已经被“优化”,不再直接反映评论中所述的 for 循环。 C 等价物看起来更像这样:
for ( i = 0; i <= baseLength; /* empty increment */ ) {
i++;
<loop-body> // includes inner loop
}
通常是这样的 for 循环:
for ( i = 0; i < N; i++ ) { <loop-body> }
根据 for 循环结构的定义,将展开如下:
i = 0;
while ( i < N ) {
<loop-body>
i++;
}
但是,如您所见,在您显示的代码中,i++
增量已从 loop-body
之后移动到 loop-body
之前。
因此,在执行完内循环后,外循环没有增量代码执行——因此,内循环的退出位置可以直接从top继续外循环。
但是,在进行这些更改时,我们必须小心 b/c 现在 loop-body
执行时 i
的值比翻译自的 C 代码大 1现在显示在评论中。如果 i
在 loop-body
中使用,这是一个问题。
而这里i
确实是在循环体内使用的,作为内循环迭代控制的一部分。因为i
大了一个,所以这个内循环会比注释中写的C代码多迭代一次。
如果没有应用“优化”,内循环可能会通过向前跳到属于外循环的 i++
增量退出,然后 j outerLoop
(向后跳) 如您所料,继续外循环。
初级汇编程序员通常热衷于修改他们在翻译成汇编期间开始使用的 C 代码或伪代码,但这些更改通常是在不了解它们在逻辑上或算法上不等效的情况下完成的。例如,将 while 循环更改为 do-while 循环;将数组引用更改为指针操作——在这种情况下更改操作顺序。由于 C 可以表达所有这些(do-while、指针等)我主张首先在 C 中进行优化,然后验证等效行为,并将其用于汇编。
是的,还有其他优化仅在汇编中有意义(即在 C 中不可能或不实用),但建议将这些优化留到效率是主要主题时,直到那时遵循 C 起始代码而不是字面意思。