Hi all,
For education, and the fun of it, I’m writing an LLVM backend for the MC6809 processor. I’m using GlobalISel as that seems to be the future, and i’ve made a fair bit of progress with it.
The processor is strange by modern standards, so I have to make some design choices up front. I want LLVM to do as much of the work as I can, within reason. I’ve borrowed an idea from the llvm-mos project (for the 6502). Instruction are first lowered to pseudoinstructions modelling the processor’s general architecture, but leaving the registers in as classes, sometimes with only one register in the class. A later pass then lowers to the MC instruction once the register is known. So far so good.
I’ve got a tricky problem here, though. In trying to compile
char
subtract(char a)
{
return 71 - a;
}
I get
bb.1.entry:
liveins: $ab
%0:_(s8) = COPY $ab
%1:_(s8) = G_CONSTANT i8 71
%2:_(s8) = G_SUB %1:_, %0:_
$ab = COPY %2:_(s8)
ReturnImplicit implicit $ab
This is good, except that $ab is now in a register, but the constant is still virtual. The processor can’t directly do the subtraction - the contents of $ab would need to be deliberately spilled. Note that while the MC6809 does have 2 accumulators, A and B, arithmetic directly between them is not possible.
The final MC assembler should look something like
pshs b ; Push b onto the stack (or perhaps the frame)
ldb #71
subb ,s+ ; Subtract the value from ToS and pop stack (or frame)
rts
My question - I reckon I could do this with instruction bundles, but is there a cleaner way of deliberately spilling $ab into some stack- or frame-local storage? MemoryOperands look like they may appear at this point?
Another way of doing this could be
subb #71
negb
rts
… but this may get messy with multibyte subtractions and sorting out signed vs unsigned.