MIPS 如何存储大于 32 位的数字?
How does MIPS store a number larger than 32 bits?
我一直在寻找这个问题的答案,但找不到明确的答案。它会在多个寄存器之间拆分数字还是不能简单地处理它?
我尝试使用 MARS 对其进行测试,并使用数字 4294967296,即 0x100000000,但寄存器只保存了 0x00000000,因此省略了“1”位。有办法处理这样的数字吗?
使用 2 个寄存器,一个额外的寄存器用于高半部分。 MIPS 没有标志,因此没有 2 指令 add
/add-with-carry
添加 int64_t 的方法,就像许多其他 ISA 上那样,但您可以查看编译器输出对于可以轻松添加两个 64 位整数的 C 函数。
#include <stdint.h>
int64_t add64(int64_t a, int64_t b) {
return a+b;
}
使用 gcc5.4 为 MIPS on the Godbolt compiler explorer 编译 -O3 -fno-delayed-branch
1:
add64:
addu ,,
sltu ,, # check for carry-out with sum_lo < a_lo (unsigned)
addu ,, # add high halves
addu ,, # add the carry-out from the low half into the high half
j # return
nop # branch-delay slots
脚注 1:所以 GCC 只用 NOP 填充 branch-delay slot,而不是真正的指令。因此,相同的代码可以在没有像 MARS 默认模拟的延迟槽的简化 MIPS 上工作。
在内存中,大端模式下的MIPS(MIPS更常见的选择)以大端顺序存储整个64位整数,因此“高半”(最重要的 32 位)在低地址,因此该字的最高字节在最低地址,所有 8 个字节按位值降序排列。
void add64_store(int64_t a, int64_t b, int64_t *res) {
*res = a+b;
}
## gcc5.4 -O3 for MIPS - big-endian, not MIPS (el)
addu ,, # low half
lw ,16($sp)
sltu ,, # carry-out
addu ,,
addu ,, # high half
sw ,0() # store the high half to res[0..3] (byte offsets)
sw ,4() # store the low half to res[4..7]
j
nop # delay slot
正如您从所使用的寄存器编号中看到的那样,调用约定在较低编号的寄存器(较早的 arg) 中传递高半部分,这与小端架构不同高半部分进入后面的 arg 传递槽。如果您 运行 超出寄存器并且 int64_t
被传递到堆栈,这将使事情按预期工作。
在带有标志和带进位加法指令的体系结构上(例如 ARM32),您将获得一条加法指令,该指令在 C:R0
中创建 33 位结果(进位标志中的最高位,寄存器中的低 32)。
add64:
adds r0, r2, r0 @ ADD and set flags
adc r1, r3, r1 @ r1 = r1 + r3 + carry
bx lr
您标记了此 MIPS32,因此您没有可用的 ISA 64 位扩展。这是 1991 年在 MIPS III 中引入的,但对于嵌入式使用,MIPS32 是一种现代 MIPS,具有 64 位寄存器以外的扩展。
相同的推理适用于具有 daddu
的 64 位 MIPS 上的 128 位整数
我一直在寻找这个问题的答案,但找不到明确的答案。它会在多个寄存器之间拆分数字还是不能简单地处理它? 我尝试使用 MARS 对其进行测试,并使用数字 4294967296,即 0x100000000,但寄存器只保存了 0x00000000,因此省略了“1”位。有办法处理这样的数字吗?
使用 2 个寄存器,一个额外的寄存器用于高半部分。 MIPS 没有标志,因此没有 2 指令 add
/add-with-carry
添加 int64_t 的方法,就像许多其他 ISA 上那样,但您可以查看编译器输出对于可以轻松添加两个 64 位整数的 C 函数。
#include <stdint.h>
int64_t add64(int64_t a, int64_t b) {
return a+b;
}
使用 gcc5.4 为 MIPS on the Godbolt compiler explorer 编译 -O3 -fno-delayed-branch
1:
add64:
addu ,,
sltu ,, # check for carry-out with sum_lo < a_lo (unsigned)
addu ,, # add high halves
addu ,, # add the carry-out from the low half into the high half
j # return
nop # branch-delay slots
脚注 1:所以 GCC 只用 NOP 填充 branch-delay slot,而不是真正的指令。因此,相同的代码可以在没有像 MARS 默认模拟的延迟槽的简化 MIPS 上工作。
在内存中,大端模式下的MIPS(MIPS更常见的选择)以大端顺序存储整个64位整数,因此“高半”(最重要的 32 位)在低地址,因此该字的最高字节在最低地址,所有 8 个字节按位值降序排列。
void add64_store(int64_t a, int64_t b, int64_t *res) {
*res = a+b;
}
## gcc5.4 -O3 for MIPS - big-endian, not MIPS (el)
addu ,, # low half
lw ,16($sp)
sltu ,, # carry-out
addu ,,
addu ,, # high half
sw ,0() # store the high half to res[0..3] (byte offsets)
sw ,4() # store the low half to res[4..7]
j
nop # delay slot
正如您从所使用的寄存器编号中看到的那样,调用约定在较低编号的寄存器(较早的 arg) 中传递高半部分,这与小端架构不同高半部分进入后面的 arg 传递槽。如果您 运行 超出寄存器并且 int64_t
被传递到堆栈,这将使事情按预期工作。
在带有标志和带进位加法指令的体系结构上(例如 ARM32),您将获得一条加法指令,该指令在 C:R0
中创建 33 位结果(进位标志中的最高位,寄存器中的低 32)。
add64:
adds r0, r2, r0 @ ADD and set flags
adc r1, r3, r1 @ r1 = r1 + r3 + carry
bx lr
您标记了此 MIPS32,因此您没有可用的 ISA 64 位扩展。这是 1991 年在 MIPS III 中引入的,但对于嵌入式使用,MIPS32 是一种现代 MIPS,具有 64 位寄存器以外的扩展。
相同的推理适用于具有 daddu