【问题标题】:How does MIPS store a number larger than 32 bits?MIPS 如何存储大于 32 位的数字?
【发布时间】:2019-04-13 21:06:31
【问题描述】:

我一直在寻找这个问题的答案,但找不到一个明确的答案。它是在多个寄存器之间拆分数字还是不能简单地处理它? 我尝试使用 MARS 对其进行测试,并使用数字 4294967296,即 0x100000000,但寄存器仅保存了 0x00000000,因此省略了“1”位。有没有办法处理这样的数字?

【问题讨论】:

  • 如果您只使用 32 位寄存器,那么是的,上面的所有内容都被丢弃,并且值被“截断”到仅 32 位。因此,要存储更多位,您必须使用更多位(多个寄存器,内存中的多个字等),CPU 中的任何内容都不会因为突然 32 位不够用而动态膨胀,所有大小在 asm 代码中都是固定的,并且代码必须准备好处理更多位,否则不会。

标签: assembly memory mips mips32 bigint


【解决方案1】:

使用 2 个寄存器,一个额外的用于高半部分。 MIPS 没有标志,因此没有像在许多其他 ISA 上那样添加 int64_t 的 2 指令 add/add-with-carry,但您可以查看添加两个 64 的 C 函数的编译器输出位整数很容易。

#include <stdint.h>

int64_t add64(int64_t a, int64_t b) { 
    return a+b;
}

编译为 MIPS on the Godbolt compiler explorer 和 gcc5.4 -O3 -fno-delayed-branch1:

add64:
    addu    $3,$5,$7
    sltu    $5,$3,$5     # check for carry-out with  sum_lo < a_lo  (unsigned)
    addu    $2,$4,$6     # add high halves
    addu    $2,$5,$2     # add the carry-out from the low half into the high half
    j       $31          # return
    nop                # branch-delay slots

脚注 1:所以 GCC 只用 NOP 填充 branch-delay slot,而不是真正的指令。因此,相同的代码可以在没有延迟槽的简化 MIPS 上运行,就像 MARS 默认模拟的那样。


在内存中,大​​端模式下的 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    $7,$5,$7        # low half
    lw      $2,16($sp)
    sltu    $5,$7,$5        # carry-out
    addu    $4,$4,$6        
    addu    $5,$5,$4        # high half
    sw      $5,0($2)        # store the high half to res[0..3] (byte offsets)
    sw      $7,4($2)        # store the low  half to res[4..7]
    j       $31
    nop                   # delay slot

从所使用的寄存器编号可以看出,调用约定将高半部分传递到编号较低的寄存器(早期的 arg)中,这与小端架构中高半部分传递在后面的 arg 传递槽中。如果您用完了寄存器并且在堆栈上传递了int64_t,这会使事情按预期工作。


在带有标志和带进位加法指令的体系结构上(例如 ARM32),您会得到一个加法指令,它会在 C:R0 中创建一个 33 位结果(进位标志中的最高位,a 中的低 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 位寄存器以外的扩展。

同样的道理也适用于 64 位 MIPS 上的 128 位整数daddu

【讨论】:

  • 很好的答案。您知道在 j $31 之后有什么命令(在两个示例中)吗?我以为这意味着跳转(回到被调用者),那么之后怎么会有重要的代码?
  • GCC 的目标是真正的 MIPS,它有一个 branch-delay slot。即使采用分支,分支之后的第一条指令也会无条件运行。我在第一个代码块上的 cmets 指出了这一点。您可以使用-fno-delayed-branch 进行编译,让 GCC 只用 NOP 填充它,这样您就可以在模拟器中运行代码以获得简化的 MIPS 而没有延迟槽(如 MARS 的默认设置)。
  • @lalala:更新了我的答案以使用-fno-delayed-branch,因为现在大多数学习 MIPS 的人显然不是在学习真正的 MIPS,而是在没有延迟槽的情况下简化了 MIPS。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-23
  • 2014-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多