在 MIPS 中声明整数值
Declaring integer values in MIPS
所以我正在编写一个汇编程序,它有很多常量整数值。
我知道在 .data 部分我可以分配一个 .word 数据类型的标签并输入我的号码。使用这种方法我仍然必须在main中加载一个地址。
但在主要方面,我可以简单地使用
li $t1, some_number
这些方法中有哪一种比另一种更好吗?为什么?
一般来说,我会说使用 li
是更好的方法。您避免在 .data
部分添加一堆混乱,并且在某些情况下您还将获得更高效的代码。
让我们看一些例子:
.data
ten: .word 10
million: .word 1000000
.text
main:
lw $t0,ten
li $t1,10
lw $t2,million
li $t3,1000000
重要的是要了解 lw
和 li
都是 伪指令,它们被翻译成一个或多个实际指令。 lw
是否存在于 MIPS 指令集中,但它的这个特定变体不存在。 li
MIPS 指令集中不存在。
如果我们查看 SPIM 为前两条指令生成的内容,我们会看到:
[0x00400024] 0x3c011001 lui , 4097 ; 9: lw $t0,ten
[0x00400028] 0x8c280000 lw , 0()
[0x0040002c] 0x3409000a ori , [=11=], 10 ; 10: li $t1,10
所以这是 lw
变体的一条附加指令,因为地址首先必须加载到寄存器中,然后从该地址加载值。这也意味着一次额外的(可能很慢)内存访问(好吧,如果算上指令获取,则为两次)。
现在让我们看看另外两条指令,其中要加载的值太大而无法在一条指令中编码:
[0x00400030] 0x3c011001 lui , 4097 ; 11: lw $t2,million
[0x00400034] 0x8c2a0004 lw , 4()
[0x00400038] 0x3c01000f lui , 15 ; 12: li $t3,1000000
[0x0040003c] 0x342b4240 ori , , 16960
此处使用两条指令加载立即数 1000000,如 (15 << 16) | 16960
。所以这两种变体都需要两条指令,但是 li
变体不需要从内存中读取。
如果您想为常量分配一个有意义的名称以避免在您的代码中出现幻数,您可以使用 =
:
TEN = 10
li $t0, TEN # Expands to li $t0, 10
您也许可以通过使用 $gp
-相对寻址来避免一直加载 lw
的地址,但我觉得这超出了范围这个问题。
所以我正在编写一个汇编程序,它有很多常量整数值。
我知道在 .data 部分我可以分配一个 .word 数据类型的标签并输入我的号码。使用这种方法我仍然必须在main中加载一个地址。
但在主要方面,我可以简单地使用
li $t1, some_number
这些方法中有哪一种比另一种更好吗?为什么?
一般来说,我会说使用 li
是更好的方法。您避免在 .data
部分添加一堆混乱,并且在某些情况下您还将获得更高效的代码。
让我们看一些例子:
.data
ten: .word 10
million: .word 1000000
.text
main:
lw $t0,ten
li $t1,10
lw $t2,million
li $t3,1000000
重要的是要了解 lw
和 li
都是 伪指令,它们被翻译成一个或多个实际指令。 lw
是否存在于 MIPS 指令集中,但它的这个特定变体不存在。 li
MIPS 指令集中不存在。
如果我们查看 SPIM 为前两条指令生成的内容,我们会看到:
[0x00400024] 0x3c011001 lui , 4097 ; 9: lw $t0,ten
[0x00400028] 0x8c280000 lw , 0()
[0x0040002c] 0x3409000a ori , [=11=], 10 ; 10: li $t1,10
所以这是 lw
变体的一条附加指令,因为地址首先必须加载到寄存器中,然后从该地址加载值。这也意味着一次额外的(可能很慢)内存访问(好吧,如果算上指令获取,则为两次)。
现在让我们看看另外两条指令,其中要加载的值太大而无法在一条指令中编码:
[0x00400030] 0x3c011001 lui , 4097 ; 11: lw $t2,million
[0x00400034] 0x8c2a0004 lw , 4()
[0x00400038] 0x3c01000f lui , 15 ; 12: li $t3,1000000
[0x0040003c] 0x342b4240 ori , , 16960
此处使用两条指令加载立即数 1000000,如 (15 << 16) | 16960
。所以这两种变体都需要两条指令,但是 li
变体不需要从内存中读取。
如果您想为常量分配一个有意义的名称以避免在您的代码中出现幻数,您可以使用 =
:
TEN = 10
li $t0, TEN # Expands to li $t0, 10
您也许可以通过使用 $gp
-相对寻址来避免一直加载 lw
的地址,但我觉得这超出了范围这个问题。