Hmm, I'm getting nowhere pretty fast. It seems 68000 with its CISC nature is quite complex to implement for a novice. I can see how to implement simple stuff, like -- move dn, dn move dn, (an) As that just turns into stores, sets, etc. But how would you represent things like indexed access? move dn, (an,dn) move dn, offset(an) Can I only really define very simple operations for the main instruction info, and then the rest comes as optimisation? It sounds like that may not be very efficient?
> As that just turns into stores, sets, etc. But how would you represent things like indexed access? > > move dn, (an,dn) > move dn, offset(an)These are fairly easy (the difficulty with the pre/post indexed modes is that they tend to define two values or otherwise not be tree-like in DAG form). For these you just put in a more complicated pattern representing the address calculation that happens. For example, with "(an, dn)" the address is "an+dn" so you'd write your pattern as: "(store i32:$Dn, (add i32:$An, i32:$Dm)". For the "Dn.W" variants you'll probably want to throw a trunc in there. And for the offset ones you'll want to define an "offsetimm" (or whatever your preferred name is) instance of ImmLeaf with i32 type (because addresses are 32-bits) but only accepting signed 16-bit values that can actually be encoded: def offsetimm : ImmLeaf<i32, [{ return Imm >= -32768 && Imm <= 32767; }]>; [...] (store i32:$Dn, (add i32:$An, offsetimm:$imm)) The biggest wrinkle is that you probably want to defer choosing whether to use An or Dn as the offset as long as possible. You could either fix that up later (optimisation!) or try to define these instructions to accept *both* Dn and An and then encode it properly. I'm afraid I don't know enough about the 68k instruction set to be sure which is better. Cheers. Tim.
On 9 Jul 2015, at 15:30, James Boulton <eiconic at googlemail.com> wrote:> > Hmm, I'm getting nowhere pretty fast. It seems 68000 with its CISC nature is quite complex to implement for a novice.As I said before, there’s a big difference between generating working m68k code and generating code that makes optimal use of the instruction set. I’d aim to get the former working first - use fairly naive mappings to instructions - and then look at peephole optimisations once you have some concrete cases of suboptimal code. It’s quite easy to have SelectionDAG emit instructions that are correct and then clean them up when you’re in the SSA machine instruction form. David
That's very helpful, thank-you! I've seen immediate offsets handled through an Operand define. How on earth does it know to put an offset into simm16 below along with the address in the register? It seems to be a more implicit way of doing the immediate add pattern you suggested, but I have no idea how this actually works. def simm16 : Operand<i32>; def mem : Operand<i32> { let MIOperandInfo = (ops AR, simm16); let PrintMethod = "printMemOperand"; } I prefer the explicit pattern method suggested, as I can understand what's going on, but I would really like to know how the Operand stuff actually works. Thanks! -----Original Message----- From: Tim Northover [mailto:t.p.northover at gmail.com] Sent: 09 July 2015 19:15 To: James Boulton Cc: LLVM Dev Subject: Re: [LLVMdev] New backend help request.> As that just turns into stores, sets, etc. But how would you represent things like indexed access? > > move dn, (an,dn) > move dn, offset(an)These are fairly easy (the difficulty with the pre/post indexed modes is that they tend to define two values or otherwise not be tree-like in DAG form). For these you just put in a more complicated pattern representing the address calculation that happens. For example, with "(an, dn)" the address is "an+dn" so you'd write your pattern as: "(store i32:$Dn, (add i32:$An, i32:$Dm)". For the "Dn.W" variants you'll probably want to throw a trunc in there. And for the offset ones you'll want to define an "offsetimm" (or whatever your preferred name is) instance of ImmLeaf with i32 type (because addresses are 32-bits) but only accepting signed 16-bit values that can actually be encoded: def offsetimm : ImmLeaf<i32, [{ return Imm >= -32768 && Imm <= 32767; }]>; [...] (store i32:$Dn, (add i32:$An, offsetimm:$imm)) The biggest wrinkle is that you probably want to defer choosing whether to use An or Dn as the offset as long as possible. You could either fix that up later (optimisation!) or try to define these instructions to accept *both* Dn and An and then encode it properly. I'm afraid I don't know enough about the 68k instruction set to be sure which is better. Cheers. Tim.