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.
Tim Northover
2013-Feb-02 18:46 UTC
[LLVMdev] Trouble with instructions for lowering load/store.
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.
Possibly Parallel Threads
- [LLVMdev] A question about instruction operands.
- Printing PC-relative offsets - how to get the instruction length?
- [LLVMdev] A question about instruction operands.
- [LLVMdev] ISel using an operand as both source and destination
- [LLVMdev] ISel using an operand as both source and destination