For a Z80 backend, "eliminateCallFramePseudoInstr()" shall adjust the stack pointer in three possible ways, e.g. after a function call, depending on the amount (= adjustment size) *and some other rules*:
1. via one or more target "pop <reg>" instructions (SP increments +2 per instruction), using an unused reg (disregarding the contents after the operation), followed by an optional +1 increment on the SP for odd amounds (SP can be inc/dec'd by 1 directly).
2. incrementing the SP register directly with a special target operation (increments +1 per operation), without using any other register. Requires twice as much instructions as "pop" in sequence, though.
3. via a long sequence of target-specific arithmetic instructions that involves a scratch reg (which would have to be saved before and restored after the call). This should only be used for larger sizes of call frame index.
Option 1 ("pop"s) is by far preferred for small call frame sizes. However, this requires finding a suitable register. And this is where it gets complicated:
"Suitable" for option 1 means that it shall be any of the 4 physical registers AF, HL, DE, BC. When invoked after a function call to do caller-cleans-stack, none of the register(s) used for return value of the function call shall be used. The calling convention uses
- one specific pysical 8 bit register (lower 8 bits of AF) for 8 bit return values
- one specific physical 16 bit register (reg HL) for 16 bit
- two 16 bit regs (regs HL + DE) for 32 bits return value
When determining if one of those registers is available for the option 1 way of cleaning-up the stack after a function call, reverse-order priority is preferred: BC, DE, HL, AF - due to the highly asymmetric command set of the Z80, the "least otherwise usable" register should be used for that operation, starting with "BC".
Now my questions are:
A) Is there a way to check if any of those registers are free at that point (in eliminateCallFramePseudoInstr()) - i.e. not used as return or to hold other values?
B) If it could be determined that none of the registers are free, option 2 (adjusting the SP by a series of +1) should be used for small amounts of call frame size, option 1 with the forced register "BC" for "pop" for mid amounts, and option 3 for larger amounts.
Now if register "BC" is forced to be used to clean the stack up after a function call, it should be saved (via "push") on the stack before the function is called, or to be specific, even *before* the first function parameter for the upcoming function call is pushed to the stack. And restored after call frame cleanup (after tha last call-frame-elimination-"pop") - by another "pop", restoring the original value.
Would "createVirtualRegister" with a register class containing only that register do exactly that?
Or is there a better way to do this?