RISC-V 在带有 LUI / ADDI 的寄存器中生成 -1 / 0xFFFFFFFF?

RISC-V generate -1 / 0xFFFFFFFF in a register with LUI / ADDI?

我正在学习如何为 RISC-V 处理器编写代码。我想将 0xFFFFFFFF 的值存储到内存/寄存器中。

我可以通过在addi指令之前添加一个lui来扩展addi指令的12个立即位, 像这样:

lui t0, 0xFFFFF
addi t0, t0, 0x7FF

但结果会像 0xFFFFF7FF.

那么,我怎样才能产生那个价值呢?

询问 C 编译器:

unsigned foo(){return 0xFFFFFFFF;}

使用 Clang -O3 为 RISC-V (on Godbolt):

编译成这个 asm
foo():
    addi    a0, zero, -1
    ret

(gcc 只是使用了 li a0, -1 伪指令,而将细节留给了汇编程序。通常你应该这样做,除非你想考虑选择可以更有效地生成的常量。)


RISC-V addi 将其直接操作数符号扩展为 32(或 64)位,因此如果您想要第 12 位中的 1,则需要在您选择高位时考虑到这一点。

在这种情况下,高位的正确起始值为 0,因此您可以完全优化掉 lui

RISC-V 使用 2 的补码有符号整数,因此符号扩展只是意味着在扩展时将符号位复制到所有更高的位置。

我们先分析一下你的代码哪里出了问题:

lui t0, 0xFFFFF
addi t0, t0, 0x7FF
  • lui 指令将 20 位立即数 0xFFFFF 左移 12 位后的值加载到 t0 中。因此,t0 结果为 0xFFFFF000
  • addi sign extends 12位立即数0x7FF,并将其添加到寄存器t0。由于立即数的最高有效位(即符号位)为零,其符号扩展的 32 位值为 0x000007FF。然后将此值添加到 t0,之前是 0xFFFFF000。因此,t0 的结果值为 0xFFFFF7FF.

中所述,您可以利用符号扩展的工作原理优化掉 lui 指令:符号扩展传播符号位,这是最高有效位。

12 位立即数 0xFFF 由所有 1 组成,包括最高有效位(即符号位)。因此,它的32位符号扩展为0xFFFFFFFF,已经对应你要的值:

addi t0, zero, 0xFFF

如果你一直坚持使用luiaddi这两个指令,只需将所有0加载到t0的高位:

lui t0, 0
addi t0, t0, 0xFFF