I'm working on a Z80 backend and am trying to efficiently lower SEXT, specifically 8 to 16 bit, in LowerOperation() according to the following rules:
The Z80 has 8 bit registers and 16 bit registers, which are aliased versions of two 8 bit registers.
8 bit registers are named A, H, L, D, E and some more.
16 bit registers are HL (composed of H + L), DE (D + E) - and some more - with L and E being the low bits (LSB).
For SEXT from 8 to 16 bit, here are the rules to do it efficiently:
8 bit reg -> 16 bit reg
Fast extension:
L HL, by making MSB (H) = 0/255
E DE, by making MSB (D) = 0/255
Slow (costly) extension:
H HL or DE, by making LSB (D or L) = H and MSB (H) = 0/255
D same as above
Reg "A" doesn't have a 16 bit register pair, so SEXT must always done as a "slow" operation.
For the fast extension, how could an efficient lowering be done so L prefers being extended into HL and E into DE (and saving any previous content of H or D somewhere else)?
And for the slow extension, would creating a virtual 16 bit register pair for the destination also include a register pair that is composed of the source reg, i.e. H into HL - or even prefer it, if all are used?
Thanks,
Michael
I'm working on a Z80 backend and am trying to efficiently lower SEXT,
specifically 8 to 16 bit, in LowerOperation() according to the following
rules:
The Z80 has 8 bit registers and 16 bit registers, which are aliased
versions of two 8 bit registers.
8 bit registers are named A, H, L, D, E and some more.
16 bit registers are HL (composed of H + L), DE (D + E) - and some more -
with L and E being the low bits (LSB).
For SEXT from 8 to 16 bit, here are the rules to do it efficiently:
8 bit reg -> 16 bit reg
Fast extension:
L HL, by making MSB (H) = 0/255
E DE, by making MSB (D) = 0/255
Slow (costly) extension:
H HL or DE, by making LSB (D or L) = H and MSB (H) = 0/255
D same as above
Reg "A" doesn't have a 16 bit register pair, so SEXT must always done as a
"slow" operation.
I'm not sure it's a useful thing to insist on putting the high and low
bytes into a 16 bit register pair. Maybe that's the path of least
resistance with LLVM.
I don't think there's any particularly fast or slow places to start with
the value. In the place where you want the low half to end up is ideal of
course, but if not then it changes little. I don't think you can do better
than this?
LO -> HI || LO:
ld a, LO
rla
sbc a, a
ld HI, a
If the value starts in a, reverse the first instruction. If the value
starts somewhere else (even in HI) then move it to both LO and a. One more
instruction. Nothing else changes.
For the fast extension, how could an efficient lowering be done so L
prefers being extended into HL and E into DE (and saving any previous
content of H or D somewhere else)?
Again, you don't need to do that. If LLVM allocates the result into a 16
bit register, it will make sure by itself that nothing else useful is
already there.
Thank you very much Bruce!
Very well explained! I’m slowly getting the hang of how lowering is supposed to work in LLVM.
P.S. The code you posted is expert level, you are sure knowledgeable about the Z80! 
Ha! I did a little Z80 programming on a Sinclair ZX81 in 1981. I knew 6502
very well, before that.
That shift left then subtract-with-carry trick is exactly the same as you'd
use on 8080, 8085, and 8086/8.
6502 requires different tricks, as the sense of the carry bit is reversed
for subtract.