Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RISC-V build 32-bit constants with LUI and ADDI

LUI (load upper immediate) is used to build 32-bit constants and uses the U-type format. LUI places the U-immediate value in the top 20 bits of the destination register rd, filling in the lowest 12 bits with zeros.

I found this in manual, but if I want to move 0xffffffff to a register, all the code I need is:

LUI x2, 0xfffff000
ADDI x2, x2, 0xfff

But a problem occurred, ADDI will extend sign to make a immediate data to a signed number, so 0xfff will be extend to 0xffffffff.

It make x2 to 0xffffefff but not 0xffffffff

and what is an good implementation to move a 32bits immediate to register?

like image 909
Li Hanyuan Avatar asked Jun 07 '18 13:06

Li Hanyuan


2 Answers

TL;DR: The 32-bit constant you want to load into x2 is 0xffffffff which corresponds to -1. Since -1 is in the range [-2048, 2047], this constant can be loaded with a single instruction: addi x2, zero, -1. You can also use the li pseudoinstruction: li, x2, -1 which the assembler, in turn, translates to addi x2, zero, -1.

Loading a 32-bit constant with a lui+addi sequence

In general, we need a lui+addi sequence – two instructions – for loading a 32-bit constant into a register. The lui instruction encodes a 20-bit immediate, whereas the addi instruction encodes a 12-bit immediate. lui and addi can be used to load the upper 20 bits and the lower 12 bits of a 32-bit constant, respectively.

Let N be a 32-bit constant we want to load into a register: N ≡ n31 ... n0. Then, we can split this constant into its upper 20 bits and lower 12 bits, NU and NL, respectively: NU ≡ n31 ... n12 ; NL ≡ n11 ... n0

In principle, we encode NU in the immediate in lui and NL in the immediate in addi. Nevertheless, there is a difficulty to handle if the most significant bit of the 12-bit immediate in addi is 1 because the immediate value encoded in the addi instruction is sign extended to 32 bits. If this is the case, the addi instruction adds to the destination register not NL, but NL - 4096 instead — -4096 (or -212) is the resulting number when the upper 20 bits are 1s and the lower 12 bits are 0s.

To compensate for the unwanted term -4096, we can add 1 to lui's immediate – the LSB of the immediate in lui corresponds to bit #12 – so, adding 1 to this immediate results in adding 4096 to the destination register which cancels out the -4096 term.

Loading a 32-bit constant with a single addi instruction

The issue explained above is due to the sign extension that the immediate in addi undergoes. The decision of sign extending addi's immediate was probably to allow the loading of small integersintegers between -2048 and 2047, both inclusive – with a single addi instruction. For example, if the immediate in addi were zero extended instead of sign extended, it wouldn't be possible to load such a frequent constant like -1 into a register with just a single instruction.


Loading a 32-bit constant with the li pseudoinstruction

In any case, you can always use the li pseudoinstruction for loading a 32-bit constant without having to care about what the value of the constant to load is. This pseudoinstruction can load any 32-bit number into a register, and it is, therefore, simpler to use and less error-prone than manually writing the lui+addi sequence.

If the number fits in addi's immediate field ([-2048, 2047]), the assembler will translate the li pseudoinstruction into just an addi instruction, otherwise, li will be translated into a lui+addi sequence and the complication explained above is handled automatically by the assembler.

like image 185
ネロク・ゴ Avatar answered Oct 20 '22 03:10

ネロク・ゴ


The RISC-V assembler supports the pseudo-instruction li x2, 0xFFFFFFFF.

Let Nis a signed, 2's complement 32 bit integer.

Common case implementation of li x2,N is:

    # sign extend low 12 bits
    M=(N << 20) >> 20

    # Upper 20 bits
    K=((N-M) >> 12) <<12

    # Load upper 20 bits
    LUI x2,K

    # Add lower bits
    ADDI x2,x2,M

Of course, to load short immediate li can use

   addi x2,x0,imm

So, li x2, 0xFFFFFFFF is addi x2,x0,-1.

like image 7
Pavel Smirnov Avatar answered Oct 20 '22 03:10

Pavel Smirnov