\n
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.
\nThe base instruction set (i.e. sans compression) has no implicit registers — from the machine code perspective — all operands are specified in the machine instruction.
\nCertain 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).
\ntest.s:
\n.text\nc.addi4spn a0, sp, 8 # compressed instruction, must name sp\naddi a0, sp, 8 # non-compressed instruction, gets compressed to c.addi4spn\n\nc.addi16sp sp, 16 # compressed instruction, must name sp\naddi sp, sp, 16 # non-compressed instruction, gets compressed to c.addi\n\nc.addi16sp sp, 128 # compressed instruction, must name sp\naddi sp, sp, 128 # non-compressed instruction, gets compressed to c.addi16sp\n
\nDisassembly of section .text:\n\n00000000 <.text>:\n 0: 0028 addi a0,sp,8 # c.addi4spn\n 2: 0028 addi a0,sp,8 # c.addi4spn\n 4: 6141 addi sp,sp,16 # c.addi16sp\n 6: 0141 addi sp,sp,16 # c.addi\n 8: 6109 addi sp,sp,128 # c.addi16sp\n a: 6109 addi sp,sp,128 # c.addi16sp\n
\nAs 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.
\n","author":{"@type":"Person","name":"Erik Eidt"},"upvoteCount":3}}}Reputation: 157
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
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
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
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