如何在 MIPS 32 的 for 循环中使用 set if less than (SLT) 语句?
How to use the set if less than (SLT) statement in a for-loop in MIPS 32?
我正在做一些家庭作业,我的问题是我应该在此 for 循环程序集中包含 SLT(如果小于则设置)行,但我不确定该怎么做。我发现 this question 有帮助,但我不能使用 BLT (branch if less than) 语句,教授确实介绍了宏,但这个问题指定使用 SLT。我最终只是在我的作业陈述中使用了它,但我觉得这几乎不能满足教授的要求,这里是陈述:slt $t2, $t0, $t1 #t2 holds y = 1 if i < x
。它根本不适合代码,它没有任何用途我觉得它应该与 for 循环有关,有什么建议吗?
这是程序集代表的基本 for 循环:
for (i=0; i<x; i++)
y = y * 2;
这是 MIPS 32 中的汇编代码:
.text
.globl main
main:
li $t1, 7 #test val num of iterations, x = 7
li $t0, 0 #t0 is our counter i = 0
#li $t2, 1 #another way to assign y = 1
slt $t2, $t0, $t1 #t2 holds y = 1 if i < x
loop:
beq $t0, $t1, end #if (i)t0 == (x)7 end loop
add $t2, $t2, $t2 #body, y = y * 2
addi $t0, $t0, 1 #add 1 to i, t0
j loop #jump back to the top
end:
li $v0, 10
syscall
你是对的,slt
不用于循环控制的目的,因为它不参与循环。
条件 i<x
是一个动态条件,作为循环迭代的一部分,因为 i
每次迭代都会改变。
如果您单步调试它,您可能已经注意到了这个缺陷。
但一个问题是您没有使用出色的伪代码,因为 y
从未被初始化。我们仍然可以使用它,但请注意,您已选择以某种不属于给定伪代码的方式初始化 y
。
您用汇编语言编写的内容具有等效的伪代码:
y = i < x; // bad: outside the loop and modifying y
for (i=0; i!=x; i++) // bad: using condition i!=x
y = y + y; // good: valid for y = y * 2;
你能看出这个伪代码和原来的不一样的几个地方吗? y
被初始化为原始值中没有的东西,并且循环退出条件 i!=x
与原始值不同。此伪代码在逻辑上不等价,不会 运行 与原始代码相同。
让我们从更基本的原则和逻辑转换出发,这样您就可以看到一些问题:
for (i=0; i<x; i++)
y = y * 2;
我们首先将这个 for 循环转换为等效的 while 循环,因为 while 循环更明确:
i = 0;
while ( i < x ) {
y = y * 2;
i++;
}
接下来,我们再次将此 while 循环转换为汇编语言的 if-goto-label 样式,因为这更加明确,并且每一步都使我们更接近汇编语言。您将真正开始了解循环中的内容和不在循环中的内容,即使这仍然是伪代码(仅供参考,C 中允许使用此 if-goto-label)。
i = 0;
loop1:
if ( ! (i < x) ) goto loop1Done; // Exit loop when i < x is false
y = y * 2;
i++;
goto loop1;
loop1Done:
首先要注意的是,在汇编语言的 if-goto-label 风格中,如果我们希望程序做其他事情,我们使用 if-goto。希望您能看到,作为 if-goto 语义的结果,自然操作是告诉处理器何时退出循环——而不是像 C 中所做的那样何时留在循环中——因此对条件(MIPS 可以通过多种方式处理)。
接下来,我们可以清楚地看到循环内部需要关系运算i < x
(及其否定),因此必须在循环的每次迭代中重复。
操作 if ( ! (i < x) ) goto ...
是合法的 C 代码,但可以在伪代码中重述为:if ( i < x is false ) goto ...
.
slt
可以按照你在$t0
中用操作数i
和$t1
中的x
描述的那样使用,所以那部分很好,但是结果需要转到一个新的临时寄存器,而不是破坏原始值 y
(原始伪代码中未指定)。让我们想象一下使用 $t10
作为这个临时替代方案。因此,slt $t10, $t0, $t1
,并注意它 在循环中的位置 。
现在测试条件测试的条件分支部分。我们要测试 i<x
比较的结果是否为假,如果是则分支退出循环。这样的分支需要测试 $t10
,因为它保存了 slt
的 i<x
的结果,并且为了测试这个布尔值是否为假,我们将使用 beq $t10 [=36=] loop1Done
,它表示如果$t10
等于 false([=38=]
始终为 false)然后执行退出循环的 goto/branch。
作为 reader 的练习,完成从 if-goto-label pseudo/C 代码到汇编代码的逻辑转换。
还要从上面的讨论中注意到,您的原始伪代码并不是独立存在的:y
的初始化是必要的,因此为了实际 运行 这个 MIPS 转换代码,您需要将不得不添加这样的初始化(如果 y
的寄存器恰好是 0,因为模拟器会初始化它,那么循环将是最没有意义的,因为 y = 0 * 2 不会重复做任何不同的事情)。
我正在做一些家庭作业,我的问题是我应该在此 for 循环程序集中包含 SLT(如果小于则设置)行,但我不确定该怎么做。我发现 this question 有帮助,但我不能使用 BLT (branch if less than) 语句,教授确实介绍了宏,但这个问题指定使用 SLT。我最终只是在我的作业陈述中使用了它,但我觉得这几乎不能满足教授的要求,这里是陈述:slt $t2, $t0, $t1 #t2 holds y = 1 if i < x
。它根本不适合代码,它没有任何用途我觉得它应该与 for 循环有关,有什么建议吗?
这是程序集代表的基本 for 循环:
for (i=0; i<x; i++)
y = y * 2;
这是 MIPS 32 中的汇编代码:
.text
.globl main
main:
li $t1, 7 #test val num of iterations, x = 7
li $t0, 0 #t0 is our counter i = 0
#li $t2, 1 #another way to assign y = 1
slt $t2, $t0, $t1 #t2 holds y = 1 if i < x
loop:
beq $t0, $t1, end #if (i)t0 == (x)7 end loop
add $t2, $t2, $t2 #body, y = y * 2
addi $t0, $t0, 1 #add 1 to i, t0
j loop #jump back to the top
end:
li $v0, 10
syscall
你是对的,slt
不用于循环控制的目的,因为它不参与循环。
条件 i<x
是一个动态条件,作为循环迭代的一部分,因为 i
每次迭代都会改变。
如果您单步调试它,您可能已经注意到了这个缺陷。
但一个问题是您没有使用出色的伪代码,因为 y
从未被初始化。我们仍然可以使用它,但请注意,您已选择以某种不属于给定伪代码的方式初始化 y
。
您用汇编语言编写的内容具有等效的伪代码:
y = i < x; // bad: outside the loop and modifying y
for (i=0; i!=x; i++) // bad: using condition i!=x
y = y + y; // good: valid for y = y * 2;
你能看出这个伪代码和原来的不一样的几个地方吗? y
被初始化为原始值中没有的东西,并且循环退出条件 i!=x
与原始值不同。此伪代码在逻辑上不等价,不会 运行 与原始代码相同。
让我们从更基本的原则和逻辑转换出发,这样您就可以看到一些问题:
for (i=0; i<x; i++)
y = y * 2;
我们首先将这个 for 循环转换为等效的 while 循环,因为 while 循环更明确:
i = 0;
while ( i < x ) {
y = y * 2;
i++;
}
接下来,我们再次将此 while 循环转换为汇编语言的 if-goto-label 样式,因为这更加明确,并且每一步都使我们更接近汇编语言。您将真正开始了解循环中的内容和不在循环中的内容,即使这仍然是伪代码(仅供参考,C 中允许使用此 if-goto-label)。
i = 0;
loop1:
if ( ! (i < x) ) goto loop1Done; // Exit loop when i < x is false
y = y * 2;
i++;
goto loop1;
loop1Done:
首先要注意的是,在汇编语言的 if-goto-label 风格中,如果我们希望程序做其他事情,我们使用 if-goto。希望您能看到,作为 if-goto 语义的结果,自然操作是告诉处理器何时退出循环——而不是像 C 中所做的那样何时留在循环中——因此对条件(MIPS 可以通过多种方式处理)。
接下来,我们可以清楚地看到循环内部需要关系运算i < x
(及其否定),因此必须在循环的每次迭代中重复。
操作 if ( ! (i < x) ) goto ...
是合法的 C 代码,但可以在伪代码中重述为:if ( i < x is false ) goto ...
.
slt
可以按照你在$t0
中用操作数i
和$t1
中的x
描述的那样使用,所以那部分很好,但是结果需要转到一个新的临时寄存器,而不是破坏原始值 y
(原始伪代码中未指定)。让我们想象一下使用 $t10
作为这个临时替代方案。因此,slt $t10, $t0, $t1
,并注意它 在循环中的位置 。
现在测试条件测试的条件分支部分。我们要测试 i<x
比较的结果是否为假,如果是则分支退出循环。这样的分支需要测试 $t10
,因为它保存了 slt
的 i<x
的结果,并且为了测试这个布尔值是否为假,我们将使用 beq $t10 [=36=] loop1Done
,它表示如果$t10
等于 false([=38=]
始终为 false)然后执行退出循环的 goto/branch。
作为 reader 的练习,完成从 if-goto-label pseudo/C 代码到汇编代码的逻辑转换。
还要从上面的讨论中注意到,您的原始伪代码并不是独立存在的:y
的初始化是必要的,因此为了实际 运行 这个 MIPS 转换代码,您需要将不得不添加这样的初始化(如果 y
的寄存器恰好是 0,因为模拟器会初始化它,那么循环将是最没有意义的,因为 y = 0 * 2 不会重复做任何不同的事情)。