From what I understand, RISC architecture like MIPS, uses a fixed-length instruction. For branching and jumping between memory, and respectively J or I type - we are given a section inside to allocate 16 or 26 bits to offsets from the current memory (instruction offsets - multiples of 4 byte memory offsets). if this offsets cannot emcompass all possible 2^32 bits byte-address, how does it do it when it needs to?
CodePudding user response:
Generate the address in a register with one or more extra instructions. That's the tradeoff in limiting what one instruction can do (RISC), it's the cost of doing business.
Look at compiler output for MIPS or RISC-V:
int foo(char *arr){
return arr[0x12345678];
}
Godbolt for RISC-V and MIPS
# rv32gc clang -O2
foo:
lui a1, 74565 # 0x12345 into the upper 20 bits
add a0, a0, a1 # add high part of the offset to the incoming ptr
lbu a0, 1656(a0) # offset 0x678 with the 12-bit immediate
ret
RISC-V has a 20:12 split between LUI and I-type instructions. Costs less coding space.
MIPS has a 16:16 split, with LUI being an I-type instruction. So there are fewer opcode bits in each I-type instruction in MIPS than RISC-V.
But the strategy is identical; split the offset into high/low parts, do the low part as part of the load.
# MIPS gcc 11.2 -O2 -march=mips3 -fno-delayed-branch
foo:
li $2,305397760 # 0x12340000
addu $4,$4,$2 # add large offset to pointer
lb $2,22136($4) # sign-extending byte load
jr $31 # return
nop
(Note that RISC-V is a specific architecture, a more recent design led by one of the architects of MIPS, David Patterson. In some ways it's a cleaned-up re-spin of MIPS. Both are RISCs, like AArch64 or SPARC.)