1311116Sdim//===-- AVRISelDAGToDAG.cpp - A dag to dag inst selector for AVR ----------===//
2311116Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6311116Sdim//
7311116Sdim//===----------------------------------------------------------------------===//
8311116Sdim//
9311116Sdim// This file defines an instruction selector for the AVR target.
10311116Sdim//
11311116Sdim//===----------------------------------------------------------------------===//
12311116Sdim
13311116Sdim#include "AVR.h"
14311116Sdim#include "AVRTargetMachine.h"
15311116Sdim#include "MCTargetDesc/AVRMCTargetDesc.h"
16311116Sdim
17311116Sdim#include "llvm/CodeGen/MachineRegisterInfo.h"
18311116Sdim#include "llvm/CodeGen/SelectionDAGISel.h"
19311116Sdim#include "llvm/Support/Debug.h"
20311116Sdim#include "llvm/Support/raw_ostream.h"
21311116Sdim
22311116Sdim#define DEBUG_TYPE "avr-isel"
23311116Sdim
24311116Sdimnamespace llvm {
25311116Sdim
26311116Sdim/// Lowers LLVM IR (in DAG form) to AVR MC instructions (in DAG form).
27311116Sdimclass AVRDAGToDAGISel : public SelectionDAGISel {
28311116Sdimpublic:
29311116Sdim  AVRDAGToDAGISel(AVRTargetMachine &TM, CodeGenOpt::Level OptLevel)
30311116Sdim      : SelectionDAGISel(TM, OptLevel), Subtarget(nullptr) {}
31311116Sdim
32311116Sdim  StringRef getPassName() const override {
33311116Sdim    return "AVR DAG->DAG Instruction Selection";
34311116Sdim  }
35311116Sdim
36311116Sdim  bool runOnMachineFunction(MachineFunction &MF) override;
37311116Sdim
38311116Sdim  bool SelectAddr(SDNode *Op, SDValue N, SDValue &Base, SDValue &Disp);
39311116Sdim
40311116Sdim  bool selectIndexedLoad(SDNode *N);
41311116Sdim  unsigned selectIndexedProgMemLoad(const LoadSDNode *LD, MVT VT);
42311116Sdim
43311116Sdim  bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintCode,
44311116Sdim                                    std::vector<SDValue> &OutOps) override;
45311116Sdim
46311116Sdim// Include the pieces autogenerated from the target description.
47311116Sdim#include "AVRGenDAGISel.inc"
48311116Sdim
49311116Sdimprivate:
50311116Sdim  void Select(SDNode *N) override;
51311116Sdim  bool trySelect(SDNode *N);
52311116Sdim
53311116Sdim  template <unsigned NodeType> bool select(SDNode *N);
54311116Sdim  bool selectMultiplication(SDNode *N);
55311116Sdim
56311116Sdim  const AVRSubtarget *Subtarget;
57311116Sdim};
58311116Sdim
59311116Sdimbool AVRDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
60311116Sdim  Subtarget = &MF.getSubtarget<AVRSubtarget>();
61311116Sdim  return SelectionDAGISel::runOnMachineFunction(MF);
62311116Sdim}
63311116Sdim
64311116Sdimbool AVRDAGToDAGISel::SelectAddr(SDNode *Op, SDValue N, SDValue &Base,
65311116Sdim                                 SDValue &Disp) {
66311116Sdim  SDLoc dl(Op);
67311116Sdim  auto DL = CurDAG->getDataLayout();
68311116Sdim  MVT PtrVT = getTargetLowering()->getPointerTy(DL);
69311116Sdim
70311116Sdim  // if the address is a frame index get the TargetFrameIndex.
71311116Sdim  if (const FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(N)) {
72311116Sdim    Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), PtrVT);
73311116Sdim    Disp = CurDAG->getTargetConstant(0, dl, MVT::i8);
74311116Sdim
75311116Sdim    return true;
76311116Sdim  }
77311116Sdim
78311116Sdim  // Match simple Reg + uimm6 operands.
79311116Sdim  if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB &&
80311116Sdim      !CurDAG->isBaseWithConstantOffset(N)) {
81311116Sdim    return false;
82311116Sdim  }
83311116Sdim
84311116Sdim  if (const ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
85311116Sdim    int RHSC = (int)RHS->getZExtValue();
86311116Sdim
87311116Sdim    // Convert negative offsets into positives ones.
88311116Sdim    if (N.getOpcode() == ISD::SUB) {
89311116Sdim      RHSC = -RHSC;
90311116Sdim    }
91311116Sdim
92311116Sdim    // <#Frame index + const>
93311116Sdim    // Allow folding offsets bigger than 63 so the frame pointer can be used
94311116Sdim    // directly instead of copying it around by adjusting and restoring it for
95311116Sdim    // each access.
96311116Sdim    if (N.getOperand(0).getOpcode() == ISD::FrameIndex) {
97311116Sdim      int FI = cast<FrameIndexSDNode>(N.getOperand(0))->getIndex();
98311116Sdim
99311116Sdim      Base = CurDAG->getTargetFrameIndex(FI, PtrVT);
100311116Sdim      Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i16);
101311116Sdim
102311116Sdim      return true;
103311116Sdim    }
104311116Sdim
105311116Sdim    // The value type of the memory instruction determines what is the maximum
106311116Sdim    // offset allowed.
107311116Sdim    MVT VT = cast<MemSDNode>(Op)->getMemoryVT().getSimpleVT();
108311116Sdim
109311116Sdim    // We only accept offsets that fit in 6 bits (unsigned).
110311116Sdim    if (isUInt<6>(RHSC) && (VT == MVT::i8 || VT == MVT::i16)) {
111311116Sdim      Base = N.getOperand(0);
112311116Sdim      Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i8);
113311116Sdim
114311116Sdim      return true;
115311116Sdim    }
116311116Sdim  }
117311116Sdim
118311116Sdim  return false;
119311116Sdim}
120311116Sdim
121311116Sdimbool AVRDAGToDAGISel::selectIndexedLoad(SDNode *N) {
122311116Sdim  const LoadSDNode *LD = cast<LoadSDNode>(N);
123311116Sdim  ISD::MemIndexedMode AM = LD->getAddressingMode();
124311116Sdim  MVT VT = LD->getMemoryVT().getSimpleVT();
125311116Sdim  auto PtrVT = getTargetLowering()->getPointerTy(CurDAG->getDataLayout());
126311116Sdim
127311116Sdim  // We only care if this load uses a POSTINC or PREDEC mode.
128311116Sdim  if ((LD->getExtensionType() != ISD::NON_EXTLOAD) ||
129311116Sdim      (AM != ISD::POST_INC && AM != ISD::PRE_DEC)) {
130311116Sdim
131311116Sdim    return false;
132311116Sdim  }
133311116Sdim
134311116Sdim  unsigned Opcode = 0;
135311116Sdim  bool isPre = (AM == ISD::PRE_DEC);
136311116Sdim  int Offs = cast<ConstantSDNode>(LD->getOffset())->getSExtValue();
137311116Sdim
138311116Sdim  switch (VT.SimpleTy) {
139311116Sdim  case MVT::i8: {
140311116Sdim    if ((!isPre && Offs != 1) || (isPre && Offs != -1)) {
141311116Sdim      return false;
142311116Sdim    }
143311116Sdim
144311116Sdim    Opcode = (isPre) ? AVR::LDRdPtrPd : AVR::LDRdPtrPi;
145311116Sdim    break;
146311116Sdim  }
147311116Sdim  case MVT::i16: {
148311116Sdim    if ((!isPre && Offs != 2) || (isPre && Offs != -2)) {
149311116Sdim      return false;
150311116Sdim    }
151311116Sdim
152311116Sdim    Opcode = (isPre) ? AVR::LDWRdPtrPd : AVR::LDWRdPtrPi;
153311116Sdim    break;
154311116Sdim  }
155311116Sdim  default:
156311116Sdim    return false;
157311116Sdim  }
158311116Sdim
159311116Sdim  SDNode *ResNode = CurDAG->getMachineNode(Opcode, SDLoc(N), VT,
160311116Sdim                                           PtrVT, MVT::Other,
161311116Sdim                                           LD->getBasePtr(), LD->getChain());
162311116Sdim  ReplaceUses(N, ResNode);
163311116Sdim  CurDAG->RemoveDeadNode(N);
164311116Sdim
165311116Sdim  return true;
166311116Sdim}
167311116Sdim
168311116Sdimunsigned AVRDAGToDAGISel::selectIndexedProgMemLoad(const LoadSDNode *LD,
169311116Sdim                                                   MVT VT) {
170311116Sdim  ISD::MemIndexedMode AM = LD->getAddressingMode();
171311116Sdim
172311116Sdim  // Progmem indexed loads only work in POSTINC mode.
173311116Sdim  if (LD->getExtensionType() != ISD::NON_EXTLOAD || AM != ISD::POST_INC) {
174311116Sdim    return 0;
175311116Sdim  }
176311116Sdim
177311116Sdim  unsigned Opcode = 0;
178311116Sdim  int Offs = cast<ConstantSDNode>(LD->getOffset())->getSExtValue();
179311116Sdim
180311116Sdim  switch (VT.SimpleTy) {
181311116Sdim  case MVT::i8: {
182311116Sdim    if (Offs != 1) {
183311116Sdim      return 0;
184311116Sdim    }
185311116Sdim    Opcode = AVR::LPMRdZPi;
186311116Sdim    break;
187311116Sdim  }
188311116Sdim  case MVT::i16: {
189311116Sdim    if (Offs != 2) {
190311116Sdim      return 0;
191311116Sdim    }
192311116Sdim    Opcode = AVR::LPMWRdZPi;
193311116Sdim    break;
194311116Sdim  }
195311116Sdim  default:
196311116Sdim    return 0;
197311116Sdim  }
198311116Sdim
199311116Sdim  return Opcode;
200311116Sdim}
201311116Sdim
202311116Sdimbool AVRDAGToDAGISel::SelectInlineAsmMemoryOperand(const SDValue &Op,
203311116Sdim                                                   unsigned ConstraintCode,
204311116Sdim                                                   std::vector<SDValue> &OutOps) {
205311833Sdim  assert((ConstraintCode == InlineAsm::Constraint_m ||
206311833Sdim         ConstraintCode == InlineAsm::Constraint_Q) &&
207311116Sdim      "Unexpected asm memory constraint");
208311116Sdim
209311116Sdim  MachineRegisterInfo &RI = MF->getRegInfo();
210311116Sdim  const AVRSubtarget &STI = MF->getSubtarget<AVRSubtarget>();
211311116Sdim  const TargetLowering &TL = *STI.getTargetLowering();
212311116Sdim  SDLoc dl(Op);
213311116Sdim  auto DL = CurDAG->getDataLayout();
214311116Sdim
215311116Sdim  const RegisterSDNode *RegNode = dyn_cast<RegisterSDNode>(Op);
216311116Sdim
217311116Sdim  // If address operand is of PTRDISPREGS class, all is OK, then.
218311116Sdim  if (RegNode &&
219311116Sdim      RI.getRegClass(RegNode->getReg()) == &AVR::PTRDISPREGSRegClass) {
220311116Sdim    OutOps.push_back(Op);
221311116Sdim    return false;
222311116Sdim  }
223311116Sdim
224311116Sdim  if (Op->getOpcode() == ISD::FrameIndex) {
225311116Sdim    SDValue Base, Disp;
226311116Sdim
227311116Sdim    if (SelectAddr(Op.getNode(), Op, Base, Disp)) {
228311116Sdim      OutOps.push_back(Base);
229311116Sdim      OutOps.push_back(Disp);
230311116Sdim
231311116Sdim      return false;
232311116Sdim    }
233311116Sdim
234311116Sdim    return true;
235311116Sdim  }
236311116Sdim
237311116Sdim  // If Op is add 'register, immediate' and
238311116Sdim  // register is either virtual register or register of PTRDISPREGSRegClass
239311116Sdim  if (Op->getOpcode() == ISD::ADD || Op->getOpcode() == ISD::SUB) {
240311116Sdim    SDValue CopyFromRegOp = Op->getOperand(0);
241311116Sdim    SDValue ImmOp = Op->getOperand(1);
242311116Sdim    ConstantSDNode *ImmNode = dyn_cast<ConstantSDNode>(ImmOp);
243311116Sdim
244311116Sdim    unsigned Reg;
245311116Sdim    bool CanHandleRegImmOpt = true;
246311116Sdim
247311116Sdim    CanHandleRegImmOpt &= ImmNode != 0;
248311116Sdim    CanHandleRegImmOpt &= ImmNode->getAPIntValue().getZExtValue() < 64;
249311116Sdim
250311116Sdim    if (CopyFromRegOp->getOpcode() == ISD::CopyFromReg) {
251311116Sdim      RegisterSDNode *RegNode =
252311116Sdim          cast<RegisterSDNode>(CopyFromRegOp->getOperand(1));
253311116Sdim      Reg = RegNode->getReg();
254360784Sdim      CanHandleRegImmOpt &= (Register::isVirtualRegister(Reg) ||
255311116Sdim                             AVR::PTRDISPREGSRegClass.contains(Reg));
256311116Sdim    } else {
257311116Sdim      CanHandleRegImmOpt = false;
258311116Sdim    }
259311116Sdim
260311116Sdim    // If we detect proper case - correct virtual register class
261311116Sdim    // if needed and go to another inlineasm operand.
262311116Sdim    if (CanHandleRegImmOpt) {
263311116Sdim      SDValue Base, Disp;
264311116Sdim
265311116Sdim      if (RI.getRegClass(Reg) != &AVR::PTRDISPREGSRegClass) {
266311116Sdim        SDLoc dl(CopyFromRegOp);
267311116Sdim
268311116Sdim        unsigned VReg = RI.createVirtualRegister(&AVR::PTRDISPREGSRegClass);
269311116Sdim
270311116Sdim        SDValue CopyToReg =
271311116Sdim            CurDAG->getCopyToReg(CopyFromRegOp, dl, VReg, CopyFromRegOp);
272311116Sdim
273311116Sdim        SDValue NewCopyFromRegOp =
274311116Sdim            CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(DL));
275311116Sdim
276311116Sdim        Base = NewCopyFromRegOp;
277311116Sdim      } else {
278311116Sdim        Base = CopyFromRegOp;
279311116Sdim      }
280311116Sdim
281311116Sdim      if (ImmNode->getValueType(0) != MVT::i8) {
282311116Sdim        Disp = CurDAG->getTargetConstant(ImmNode->getAPIntValue().getZExtValue(), dl, MVT::i8);
283311116Sdim      } else {
284311116Sdim        Disp = ImmOp;
285311116Sdim      }
286311116Sdim
287311116Sdim      OutOps.push_back(Base);
288311116Sdim      OutOps.push_back(Disp);
289311116Sdim
290311116Sdim      return false;
291311116Sdim    }
292311116Sdim  }
293311116Sdim
294311116Sdim  // More generic case.
295311116Sdim  // Create chain that puts Op into pointer register
296311116Sdim  // and return that register.
297311116Sdim  unsigned VReg = RI.createVirtualRegister(&AVR::PTRDISPREGSRegClass);
298311116Sdim
299311116Sdim  SDValue CopyToReg = CurDAG->getCopyToReg(Op, dl, VReg, Op);
300311116Sdim  SDValue CopyFromReg =
301311116Sdim      CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(DL));
302311116Sdim
303311116Sdim  OutOps.push_back(CopyFromReg);
304311116Sdim
305311116Sdim  return false;
306311116Sdim}
307311116Sdim
308311116Sdimtemplate <> bool AVRDAGToDAGISel::select<ISD::FrameIndex>(SDNode *N) {
309311116Sdim  auto DL = CurDAG->getDataLayout();
310311116Sdim
311311116Sdim  // Convert the frameindex into a temp instruction that will hold the
312311116Sdim  // effective address of the final stack slot.
313311116Sdim  int FI = cast<FrameIndexSDNode>(N)->getIndex();
314311116Sdim  SDValue TFI =
315311116Sdim    CurDAG->getTargetFrameIndex(FI, getTargetLowering()->getPointerTy(DL));
316311116Sdim
317311116Sdim  CurDAG->SelectNodeTo(N, AVR::FRMIDX,
318311116Sdim                       getTargetLowering()->getPointerTy(DL), TFI,
319311116Sdim                       CurDAG->getTargetConstant(0, SDLoc(N), MVT::i16));
320311116Sdim  return true;
321311116Sdim}
322311116Sdim
323311116Sdimtemplate <> bool AVRDAGToDAGISel::select<ISD::STORE>(SDNode *N) {
324311116Sdim  // Use the STD{W}SPQRr pseudo instruction when passing arguments through
325311116Sdim  // the stack on function calls for further expansion during the PEI phase.
326311116Sdim  const StoreSDNode *ST = cast<StoreSDNode>(N);
327311116Sdim  SDValue BasePtr = ST->getBasePtr();
328311116Sdim
329311116Sdim  // Early exit when the base pointer is a frame index node or a constant.
330311116Sdim  if (isa<FrameIndexSDNode>(BasePtr) || isa<ConstantSDNode>(BasePtr) ||
331311116Sdim      BasePtr.isUndef()) {
332311116Sdim    return false;
333311116Sdim  }
334311116Sdim
335311116Sdim  const RegisterSDNode *RN = dyn_cast<RegisterSDNode>(BasePtr.getOperand(0));
336311116Sdim  // Only stores where SP is the base pointer are valid.
337311116Sdim  if (!RN || (RN->getReg() != AVR::SP)) {
338311116Sdim    return false;
339311116Sdim  }
340311116Sdim
341311116Sdim  int CST = (int)cast<ConstantSDNode>(BasePtr.getOperand(1))->getZExtValue();
342311116Sdim  SDValue Chain = ST->getChain();
343311116Sdim  EVT VT = ST->getValue().getValueType();
344311116Sdim  SDLoc DL(N);
345311116Sdim  SDValue Offset = CurDAG->getTargetConstant(CST, DL, MVT::i16);
346311116Sdim  SDValue Ops[] = {BasePtr.getOperand(0), Offset, ST->getValue(), Chain};
347311116Sdim  unsigned Opc = (VT == MVT::i16) ? AVR::STDWSPQRr : AVR::STDSPQRr;
348311116Sdim
349311116Sdim  SDNode *ResNode = CurDAG->getMachineNode(Opc, DL, MVT::Other, Ops);
350311116Sdim
351311116Sdim  // Transfer memory operands.
352344779Sdim  CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {ST->getMemOperand()});
353311116Sdim
354311116Sdim  ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
355311116Sdim  CurDAG->RemoveDeadNode(N);
356311116Sdim
357311116Sdim  return true;
358311116Sdim}
359311116Sdim
360311116Sdimtemplate <> bool AVRDAGToDAGISel::select<ISD::LOAD>(SDNode *N) {
361311116Sdim  const LoadSDNode *LD = cast<LoadSDNode>(N);
362311116Sdim  if (!AVR::isProgramMemoryAccess(LD)) {
363311116Sdim    // Check if the opcode can be converted into an indexed load.
364311116Sdim    return selectIndexedLoad(N);
365311116Sdim  }
366311116Sdim
367311116Sdim  assert(Subtarget->hasLPM() && "cannot load from program memory on this mcu");
368311116Sdim
369311116Sdim  // This is a flash memory load, move the pointer into R31R30 and emit
370311116Sdim  // the lpm instruction.
371311116Sdim  MVT VT = LD->getMemoryVT().getSimpleVT();
372311116Sdim  SDValue Chain = LD->getChain();
373311116Sdim  SDValue Ptr = LD->getBasePtr();
374311116Sdim  SDNode *ResNode;
375311116Sdim  SDLoc DL(N);
376311116Sdim
377311116Sdim  Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, Ptr, SDValue());
378311116Sdim  Ptr = CurDAG->getCopyFromReg(Chain, DL, AVR::R31R30, MVT::i16,
379311116Sdim                               Chain.getValue(1));
380311116Sdim
381311116Sdim  SDValue RegZ = CurDAG->getRegister(AVR::R31R30, MVT::i16);
382311116Sdim
383311116Sdim  // Check if the opcode can be converted into an indexed load.
384311116Sdim  if (unsigned LPMOpc = selectIndexedProgMemLoad(LD, VT)) {
385311116Sdim    // It is legal to fold the load into an indexed load.
386311116Sdim    ResNode = CurDAG->getMachineNode(LPMOpc, DL, VT, MVT::i16, MVT::Other, Ptr,
387311116Sdim                                     RegZ);
388311116Sdim    ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1));
389311116Sdim  } else {
390311116Sdim    // Selecting an indexed load is not legal, fallback to a normal load.
391311116Sdim    switch (VT.SimpleTy) {
392311116Sdim    case MVT::i8:
393311116Sdim      ResNode = CurDAG->getMachineNode(AVR::LPMRdZ, DL, MVT::i8, MVT::Other,
394311116Sdim                                       Ptr, RegZ);
395311116Sdim      break;
396311116Sdim    case MVT::i16:
397311116Sdim      ResNode = CurDAG->getMachineNode(AVR::LPMWRdZ, DL, MVT::i16,
398311116Sdim                                       MVT::Other, Ptr, RegZ);
399311116Sdim      ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1));
400311116Sdim      break;
401311116Sdim    default:
402311116Sdim      llvm_unreachable("Unsupported VT!");
403311116Sdim    }
404311116Sdim  }
405311116Sdim
406311116Sdim  // Transfer memory operands.
407344779Sdim  CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {LD->getMemOperand()});
408311116Sdim
409311116Sdim  ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
410311116Sdim  ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1));
411311116Sdim  CurDAG->RemoveDeadNode(N);
412311116Sdim
413311116Sdim  return true;
414311116Sdim}
415311116Sdim
416311116Sdimtemplate <> bool AVRDAGToDAGISel::select<AVRISD::CALL>(SDNode *N) {
417311116Sdim  SDValue InFlag;
418311116Sdim  SDValue Chain = N->getOperand(0);
419311116Sdim  SDValue Callee = N->getOperand(1);
420311116Sdim  unsigned LastOpNum = N->getNumOperands() - 1;
421311116Sdim
422311116Sdim  // Direct calls are autogenerated.
423311116Sdim  unsigned Op = Callee.getOpcode();
424311116Sdim  if (Op == ISD::TargetGlobalAddress || Op == ISD::TargetExternalSymbol) {
425311116Sdim    return false;
426311116Sdim  }
427311116Sdim
428311116Sdim  // Skip the incoming flag if present
429311116Sdim  if (N->getOperand(LastOpNum).getValueType() == MVT::Glue) {
430311116Sdim    --LastOpNum;
431311116Sdim  }
432311116Sdim
433311116Sdim  SDLoc DL(N);
434311116Sdim  Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, Callee, InFlag);
435311116Sdim  SmallVector<SDValue, 8> Ops;
436311116Sdim  Ops.push_back(CurDAG->getRegister(AVR::R31R30, MVT::i16));
437311116Sdim
438311116Sdim  // Map all operands into the new node.
439311116Sdim  for (unsigned i = 2, e = LastOpNum + 1; i != e; ++i) {
440311116Sdim    Ops.push_back(N->getOperand(i));
441311116Sdim  }
442311116Sdim
443311116Sdim  Ops.push_back(Chain);
444311116Sdim  Ops.push_back(Chain.getValue(1));
445311116Sdim
446311116Sdim  SDNode *ResNode =
447311116Sdim    CurDAG->getMachineNode(AVR::ICALL, DL, MVT::Other, MVT::Glue, Ops);
448311116Sdim
449311116Sdim  ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
450311116Sdim  ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1));
451311116Sdim  CurDAG->RemoveDeadNode(N);
452311116Sdim
453311116Sdim  return true;
454311116Sdim}
455311116Sdim
456311116Sdimtemplate <> bool AVRDAGToDAGISel::select<ISD::BRIND>(SDNode *N) {
457311116Sdim  SDValue Chain = N->getOperand(0);
458311116Sdim  SDValue JmpAddr = N->getOperand(1);
459311116Sdim
460311116Sdim  SDLoc DL(N);
461311116Sdim  // Move the destination address of the indirect branch into R31R30.
462311116Sdim  Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, JmpAddr);
463311116Sdim  SDNode *ResNode = CurDAG->getMachineNode(AVR::IJMP, DL, MVT::Other, Chain);
464311116Sdim
465311116Sdim  ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
466311116Sdim  CurDAG->RemoveDeadNode(N);
467311116Sdim
468311116Sdim  return true;
469311116Sdim}
470311116Sdim
471311116Sdimbool AVRDAGToDAGISel::selectMultiplication(llvm::SDNode *N) {
472311116Sdim  SDLoc DL(N);
473311116Sdim  MVT Type = N->getSimpleValueType(0);
474311116Sdim
475311116Sdim  assert(Type == MVT::i8 && "unexpected value type");
476311116Sdim
477311116Sdim  bool isSigned = N->getOpcode() == ISD::SMUL_LOHI;
478311116Sdim  unsigned MachineOp = isSigned ? AVR::MULSRdRr : AVR::MULRdRr;
479311116Sdim
480311116Sdim  SDValue Lhs = N->getOperand(0);
481311116Sdim  SDValue Rhs = N->getOperand(1);
482311116Sdim  SDNode *Mul = CurDAG->getMachineNode(MachineOp, DL, MVT::Glue, Lhs, Rhs);
483311116Sdim  SDValue InChain = CurDAG->getEntryNode();
484311116Sdim  SDValue InGlue = SDValue(Mul, 0);
485311116Sdim
486311116Sdim  // Copy the low half of the result, if it is needed.
487311116Sdim  if (N->hasAnyUseOfValue(0)) {
488311116Sdim    SDValue CopyFromLo =
489311116Sdim        CurDAG->getCopyFromReg(InChain, DL, AVR::R0, Type, InGlue);
490311116Sdim
491311116Sdim    ReplaceUses(SDValue(N, 0), CopyFromLo);
492311116Sdim
493311116Sdim    InChain = CopyFromLo.getValue(1);
494311116Sdim    InGlue = CopyFromLo.getValue(2);
495311116Sdim  }
496311116Sdim
497311116Sdim  // Copy the high half of the result, if it is needed.
498311116Sdim  if (N->hasAnyUseOfValue(1)) {
499311116Sdim    SDValue CopyFromHi =
500311116Sdim        CurDAG->getCopyFromReg(InChain, DL, AVR::R1, Type, InGlue);
501311116Sdim
502311116Sdim    ReplaceUses(SDValue(N, 1), CopyFromHi);
503311116Sdim
504311116Sdim    InChain = CopyFromHi.getValue(1);
505311116Sdim    InGlue = CopyFromHi.getValue(2);
506311116Sdim  }
507311116Sdim
508311116Sdim  CurDAG->RemoveDeadNode(N);
509311116Sdim
510311116Sdim  // We need to clear R1. This is currently done (dirtily)
511311116Sdim  // using a custom inserter.
512311116Sdim
513311116Sdim  return true;
514311116Sdim}
515311116Sdim
516311116Sdimvoid AVRDAGToDAGISel::Select(SDNode *N) {
517311116Sdim  // If we have a custom node, we already have selected!
518311116Sdim  if (N->isMachineOpcode()) {
519341825Sdim    LLVM_DEBUG(errs() << "== "; N->dump(CurDAG); errs() << "\n");
520311116Sdim    N->setNodeId(-1);
521311116Sdim    return;
522311116Sdim  }
523311116Sdim
524311116Sdim  // See if subclasses can handle this node.
525311116Sdim  if (trySelect(N))
526311116Sdim    return;
527311116Sdim
528311116Sdim  // Select the default instruction
529311116Sdim  SelectCode(N);
530311116Sdim}
531311116Sdim
532311116Sdimbool AVRDAGToDAGISel::trySelect(SDNode *N) {
533311116Sdim  unsigned Opcode = N->getOpcode();
534311116Sdim  SDLoc DL(N);
535311116Sdim
536311116Sdim  switch (Opcode) {
537311116Sdim  // Nodes we fully handle.
538311116Sdim  case ISD::FrameIndex: return select<ISD::FrameIndex>(N);
539311116Sdim  case ISD::BRIND:      return select<ISD::BRIND>(N);
540311116Sdim  case ISD::UMUL_LOHI:
541311116Sdim  case ISD::SMUL_LOHI:  return selectMultiplication(N);
542311116Sdim
543311116Sdim  // Nodes we handle partially. Other cases are autogenerated
544311116Sdim  case ISD::STORE:   return select<ISD::STORE>(N);
545311116Sdim  case ISD::LOAD:    return select<ISD::LOAD>(N);
546311116Sdim  case AVRISD::CALL: return select<AVRISD::CALL>(N);
547311116Sdim  default:           return false;
548311116Sdim  }
549311116Sdim}
550311116Sdim
551311116SdimFunctionPass *createAVRISelDag(AVRTargetMachine &TM,
552311116Sdim                               CodeGenOpt::Level OptLevel) {
553311116Sdim  return new AVRDAGToDAGISel(TM, OptLevel);
554311116Sdim}
555311116Sdim
556311116Sdim} // end of namespace llvm
557311116Sdim
558