RISC-V generate -1 / 0xFFFFFFFF in a register with LUI / ADDI?

2

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?

assembly
riscv
asked on Stack Overflow Jul 27, 2019 by Kralik_011 • edited Jul 27, 2019 by ローウ

2 Answers

3

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.

answered on Stack Overflow Jul 27, 2019 by Peter Cordes
1

Let's first analyse where the problem with your code is:

lui t0, 0xFFFFF
addi t0, t0, 0x7FF
  • The lui instruction loads into t0 the value resulting from left shifting the 20-bit immediate 0xFFFFF by 12 bits. Therefore, t0 results in 0xFFFFF000.
  • The 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 1s, 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 0s into the upper bits of t0:

lui t0, 0
addi t0, t0, 0xFFF
answered on Stack Overflow Jul 27, 2019 by ローウ

User contributions licensed under CC BY-SA 3.0