Trouble with instructions for lowering load/store.

Hello.
I write backend for Z80 cpu and I have some trouble with lowering load/store nodes to different machine opcodes. Some target instructions work with specified registers (not all registers in RegisterClass). Often it's one or two registers. I don't understand how use ComplexPattern in this case. But if I don't use ComplexPattern I'll have other problems - not all instruction can select in InstructionSelection pass.

My work place here: https://github.com/earl1k/llvm-z80

Example of some load instructions for Z80 CPU with opcode:
Opcode Instruction node pattern
0x46 LD $dst,(HL) (set GR8:$dst, (load HL))
0x0A LD A,(BC) (set A, (load BC))
0x1A LD A,(DE) (set A, (load DE))
0x3A LD A,($src) (set A, (load i16imm:$src))

Target Description file:
...
let canFoldAsLoad = 1, isReMaterializable = 1 in {
   let Uses = [HL] in
   def LD8rm : IRy<0x46, (outs GR8:$dst), (ins),
     "ld\t{$dst, (hl)}", [(set GR8:$dst, (load HL))]>;
   let Defs = [A], Uses = [BC] in
   def LD8AmBC : I<0x0A, (outs), (ins),
     "ld\t{a, (bc)}", [(set A, (load BC))]>;
   let Defs = [A], Uses = [DE] in
   def LD8AmDE : I<0x1A, (outs), (ins),
     "ld\t{a, (bc)}", [(set A, (load DE))]>;
   let Defs = [A] in
   def LD8Am : II16<0x3A, (outs), (ins i16imm:$src),
     "ld\t{a, ($src)", [(set A, (load imm:$src))]>;
}
...

GR8 - i8 RegisterClass (contains registers: A, B, C, D, E, H, L)
GR16 - i16 RegisterClas (contains registers: BC, DE, HL)

I have some questions:
1. Can I specify the register in TargetLowering or SelectionDAGISel and how do it?
2. How most effectively and correctly define target instructions?

Thanks.

Hi Earl,

Example of some load instructions for Z80 CPU with opcode:
Opcode Instruction node pattern
0x46 LD $dst,(HL) (set GR8:$dst, (load HL))
0x0A LD A,(BC) (set A, (load BC))
0x1A LD A,(DE) (set A, (load DE))
0x3A LD A,($src) (set A, (load i16imm:$src))

Target Description file:
...
  def LD8rm : IRy<0x46, (outs GR8:$dst), (ins),
    "ld\t{$dst, (hl)}", [(set GR8:$dst, (load HL))]>;
...
GR8 - i8 RegisterClass (contains registers: A, B, C, D, E, H, L)
GR16 - i16 RegisterClas (contains registers: BC, DE, HL)

The biggest problem I see here is that by giving no input operands,
you've left yourself no way of specifying the address. A must clearly
be from somewhere you're interested in ("HL" is not enough, LLVM has
no idea what's there or why).

It may seem wasteful, but the obvious solution is to create more
registerclasses (each register can be in as many as needed). For the
example quoted, you'd want a register class containing just "HL". What
you name it is personal preference, I'll assume GPR_HL here.

Then you'd define your instruction by:

def LD8rm : IRy<0x46, (outs GR8:$dst), (ins GPR_HL:$addr),
  "ld\t{$dst, ($addr)}". [set GR8:$dst, (load GPR_HL:$addr)]>;

This tells LLVM that the instruction's going to have an operand that
represents the address. Sure it'll always be in HL, but at least LLVM
knows what's going on now.

The register allocator will come along to allocate that register,
obviously give it HL, and then decide of its own accord that it needs
a copy to get the address it's calculated into that register (or even
better to calculate the address there in the first place).

Your other instructions would do similar tricks, both to "ins" and "outs".

I don't understand how use ComplexPattern in this case.

A ComplexPattern may or may not be necessary here. My feeling is that
it's mostly present in existing targets to deal with the fact that
loads can have rather complicated possible addresses (e.g. register +
12-bit signed immediate shifted by the phase of the moon). In your
case, it appears that an address has to be put into a register, and
that's that (disclaimer: I know no more of Z80 than you've posted
here, I may be wrong).

Also, even with more complicated addressing modes you may be able to
get away without a ComplexPattern for loads/stores. I've recently
committed the AArch64 backend which did away of it in favour of some
TableGen. I'm still in two minds about whether it's a *better*
solution myself, but it is at least possible.

Let us know if you need more help.

Tim.