miki1307
miki1307

Reputation: 157

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

I can't figure out how to call these two instructions in a proper way. The first operand of the first instruction C.ADDI4SPN should be a register, and the second one, if I'm right, should be a number which is scaled by 4.

But when I try to call the instruction I get the message that the operands are illegal.

The same thing is with the second instruction C.ADDI16SP, the only difference is that the number should be scaled by 16. These are the descriptions of the instructions in the manual:

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

These are the examples of how I attempt to use the instructions:

c.addi16sp 32
c.addi4spn x10, 8

Upvotes: 2

Views: 2173

Answers (3)

yflelion
yflelion

Reputation: 1746

As mentioned by @Erik Eidt you have to name the sp register.
This choice was made in riscv-opc.c.
https://github.com/riscv/riscv-binutils-gdb/blob/riscv-binutils-2.35/opcodes/riscv-opc.c
If you take a look you have these two definitions:

{"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 and CL are the operands:
Ct : /* RS2 x8-x15 */
Cc : sp ( this is why you need the sp ).
CK and CL for the RVC_ADDI4SPN_IMM and RVC_ADDI16SP_IMM.

The reason why you have addi in the objdump is because :

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

and

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

Since they are declared before the previous ones , the objdump match an addi.

Upvotes: 2

Erik Eidt
Erik Eidt

Reputation: 26766

It seems that for some reason I don't know, that we have to name the sp register when using these instructions:

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

It is possible that this is for consistency with the uncompressed instruction expansion, where you also have to name sp.

However, while some might count this as a feature, others (such as myself) more likely to count this as a bug or an oddity at best, because an implicit register (that you can't ever change) probably shouldn't be required in the assembly form — when explicitly using the compressed opcode.

The base instruction set (i.e. sans compression) has no implicit registers — from the machine code perspective — all operands are specified in the machine instruction.

Certain assembly mnemonics allow omitting the register, which is then filled in by the assembler in generating the machine code: jal and ret (pseudo instructions) for example do not allow or require the assembly program to name a register yet the machine code for these instructions has an rd/rs1 register field (respectively) filled in with x1/ra by the assembler.

To use c.lwsp, we also specify the sp register, so it looks very much like an lw instruction.  And c.jal looks just like the jal pseudo instruction in assuming x1 as the link register — even though c.jal does hard code x1 as an implicit target register, while jal's translation does not — from the machine code perspective.

So, I guess what they're going for is maximum compatibility with the uncompressed instructions assembly forms.  And I guess that makes the disassembly a bit more palatable, since it cannot tell whether you originally used a compressed opcode vs. the assembler compressing the instruction (though I'm not sure how worthwhile it is to show disassembly of compressed instructions using uncompressed but compressible forms).


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

As you can see the disassembler assumes you used (or want to see) non-compressed instruction syntax even though the assembler may or may not have converted these to their compressed equivalents.

Upvotes: 3

old_timer
old_timer

Reputation: 71586

Start by going backward (and understand that assembly is tool specific not target).

.hword 0x110c

   0:   110c                    addi    x11,x2,160

Then try some more

.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.

This was done with gnu assembler, and objdump from binutils.

It appears you need an immediate that is a multiple of four:

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

to get it to optimize into this instruction.

Upvotes: 2

Related Questions