如何使用RISC-V架构的C.ADDI4SPN和C.ADDI16SP指令(压缩子集)?

How to use C.ADDI4SPN and C.ADDI16SP instructions (compressed subset) of RISC-V architecture?

我不知道如何以正确的方式调用这两条指令。第一个指令的第一个操作数 C.ADDI4SPN 应该是一个寄存器,第二个,如果我是对的,应该是一个按 4 缩放的数字。

但是当我尝试调用该指令时,我收到操作数非法的消息。

第二条指令C.ADDI16SP也是一样,唯一的区别是数字要按16缩放。 这些是手册中指令的描述:

C.ADDI16SP adds the non-zero sign-extended 6-bit immediate to the value in the stack pointer (sp=x2), where the immediate is scaled to represent multiples of 16 in the range (-512,496).

C.ADDI4SPN is a CIW-format RV32C/RV64C-only instruction that adds a zero-extended non-zero immediate, scaled by 4, to the stack pointer, x2, and writes the result to rd0

这些是我尝试使用说明的示例:

c.addi16sp 32
c.addi4spn x10, 8

从倒退开始(并了解汇编是特定于工具而非目标的)。

.hword 0x110c

   0:   110c                    addi    x11,x2,160

然后再尝试一些

.hword 0x110c
addi    x11,x2,160
addi    x12,x2,160
addi    x13,x2,160
addi    x14,x2,160
addi    x14,x2,40
addi    x14,x2,4

00000000 <.text>:
   0:   110c                    addi    x11,x2,160
   2:   110c                    addi    x11,x2,160
   4:   1110                    addi    x12,x2,160
   6:   1114                    addi    x13,x2,160
   8:   1118                    addi    x14,x2,160
   a:   1038                    addi    x14,x2,40
   c:   0058                    addi    x14,x2,4

This instruction is used to generate pointers to stack-allocated variables, and expands to addi rd ′ , x2, nzuimm.

这是用 gnu 汇编器和 binutils 的 objdump 完成的。

您似乎需要一个四的倍数的立即数:

addi    x14,x2,4
addi    x14,x2,5
addi    x14,x2,6
addi    x14,x2,7
addi    x14,x2,8

00000000 <.text>:
   0:   0058                addi    x14,x2,4
   2:   00510713            addi    x14,x2,5
   6:   00610713            addi    x14,x2,6
   a:   00710713            addi    x14,x2,7
   e:   0038                addi    x14,x2,8

让它优化到这条指令中。

似乎出于某种我不知道的原因,我们在使用这些指令时必须命名 sp 寄存器:

c.addi4sp, x10, sp, 8
c.addi16sp sp, 16

这可能是为了与未压缩的指令扩展保持一致,其中您还必须命名 sp.

然而,虽然有些人可能将其视为一项功能,但其他人(例如我自己)更有可能将其视为错误或最多是怪事,因为隐式寄存器(您永远无法更改)可能在汇编形式中不应该是必需的——当明确使用压缩操作码时。

基本指令集(即无压缩)没有隐式寄存器——从机器代码的角度来看——所有操作数都在机器指令中指定。

某些汇编助记符允许省略寄存器,然后由汇编器在生成机器代码时填充:例如 jalret(伪指令)不允许或要求汇编程序来命名寄存器,但这些指令的机器代码有一个 rd/rs1 寄存器字段(分别)由汇编器填充 x1/ra

为了使用c.lwsp,我们还指定了sp寄存器,所以看起来很像lw指令。 c.jal 看起来就像假设 x1 作为 link 寄存器的 jal 伪指令——尽管 c.jalx1 硬编码为隐式目标寄存器,而 jal 的翻译没有——从机器代码的角度来看。

所以,我猜他们想要的是与未压缩指令汇编形式的最大兼容性。而且我想这会使反汇编更容易接受,因为它无法判断您最初使用的是压缩操作码还是汇编程序压缩指令(尽管我不确定使用未压缩但显示压缩指令的反汇编有多大价值可压缩形式)。


test.s:

.text
c.addi4spn a0, sp, 8  # compressed instruction, must name sp
addi a0, sp, 8        # non-compressed instruction, gets compressed to c.addi4spn

c.addi16sp sp, 16     # compressed instruction, must name sp
addi sp, sp, 16       # non-compressed instruction, gets compressed to c.addi

c.addi16sp sp, 128    # compressed instruction, must name sp
addi sp, sp, 128      # non-compressed instruction, gets compressed to c.addi16sp

Disassembly of section .text:

00000000 <.text>:
   0:   0028                    addi    a0,sp,8    # c.addi4spn
   2:   0028                    addi    a0,sp,8    # c.addi4spn
   4:   6141                    addi    sp,sp,16   # c.addi16sp
   6:   0141                    addi    sp,sp,16   # c.addi
   8:   6109                    addi    sp,sp,128  # c.addi16sp
   a:   6109                    addi    sp,sp,128  # c.addi16sp

如您所见,反汇编程序假设您使用(或希望看到)non-compressed 指令语法,即使汇编程序可能已将或可能未将这些转换为它们的压缩等价物。

如@Erik Eidt 所述,您必须命名 sp 寄存器。
这个选择是在 riscv-opc.c.
中做出的 https://github.com/riscv/riscv-binutils-gdb/blob/riscv-binutils-2.35/opcodes/riscv-opc.c
如果你看一下你有这两个定义:

{"c.addi4spn", 0, INSN_CLASS_C,   "Ct,Cc,CK", MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN, match_c_addi4spn, 0 },
{"c.addi16sp", 0, INSN_CLASS_C,   "Cc,CL", MATCH_C_ADDI16SP, MASK_C_ADDI16SP, match_c_addi16sp, 0 },

Ct Cc CK和CL是操作数:
Ct : /* RS2 x8-x15 */
Cc : sp(这就是你需要 sp 的原因)。
RVC_ADDI4SPN_IMM 和 RVC_ADDI16SP_IMM.

的 CK 和 CL

objdump 中有 addi 的原因是:

{"addi",        0, INSN_CLASS_C,   "Ct,Cc,CK", MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN, match_c_addi4spn, INSN_ALIAS },

{"addi",        0, INSN_CLASS_C,   "Cc,Cc,CL", MATCH_C_ADDI16SP, MASK_C_ADDI16SP, match_c_addi16sp, INSN_ALIAS },

由于它们是在之前的声明之前声明的,objdump 匹配一个 addi。