-
Notifications
You must be signed in to change notification settings - Fork 10
Description
The current ABI always materialises globals with the sequence:
auipcc {reg}, {relocation on symbol} # usually relaxed away, occasionally rewritten to auicgp
cincoffset {reg}, {reg}, {relocation on auipcc} # usually rewrites source register to cgp, displacement in integer
csetbounds {reg}, {reg}, {size relocation on symbol}
In some cases, particularly when the size is large, but also when the same global is referenced a lot of times, this sequence will be shorter:
auipcc {reg}, {relocation to captable entry} # Usually a c.auipc, because you need a very large compartment to not be able to cover all of .text with c.aupic
clc {reg}, {relocation to auipcc}({reg})
This is actually a saving if the number of references to the global multiplied by the length of this sequence plus one capability (8 bytes), is greater than the number of occurrences of the earlier sequence. In the best case, this second sequence will be 6 bytes, in the worst 8 bytes. The common case for the first sequence is 8 bytes, so this requires four references to the same global to break even, and five to be a win, but for large globals, it's always a win because cincoffset + lui + csetbounds is 12 bytes of instruction and burns a register.
In addition, if we rewrite all references to a global to the latter sequence, the global no longer has to be reachable via cgp. We can then have the linker move it to a different section. This requires a bit of work in the loader because it now has two notions of compartment globals: the full set, and only those reachable from cgp. This will reduce the size of the section that ends up reachable via cgp, which, in turn, means that auicgp is less likely to be needed.
If we can do this in the toolchain, we could potentially eliminate auicgp entirely. This would be very nice because:
- It is a big instruction (in terms of encoding space).
- It is on the critical path for Ibex (so things could go faster without it).