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现在显示在评论中。如果 iloop-body 中使用,这是一个问题。

而这里i确实是在循环体内使用的,作为内循环迭代控制的一部分。因为i大了一个,所以这个内循环会比注释中写的C代码多迭代一次。

如果没有应用“优化”,内循环可能会通过向前跳到属于外循环的 i++ 增量退出,然后 j outerLoop(向后跳) 如您所料,继续外循环。


初级汇编程序员通常热衷于修改他们在翻译成汇编期间开始使用的 C 代码或伪代码,但这些更改通常是在不了解它们在逻辑上或算法上不等效的情况下完成的。例如,将 while 循环更改为 do-while 循环;将数组引用更改为指针操作——在这种情况下更改操作顺序。由于 C 可以表达所有这些(do-while、指针等)我主张首先在 C 中进行优化,然后验证等效行为,并将其用于汇编。

是的,还有其他优化仅在汇编中有意义(即在 C 中不可能或不实用),但建议将这些优化留到效率是主要主题时,直到那时遵循 C 起始代码而不是字面意思。