Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loading an address in MIPS64

Tags:

mips

mips64

This is probably a simple, obvious thing I'm just not seeing, but how do I load an address in a MIPS64 processor? In a MIPS32 processor the following assembler pseudo-instruction:

la $at, LabelAddr

Expands into:

lui $at, LabelAddr[31:16]
ori $at,$at, LabelAddr[15:0]

Looking at the MIPS64 instruction set, I see that lui still loads a 16-bit immediate into the upper half of a 32-bit word. There doesn't appear to be any kind of expanded instruction that loads an immediate anywhere into the upper area of a 64-bit word. This seems, then, that to do the equivalent of an la pseudo-instruction I'd need to expand into code something like:

lui $at, LabelAddr[63:48]
ori $at, $at, LabelAddr[47:32]
sll $at, 16
ori $at, $at, LabelAddr[31:16]
sll $at, 16
ori $at, $at, LabelAddr[15:0]

This strikes me as a bit ... convoluted for something as basic as loading an address so it leaves me convinced that I've overlooked something.

What is it I've overlooked (if anything)?

like image 212
JUST MY correct OPINION Avatar asked Oct 12 '10 11:10

JUST MY correct OPINION


People also ask

How do I load words into MIPS?

The MIPS instruction that loads a word into a register is the lw instruction. The store word instruction is sw . Each must specify a register and a memory address. A MIPS instruction is 32 bits (always).

Is load word a pseudo instruction?

lw load a word from memory. Apart from the second, all are pseudo-instructions.

What is an address in MIPS?

A MIPS memory address is 32 bits (always). How can a load or store instruction specify an address that is the same size as itself? An instruction that refers to memory uses a base register and an offset. The base register is a general purpose register that contains a 32-bit address.

What is load word?

The lw pseudoinstruction copies a word of data from memory into a register seemingly in one instruction: lw d,exp # Load register $d with the value at # address exp.


1 Answers

I think if you need to load a lot of constants, you should put it in a constant pool (A.K.A "literal pool") near the current code and then load it by an ld instruction.

For example: $s0 contains the pool's base address, and the constant you want to load is at offset 48, you can load it to $t1 by the instruction ld $t1, 48($s0)

This technique is very common in ARM, where instructions could only load a 12-bit immediate (only later versions of ARM can load 16-bit immediates with some restrictions). And it is used in Java too.

However somehow MIPS compilers still always generate multiple instructions to load a 64-bit immediate. For example to load 0xfedcba0987654321 on MIPS gcc uses

    li      $2,-9568256       # 0xffffffffff6e0000
    daddiu  $2,$2,23813
    dsll    $2,$2,17
    daddiu  $2,$2,-30875
    dsll    $2,$2,16
    daddiu  $2,$2,17185

Many other RISC architectures have more efficient ways to load an immediate so they need less instructions, but still at least 4. Maybe the instruction cache cost is lower than data cache cost in those cases, or maybe someone just don't like that idea

Here's an example of handwritten constant pool on MIPS

# load pool base address
    dla $s0, pool
foo:
# just some placeholder
    addu $t0, $t0, $t1
bar:
# load from pool
    ld $a0, pool_foo($s0)
    ld $a1, pool_bar($s0)

.section pool
# macro helper to define a pool entry
.macro ENTRY label
pool_entry_\label\(): .quad \label
.equ pool_\label\(), pool_entry_\label - pool
.endm
ENTRY foo
ENTRY bar

I failed to persuade any MIPS compilers to emit a literal pool but here's a compiler-generated example on ARM

like image 77
phuclv Avatar answered Sep 20 '22 08:09

phuclv