What is the difference between la and li in opcodes in MIPS?

They’re fairly similar, as both are (mostly) used for loading immediate values. Both of them are also pseudo-instructions, so it’s really up to each assembler that supports them to determine exactly how they should function.


li stands for Load Immediate and is a convenient way of loading an immediate up to 32 bits in size. Instructions like addi and ori can only encode 16-bit immediates, so the assembler may translate li into multiple instructions.

For example, li $t0,0x12345678 might become:

lui $at, 0x1234 
ori $t0, $at, 0x5678        

So it’s just a way to save you from writing those two instructions, and instead letting the assembler working that out for you.

There’s really no reason why e.g. li $t0, Message wouldn’t be supported, since labels are also immediates, but some assemblers might not accept labels for li.


la stands for Load Address. It can be used to load integer constants just like li, e.g. la $t0,0x1234678. But it also works with labels: la $t0, Message # t0 = address of Message.
Some assemblers may also allow you to do things like la $t0, 8($t1) # t0 = t1 + 8.


When you’d use li and when you’d use la depends on the context. If the value you’re loading is going to be used as an address you would typically use la to load it, and otherwise you’d typically use li. Since they are partially interchangable it’s really up to you, but other people might find your code strange-looking if you use la all the time to load integer constants.

Leave a Comment