0

So I am writing an assembly program that has lots of constant integer values.

I know that in the .data section I can assign a label with a .word data type and type in my number. With this method I still have to load an address in main.

But in main, I could just simply use

li $t1, some_number

Are any one of these methods better than the other and why?

1 Answer 1

1

Generally I'd say using li is the better approach. You're avoiding adding a bunch of clutter in your .data section, and you will also get more efficient code in some cases.

Let's look at some examples:

.data
ten: .word 10
million: .word 1000000

.text 
main:
    lw $t0,ten
    li $t1,10
    lw $t2,million
    li $t3,1000000

It's important to understand here that both lw and li are pseudo-instructions that get translated into one or more actual instructions. lw does exist in the MIPS instruction set, but this particular variant of it doesn't. li doesn't exist in the MIPS instruction set.

If we look at what SPIM generates for the first two instructions, we see:

[0x00400024]    0x3c011001  lui $1, 4097                    ; 9: lw $t0,ten
[0x00400028]    0x8c280000  lw $8, 0($1)

[0x0040002c]    0x3409000a  ori $9, $0, 10                  ; 10: li $t1,10

So that's one additional instruction for the lw variant, as the address first has to be loaded into a register, and then the value is loaded from that address. This also means one additional (potentially slow) memory access (well, two if you count the instruction fetch).

Now let's look at the other two instructions, where the value to be loaded is too large to be encoded in a single instruction:

[0x00400030]    0x3c011001  lui $1, 4097                    ; 11: lw $t2,million
[0x00400034]    0x8c2a0004  lw $10, 4($1)

[0x00400038]    0x3c01000f  lui $1, 15                      ; 12: li $t3,1000000
[0x0040003c]    0x342b4240  ori $11, $1, 16960

Here the immediate 1000000 is loaded using two instructions as (15 << 16) | 16960. So both variants require two instructions, but the li variant doesn't need to read from memory.


If you want to assign a meaningful name to a constant to avoid having magic numbers all over your code you can do so with =:

TEN = 10

li $t0, TEN   # Expands to li $t0, 10

You could perhaps avoid loading the addresses for lw all the time by using $gp-relative addressing, but I feel that that's beyond the scope of this question.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for that extensive reply!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.