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
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…