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