1
....
//---------------------------------
// Init State
//---------------------------------
int32_t state[16];
state[0] = 0x61707865;
...
    ||  c -> asm(riscv32-gcc -S inputcode.c)
    ||  convert
    \/
...
addi  sp,sp,-112
sw    ra,108(sp)
sw    s0,104(sp)
addi  s0,sp,112
sw    a0,-100(s0)
sw    a1,-104(s0)
li    a5,1634762752
addi  a5,a5,-1947
....

You can just use li a5,1634760805 (1634760805=1634762752-1947), but why do you do li a5,1634762752 and addi a5,a5,-1947?


GCC still does this with optimization enabled:

int foo(){
    return 0x61707865;
}

compiling with rv32gcc 10.2 -O3 on Godbolt to

foo:
        li      a0,1634762752
        addi    a0,a0,-1947
        ret

vs. this with clang 14 -O3 avoiding the li pseudo-instruction

foo:                                    # @foo
        lui     a0, 399112
        addi    a0, a0, -1947
        ret
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
김민재
  • 21
  • 2
  • 1
    The immediate operand of `li` cannot be any value. There are only a limited number of bits for it. 1634762752 (hex 61708000) is one of the values it can be, and then adding −1947 gives the desired result. – Eric Postpischil Apr 26 '22 at 02:00
  • Note that `1634762752` is `0x61708000`. GCC may be using that `li` pseudo-instruction as a proxy for an explicit `lui` to set the upper 20 bits, instead of just letting the assembler expand an `li` into two instructions for a value that was non-zero in the top 20 *and* low 12 (and didn't fit in a sign-extended 12-bit immediate for `addi` with the zero register). But contrary to what @Eric wrote, `li a5, 0x61707865` does actually assemble. (using `clang -c -target riscv32 foo.s` / `llvm-objdump -d foo.o`, it's `lui a5, 399112` / `addi a5, a5, -1947` because `lui` shifts its source op) – Peter Cordes Apr 26 '22 at 04:14
  • Near duplicate of [RISC-V build 32-bit constants with LUI and ADDI](https://stackoverflow.com/q/50742420) but that doesn't mention or explain GCC emitting `li` with the already-left-shifted value instead of `lui` with a value to be left-shifted. – Peter Cordes Apr 26 '22 at 04:20
  • a 32 bit instruction cannot hold the opcode, and the destination register and 32 bits of immediate data. you cannot fit more than 32 bits into 32 bits. so it takes two or more instructions, just like a list of other (fixed length) instruction sets. – old_timer Apr 26 '22 at 13:40
  • @EricPostpischil The question is not that stupid: On other CPUs, the corresponding pseudo-instruction (`ldr =` on ARM and `li` on MIPS) results in two words (on ARM) or two instructions (on MIPS) when assembling. So you could ask the question why RISCV assemblers do not allow any value and replace the `li` pseudo-instruction by two instructions... – Martin Rosenau Apr 27 '22 at 09:20

0 Answers0