I am learning how to write code for a RISC-V processor. I want to store a value of 0xFFFFFFFF
into memory / a register.
I can extend the 12 immediate bits of addi
instruction by adding a lui
before it,
something like this:
lui t0, 0xFFFFF
addi t0, t0, 0x7FF
But the result will end up something like 0xFFFFF7FF
.
So then, how can I generate that value?
Ask a C compiler:
unsigned foo(){return 0xFFFFFFFF;}
compiles to this asm with Clang -O3
for RISC-V (on Godbolt):
foo():
addi a0, zero, -1
ret
(gcc just uses the li a0, -1
pseudo-instruction and leaves the details to the assembler. Normally you should do the same, unless you want to think about choosing constants that can be generated more efficiently.)
RISC-V addi
sign-extends its immediate operand to 32 (or 64) bits, so if you want a one in the 12th bit, you need to account for that in your choice for the upper bits.
In this case, the right starting value for the upper bits is 0
so you can optimize away the lui
entirely.
RISC-V uses 2's complement signed integers so sign-extension just means duplicating the sign bit to all higher positions when widening.
Let's first analyse where the problem with your code is:
lui t0, 0xFFFFF
addi t0, t0, 0x7FF
lui
instruction loads into t0
the value resulting from left shifting the 20-bit immediate 0xFFFFF
by 12 bits. Therefore, t0
results in 0xFFFFF000
.addi
sign extends the 12-bit immediate 0x7FF
, and adds it to the register t0
. Since the most significant bit (i.e., the sign bit) of the immediate is zero, its sign extended 32-bit value is 0x000007FF
. This value is then added to t0
, which was previously 0xFFFFF000
. Therefore, the resulting value of t0
is 0xFFFFF7FF
.As already explained in this answer, you can optimise away the lui
instruction by taking advantage of how the sign extension works: sign extension propagates the sign bit, which is the most significant bit.
The 12-bit immediate 0xFFF
consists of all 1
s, including the most significant bit (i.e., the sign bit). Therefore, its 32-bit sign extension is 0xFFFFFFFF
, which already corresponds to the value you want:
addi t0, zero, 0xFFF
If you keep insisting on using both instructions, lui
and addi
, simply load all 0
s into the upper bits of t0
:
lui t0, 0
addi t0, t0, 0xFFF
User contributions licensed under CC BY-SA 3.0