lipseudo
li
rd, immpseudo
rd = imm

li puts a plain constant number into a register. The name is short for load immediate — immediate being the standard word for a fixed value you write directly in the code. li t0, 42 simply makes t0 hold 42. It is one of the first instructions you reach for, since almost every program starts by putting some known numbers into registers: counters, limits, service codes.

It earns the load name because of a hardware limit worth understanding. Every RISC-V instruction is itself exactly 32 bits, and it has to encode the operation, the registers, and the constant all together — so there is no room inside a single instruction to carry a full 32-bit constant. Small constants fit; large ones do not.

li hides that problem. It is a pseudo-instruction, a convenient name the assembler turns into whatever real instructions are needed. For a small value, one instruction suffices. For a large one, the assembler automatically emits two — one to set the upper portion and one to add the lower — so that from your point of view li t1, 0x10010000 just works, however big the number. You can watch the simulator reveal the real instructions it expands into.

Keep li distinct from la: li loads a literal number you typed, while la loads the address that a label stands for. Numbers come from li; locations come from la. The example loads a small value and a large one to show both cases handled the same way.

Expands to
addi rd, zero, imm          # small constants
lui rd, hi  +  addi rd, rd, lo   # large constants

A pseudo-instruction: the assembler turns it into the real instruction(s) above.

li t0, 42
li t1, 0x10010000