weiqi7777

riscv32位架构如何进行64位加减运算

0
阅读(2198)

在rv32架构下,一个64位变量,是要用2个寄存器保存的。在c程序中,我们是可以直接对64位变量进行加减操作的。

那么rv32下,又是如何实现64位加减运算的了?下面来讨论一下。

一、64位加

测试程序:

int main() {

int64_t a = 0xbbbbbbbb;

int64_t b = 0xcccccccc;

int64_t c = a + b;

printf("%016llx\n", c);

}

使用riscv32-unknown-elf-gcc编译器编译,使用riscv32-unknown-elf-objdump查看反汇编:

0001016e

:

1016e: 7179 addi x2,x2,-48

10170: d606 sw x1,44(x2)

10172: d422 sw x8,40(x2)

10174: 1800 addi x8,x2,48

10176: bbbbc7b7 lui x15,0xbbbbc

1017a: bbb78793 addi x15,x15,-1093 #bbbbbbbb <__BSS_END__+0xbbb9c143>

1017e: 4801 li x16,0

10180: fef42423 sw x15,-24(x8)

10184: ff042623 sw x16,-20(x8)

10188: ccccd7b7 lui x15,0xccccd

1018c: ccc78793 addi x15,x15,-820 #cccccccc <__BSS_END__+0xcccad254>

10190: 4801 li x16,0

10192: fef42023 sw x15,-32(x8)

10196: ff042223 sw x16,-28(x8)

1019a: fe842683 lw x13,-24(x8)

1019e: fec42703 lw x14,-20(x8)

101a2: fe042583 lw x11,-32(x8)

101a6: fe442603 lw x12,-28(x8)

101aa: 00b687b3 add x15,x13,x11

101ae: 853e mv x10,x15

101b0: 00d53533 sltu x10,x10,x13

101b4: 00c70833 add x16,x14,x12

101b8: 01050733 add x14,x10,x16

101bc: 883a mv x16,x14

101be: fcf42c23 sw x15,-40(x8)

101c2: fd042e23 sw x16,-36(x8)

101c6: fd842603 lw x12,-40(x8)

101ca: fdc42683 lw x13,-36(x8)

101ce: 67f9 lui x15,0x1e

101d0: d4078513 addi x10,x15,-704 # 1dd40 <__clzsi2+0x40>

101d4: 22a5 jal 1033c

这里就需要riscv的反汇编知识了。

在rv32下,64位变量,是要使用2个寄存器来保存的。另外rv32下,没有load/store 64位指令,因此保存或读取64位变量,需要两次32位仿存操作。

下面一段一段进行分析:

10176: bbbbc7b7 lui x15,0xbbbbc

1017a: bbb78793 addi x15,x15,-1093 #bbbbbbbb <__BSS_END__+0xbbb9c143>

1017e: 4801 li x16,0

10180: fef42423 sw x15,-24(x8)

10184: ff042623 sw x16,-20(x8)

x15的值为0xbbbbbbbb,x16的值为0,刚好组合得到变量a,将x15和x16,写入到栈-24和-20位置,所以可以知道,变量a的首地址为sp-24。

10188: ccccd7b7 lui x15,0xccccd

1018c: ccc78793 addi x15,x15,-820 #cccccccc <__BSS_END__+0xcccad254>

10190: 4801 li x16,0

10192: fef42023 sw x15,-32(x8)

10196: ff042223 sw x16,-28(x8)

x15的值为0xcccccccc,x16的值为0,刚好组合得到变量b,将x15和x16,写入到栈-32和-28位置,所以可以知道,变量b的首地址为sp-32。

1019a: fe842683 lw x13,-24(x8)

1019e: fec42703 lw x14,-20(x8)

101a2: fe042583 lw x11,-32(x8)

101a6: fe442603 lw x12,-28(x8)

从之前分析,可以得知

  • x13:变量a的低32位
  • x14,:变量a的高32位
  • x11:变量b的低32位
  • x12:变量b的高32位

后面就开始进行真正的运算了:

101aa: 00b687b3 add x15,x13,x11

101ae: 853e mv x10,x15

101b0: 00d53533 sltu x10,x10,x13

101b4: 00c70833 add x16,x14,x12

101b8: 01050733 add x14,x10,x16

101bc: 883a mv x16,x14

首先将x11和x13相加,其实就是将变量a的低32位和变量b的低32位相加,得到的结果,保存到x15中。

将x15保存到x10中,在将x10和x13进行无符号比较。如果x10无符号小于x13,x10更新1,否则更新为0。 这里为什么要进行这样操作呢?

原因就是 2个32位数相加,是可能会有进位的,如果有进位,那么高32位相加的时候,要加上这个进位。 riscv没有arm有运算进位指令,只能通过其他的方式来获取进位。

x10是低32位相加的结果,如果结果小于一个加数,那么表示是有进位的,否则就没有。因此通过sltu指令,就可以得到低32位的进位结果。

x12和x14相加,其实就是将变量a的高32位和变量b的高32位相加,得到的结果,保存到x16中。

还需要考虑低32位相加进位,因此还要将x16加上x10,写入到x14。最后将x14保存到x16中。

所以最终

  • x15:变量c的低32位
  • x16:变量c的高32位

通过以上,我们就知道了rv32下,如何进行64位变量加运算。

二、64位减

测试程序:

int main() {

int64_t a = 0xbbbbbbbb;

int64_t b = 0xcccccccc;

int64_t c = a - b;

printf("%016llx\n", c);

}

汇编代码如下:

0001016e

:

1016e: 7179 addi x2,x2,-48

10170: d606 sw x1,44(x2)

10172: d422 sw x8,40(x2)

10174: 1800 addi x8,x2,48

10176: bbbbc7b7 lui x15,0xbbbbc

1017a: bbb78793 addi x15,x15,-1093 #bbbbbbbb <__BSS_END__+0xbbb9c143>

1017e: 4801 li x16,0

10180: fef42423 sw x15,-24(x8)

10184: ff042623 sw x16,-20(x8)

10188: ccccd7b7 lui x15,0xccccd

1018c: ccc78793 addi x15,x15,-820 #cccccccc <__BSS_END__+0xcccad254>

10190: 4801 li x16,0

10192: fef42023 sw x15,-32(x8)

10196: ff042223 sw x16,-28(x8)

1019a: fe842683 lw x13,-24(x8)

1019e: fec42703 lw x14,-20(x8)

101a2: fe042583 lw x11,-32(x8)

101a6: fe442603 lw x12,-28(x8)

101aa: 40b687b3 sub x15,x13,x11

101ae: 853e mv x10,x15

101b0: 00a6b533 sltu x10,x13,x10

101b4: 40c70833 sub x16,x14,x12

101b8: 40a80733 sub x14,x16,x10

101bc: 883a mv x16,x14

101be: fcf42c23 sw x15,-40(x8)

101c2: fd042e23 sw x16,-36(x8)

101c6: fd842603 lw x12,-40(x8)

101ca: fdc42683 lw x13,-36(x8)

101ce: 67f9 lui x15,0x1e

101d0: d4078513 addi x10,x15,-704 # 1dd40 <__clzsi2+0x40>

101d4: 22a5 jal 1033c

从反汇编知道,也是使用sltu指令,获取低32位减法借位。然后高32位运算,要减去这个借位。

Baidu
map