Disable spilling sub-registers in LLVM

Hi,

I wonder if there is a way in LLVM to disable spilling a register-class while still enabling the super-registers of this register-class to be spilled.

If not, how can we implement spilling for sub-registers when stack load/stores can only operate on the super registers? Is there a way even if it is suboptimal?

Thanks,
Ahmed

Hi,

I wonder if there is a way in LLVM to disable spilling a register-class while still enabling the super-registers of this register-class to be spilled.

What would you have the register allocator do when it runs out of register and you have spilling disabled? Abort the compilation?

If you just want a special instruction sequence (like using a bigger loads/stores for the spills) then you should be able to implement that in storeRegToStackSlot()/loadRegFromStackSlot().

- Matthias

Hi Matthias,

No. I want the register allocator to spill the super-register (the large one e.g., 64-bit) and not just the sub-register (e.g., the 32-bit that is a piece of of the 64-bit register) because the stack loads/store width is 64-bit in this example.

RegClass1 (sub-registers): sub_registers (32-bit) --> can be natively used in arithmetic operations but no stack loads/stores for that width.

RegClass2 (super-registers): [sub_register, subregister] (64-bit) --> can be natively used in arithmetic operations and can be used in loads/stores.

Thanks,
Ahmed

Hi Ahmed,

If you access your values with sub-registers indices, IIRC the inline spiller will spill the super register.
If you access your values directly (via sub-regclass), then the spiller uses this class.

Basically what I am saying is the spiller spills the value that contains the accesses.

E.g.,
= v; will spill v
= v.sub1; will spill v too, but v is a super register in that case.

Cheers,
-Quentin

Hi Quentin,

Let me clarify if I understood this correctly.

If the accesses (writes and reads) to sub-registers are expressed always as sub-registers of the super-register register class (e.g., SuperReg.sub1;), then the spilling decision is for the super register.

But, if the accesses are in terms of the register class of the sub-registers directly (SubReg;), then the spilling decision will be for the sub-register.

So if we forced before register allocation all sub-register accesses to be accessed to "lanes" of the super register class then we guarantee that spilling is for the Super Registers only?

Thanks,
Ahmed

I still think my answer applies that you have to modify storeRegToStackSlot()/loadRegFromStackSlot(). They decide how registers are spilled and reloaded. Nobody is stopping you from using super registers spills/reloads to implement spilling/reloading smaller registers there.

- Matthias

Hi Quentin,

Let me clarify if I understood this correctly.

If the accesses (writes and reads) to sub-registers are expressed always as sub-registers of the super-register register class (e.g., SuperReg.sub1;), then the spilling decision is for the super register.

But, if the accesses are in terms of the register class of the sub-registers directly (SubReg;), then the spilling decision will be for the sub-register.

So if we forced before register allocation all sub-register accesses to be accessed to "lanes" of the super register class then we guarantee that spilling is for the Super Registers only?

That’s correct, however, Matthias’ suggestion will do what you want and is probably easier to achieve. I was just describing the current behavior.

Right Matthias, I am aware that an implementation for storeRegToStackSlot()/loadRegFromStackSlot() is necessary. But these functions receive the physical register that need to be spilled, they might receive the sub-register. In this case, using the super-register naively is unsafe (e.g., one might overwrite parts of it). Thus, I think the register allocator/spillar need to be aware of the exact register that is spilled.

To make my point clear, I believe an implementation of storeRegToStackSlot()/loadRegFromStackSlot() is not sufficient (as it received the physical register already). Does this make sense?

Well if you really have distinct subregisters[1] and cannot restore into one of the subregisters without clobbering the others then you probably have a situation that llvm doesn't support today (at least to my knowledge).

- Matthias

[1] i.e. not just something like X86 where rax/eax/ax can't really be divided except for ah/al)

Matthias's suggestion was to use the TII functions not to simply replace the smaller register with a larger one (which as you pointed out would not work), but to generate code that would effectively loaded/stored the small register, while using load/store instructions for larger registers. In other words, this code would have several instructions, that would make sure that the loaded value is correct in the end.

-Krzysztof