xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp (revision 6e516c87b6d779911edde7481d8aef165b837a03)
10b57cec5SDimitry Andric //===-- AVRISelDAGToDAG.cpp - A dag to dag inst selector for AVR ----------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines an instruction selector for the AVR target.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "AVR.h"
140b57cec5SDimitry Andric #include "AVRTargetMachine.h"
150b57cec5SDimitry Andric #include "MCTargetDesc/AVRMCTargetDesc.h"
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
180b57cec5SDimitry Andric #include "llvm/CodeGen/SelectionDAGISel.h"
190b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
200b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric #define DEBUG_TYPE "avr-isel"
23bdd1243dSDimitry Andric #define PASS_NAME "AVR DAG->DAG Instruction Selection"
240b57cec5SDimitry Andric 
25bdd1243dSDimitry Andric using namespace llvm;
26bdd1243dSDimitry Andric 
27bdd1243dSDimitry Andric namespace {
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric /// Lowers LLVM IR (in DAG form) to AVR MC instructions (in DAG form).
300b57cec5SDimitry Andric class AVRDAGToDAGISel : public SelectionDAGISel {
310b57cec5SDimitry Andric public:
32bdd1243dSDimitry Andric   AVRDAGToDAGISel() = delete;
33bdd1243dSDimitry Andric 
345f757f3fSDimitry Andric   AVRDAGToDAGISel(AVRTargetMachine &TM, CodeGenOptLevel OptLevel)
350fca6ea1SDimitry Andric       : SelectionDAGISel(TM, OptLevel), Subtarget(nullptr) {}
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric   bool SelectAddr(SDNode *Op, SDValue N, SDValue &Base, SDValue &Disp);
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric   bool selectIndexedLoad(SDNode *N);
4204eeddc0SDimitry Andric   unsigned selectIndexedProgMemLoad(const LoadSDNode *LD, MVT VT, int Bank);
430b57cec5SDimitry Andric 
445f757f3fSDimitry Andric   bool SelectInlineAsmMemoryOperand(const SDValue &Op,
455f757f3fSDimitry Andric                                     InlineAsm::ConstraintCode ConstraintCode,
460b57cec5SDimitry Andric                                     std::vector<SDValue> &OutOps) override;
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric // Include the pieces autogenerated from the target description.
490b57cec5SDimitry Andric #include "AVRGenDAGISel.inc"
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric private:
520b57cec5SDimitry Andric   void Select(SDNode *N) override;
530b57cec5SDimitry Andric   bool trySelect(SDNode *N);
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric   template <unsigned NodeType> bool select(SDNode *N);
560b57cec5SDimitry Andric   bool selectMultiplication(SDNode *N);
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric   const AVRSubtarget *Subtarget;
590b57cec5SDimitry Andric };
600b57cec5SDimitry Andric 
610fca6ea1SDimitry Andric class AVRDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
620fca6ea1SDimitry Andric public:
630fca6ea1SDimitry Andric   static char ID;
640fca6ea1SDimitry Andric   AVRDAGToDAGISelLegacy(AVRTargetMachine &TM, CodeGenOptLevel OptLevel)
650fca6ea1SDimitry Andric       : SelectionDAGISelLegacy(
660fca6ea1SDimitry Andric             ID, std::make_unique<AVRDAGToDAGISel>(TM, OptLevel)) {}
670fca6ea1SDimitry Andric };
680fca6ea1SDimitry Andric 
69bdd1243dSDimitry Andric } // namespace
70bdd1243dSDimitry Andric 
710fca6ea1SDimitry Andric char AVRDAGToDAGISelLegacy::ID = 0;
72bdd1243dSDimitry Andric 
730fca6ea1SDimitry Andric INITIALIZE_PASS(AVRDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
74bdd1243dSDimitry Andric 
750b57cec5SDimitry Andric bool AVRDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
760b57cec5SDimitry Andric   Subtarget = &MF.getSubtarget<AVRSubtarget>();
770b57cec5SDimitry Andric   return SelectionDAGISel::runOnMachineFunction(MF);
780b57cec5SDimitry Andric }
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric bool AVRDAGToDAGISel::SelectAddr(SDNode *Op, SDValue N, SDValue &Base,
810b57cec5SDimitry Andric                                  SDValue &Disp) {
820b57cec5SDimitry Andric   SDLoc dl(Op);
830b57cec5SDimitry Andric   auto DL = CurDAG->getDataLayout();
840b57cec5SDimitry Andric   MVT PtrVT = getTargetLowering()->getPointerTy(DL);
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric   // if the address is a frame index get the TargetFrameIndex.
870b57cec5SDimitry Andric   if (const FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(N)) {
880b57cec5SDimitry Andric     Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), PtrVT);
890b57cec5SDimitry Andric     Disp = CurDAG->getTargetConstant(0, dl, MVT::i8);
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric     return true;
920b57cec5SDimitry Andric   }
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric   // Match simple Reg + uimm6 operands.
950b57cec5SDimitry Andric   if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB &&
960b57cec5SDimitry Andric       !CurDAG->isBaseWithConstantOffset(N)) {
970b57cec5SDimitry Andric     return false;
980b57cec5SDimitry Andric   }
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric   if (const ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
1010b57cec5SDimitry Andric     int RHSC = (int)RHS->getZExtValue();
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric     // Convert negative offsets into positives ones.
1040b57cec5SDimitry Andric     if (N.getOpcode() == ISD::SUB) {
1050b57cec5SDimitry Andric       RHSC = -RHSC;
1060b57cec5SDimitry Andric     }
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric     // <#Frame index + const>
1090b57cec5SDimitry Andric     // Allow folding offsets bigger than 63 so the frame pointer can be used
1100b57cec5SDimitry Andric     // directly instead of copying it around by adjusting and restoring it for
1110b57cec5SDimitry Andric     // each access.
1120b57cec5SDimitry Andric     if (N.getOperand(0).getOpcode() == ISD::FrameIndex) {
1130b57cec5SDimitry Andric       int FI = cast<FrameIndexSDNode>(N.getOperand(0))->getIndex();
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric       Base = CurDAG->getTargetFrameIndex(FI, PtrVT);
1160b57cec5SDimitry Andric       Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i16);
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric       return true;
1190b57cec5SDimitry Andric     }
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric     // The value type of the memory instruction determines what is the maximum
1220b57cec5SDimitry Andric     // offset allowed.
1230b57cec5SDimitry Andric     MVT VT = cast<MemSDNode>(Op)->getMemoryVT().getSimpleVT();
1240b57cec5SDimitry Andric 
125*6e516c87SDimitry Andric     // We only accept offsets that fit in 6 bits (unsigned), with the exception
126*6e516c87SDimitry Andric     // of 16-bit loads - those can only go up to 62, because we desugar them
127*6e516c87SDimitry Andric     // into a pair of 8-bit loads like `ldd rx, RHSC` + `ldd ry, RHSC + 1`.
128*6e516c87SDimitry Andric     bool OkI8 = VT == MVT::i8 && RHSC <= 63;
129*6e516c87SDimitry Andric     bool OkI16 = VT == MVT::i16 && RHSC <= 62;
130*6e516c87SDimitry Andric 
131*6e516c87SDimitry Andric     if (OkI8 || OkI16) {
1320b57cec5SDimitry Andric       Base = N.getOperand(0);
1330b57cec5SDimitry Andric       Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i8);
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric       return true;
1360b57cec5SDimitry Andric     }
1370b57cec5SDimitry Andric   }
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric   return false;
1400b57cec5SDimitry Andric }
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric bool AVRDAGToDAGISel::selectIndexedLoad(SDNode *N) {
1430b57cec5SDimitry Andric   const LoadSDNode *LD = cast<LoadSDNode>(N);
1440b57cec5SDimitry Andric   ISD::MemIndexedMode AM = LD->getAddressingMode();
1450b57cec5SDimitry Andric   MVT VT = LD->getMemoryVT().getSimpleVT();
1460b57cec5SDimitry Andric   auto PtrVT = getTargetLowering()->getPointerTy(CurDAG->getDataLayout());
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric   // We only care if this load uses a POSTINC or PREDEC mode.
1490b57cec5SDimitry Andric   if ((LD->getExtensionType() != ISD::NON_EXTLOAD) ||
1500b57cec5SDimitry Andric       (AM != ISD::POST_INC && AM != ISD::PRE_DEC)) {
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric     return false;
1530b57cec5SDimitry Andric   }
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric   unsigned Opcode = 0;
1560b57cec5SDimitry Andric   bool isPre = (AM == ISD::PRE_DEC);
1570b57cec5SDimitry Andric   int Offs = cast<ConstantSDNode>(LD->getOffset())->getSExtValue();
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric   switch (VT.SimpleTy) {
1600b57cec5SDimitry Andric   case MVT::i8: {
1610b57cec5SDimitry Andric     if ((!isPre && Offs != 1) || (isPre && Offs != -1)) {
1620b57cec5SDimitry Andric       return false;
1630b57cec5SDimitry Andric     }
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric     Opcode = (isPre) ? AVR::LDRdPtrPd : AVR::LDRdPtrPi;
1660b57cec5SDimitry Andric     break;
1670b57cec5SDimitry Andric   }
1680b57cec5SDimitry Andric   case MVT::i16: {
1690b57cec5SDimitry Andric     if ((!isPre && Offs != 2) || (isPre && Offs != -2)) {
1700b57cec5SDimitry Andric       return false;
1710b57cec5SDimitry Andric     }
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric     Opcode = (isPre) ? AVR::LDWRdPtrPd : AVR::LDWRdPtrPi;
1740b57cec5SDimitry Andric     break;
1750b57cec5SDimitry Andric   }
1760b57cec5SDimitry Andric   default:
1770b57cec5SDimitry Andric     return false;
1780b57cec5SDimitry Andric   }
1790b57cec5SDimitry Andric 
180349cc55cSDimitry Andric   SDNode *ResNode =
181349cc55cSDimitry Andric       CurDAG->getMachineNode(Opcode, SDLoc(N), VT, PtrVT, MVT::Other,
1820b57cec5SDimitry Andric                              LD->getBasePtr(), LD->getChain());
1830b57cec5SDimitry Andric   ReplaceUses(N, ResNode);
1840b57cec5SDimitry Andric   CurDAG->RemoveDeadNode(N);
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric   return true;
1870b57cec5SDimitry Andric }
1880b57cec5SDimitry Andric 
18904eeddc0SDimitry Andric unsigned AVRDAGToDAGISel::selectIndexedProgMemLoad(const LoadSDNode *LD, MVT VT,
19004eeddc0SDimitry Andric                                                    int Bank) {
1910b57cec5SDimitry Andric   // Progmem indexed loads only work in POSTINC mode.
19204eeddc0SDimitry Andric   if (LD->getExtensionType() != ISD::NON_EXTLOAD ||
19304eeddc0SDimitry Andric       LD->getAddressingMode() != ISD::POST_INC)
1940b57cec5SDimitry Andric     return 0;
19504eeddc0SDimitry Andric 
19604eeddc0SDimitry Andric   // Feature ELPM is needed for loading from extended program memory.
19704eeddc0SDimitry Andric   assert((Bank == 0 || Subtarget->hasELPM()) &&
19804eeddc0SDimitry Andric          "cannot load from extended program memory on this mcu");
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric   unsigned Opcode = 0;
2010b57cec5SDimitry Andric   int Offs = cast<ConstantSDNode>(LD->getOffset())->getSExtValue();
2020b57cec5SDimitry Andric 
203bdd1243dSDimitry Andric   if (VT.SimpleTy == MVT::i8 && Offs == 1 && Bank == 0)
204bdd1243dSDimitry Andric     Opcode = AVR::LPMRdZPi;
205bdd1243dSDimitry Andric 
206bdd1243dSDimitry Andric   // TODO: Implements the expansion of the following pseudo instructions.
207bdd1243dSDimitry Andric   // LPMWRdZPi:  type == MVT::i16, offset == 2, Bank == 0.
208bdd1243dSDimitry Andric   // ELPMBRdZPi: type == MVT::i8,  offset == 1, Bank >  0.
209bdd1243dSDimitry Andric   // ELPMWRdZPi: type == MVT::i16, offset == 2, Bank >  0.
2100b57cec5SDimitry Andric 
2110b57cec5SDimitry Andric   return Opcode;
2120b57cec5SDimitry Andric }
2130b57cec5SDimitry Andric 
214349cc55cSDimitry Andric bool AVRDAGToDAGISel::SelectInlineAsmMemoryOperand(
2155f757f3fSDimitry Andric     const SDValue &Op, InlineAsm::ConstraintCode ConstraintCode,
2165f757f3fSDimitry Andric     std::vector<SDValue> &OutOps) {
2175f757f3fSDimitry Andric   assert((ConstraintCode == InlineAsm::ConstraintCode::m ||
2185f757f3fSDimitry Andric           ConstraintCode == InlineAsm::ConstraintCode::Q) &&
2190b57cec5SDimitry Andric          "Unexpected asm memory constraint");
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric   MachineRegisterInfo &RI = MF->getRegInfo();
2220b57cec5SDimitry Andric   const AVRSubtarget &STI = MF->getSubtarget<AVRSubtarget>();
2230b57cec5SDimitry Andric   const TargetLowering &TL = *STI.getTargetLowering();
2240b57cec5SDimitry Andric   SDLoc dl(Op);
2250b57cec5SDimitry Andric   auto DL = CurDAG->getDataLayout();
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric   const RegisterSDNode *RegNode = dyn_cast<RegisterSDNode>(Op);
2280b57cec5SDimitry Andric 
2290b57cec5SDimitry Andric   // If address operand is of PTRDISPREGS class, all is OK, then.
2300b57cec5SDimitry Andric   if (RegNode &&
2310b57cec5SDimitry Andric       RI.getRegClass(RegNode->getReg()) == &AVR::PTRDISPREGSRegClass) {
2320b57cec5SDimitry Andric     OutOps.push_back(Op);
2330b57cec5SDimitry Andric     return false;
2340b57cec5SDimitry Andric   }
2350b57cec5SDimitry Andric 
2360b57cec5SDimitry Andric   if (Op->getOpcode() == ISD::FrameIndex) {
2370b57cec5SDimitry Andric     SDValue Base, Disp;
2380b57cec5SDimitry Andric 
2390b57cec5SDimitry Andric     if (SelectAddr(Op.getNode(), Op, Base, Disp)) {
2400b57cec5SDimitry Andric       OutOps.push_back(Base);
2410b57cec5SDimitry Andric       OutOps.push_back(Disp);
2420b57cec5SDimitry Andric 
2430b57cec5SDimitry Andric       return false;
2440b57cec5SDimitry Andric     }
2450b57cec5SDimitry Andric 
2460b57cec5SDimitry Andric     return true;
2470b57cec5SDimitry Andric   }
2480b57cec5SDimitry Andric 
2490b57cec5SDimitry Andric   // If Op is add 'register, immediate' and
2500b57cec5SDimitry Andric   // register is either virtual register or register of PTRDISPREGSRegClass
2510b57cec5SDimitry Andric   if (Op->getOpcode() == ISD::ADD || Op->getOpcode() == ISD::SUB) {
2520b57cec5SDimitry Andric     SDValue CopyFromRegOp = Op->getOperand(0);
2530b57cec5SDimitry Andric     SDValue ImmOp = Op->getOperand(1);
2540b57cec5SDimitry Andric     ConstantSDNode *ImmNode = dyn_cast<ConstantSDNode>(ImmOp);
2550b57cec5SDimitry Andric 
2560b57cec5SDimitry Andric     unsigned Reg;
257e8d8bef9SDimitry Andric     bool CanHandleRegImmOpt = ImmNode && ImmNode->getAPIntValue().ult(64);
2580b57cec5SDimitry Andric 
2590b57cec5SDimitry Andric     if (CopyFromRegOp->getOpcode() == ISD::CopyFromReg) {
2600b57cec5SDimitry Andric       RegisterSDNode *RegNode =
2610b57cec5SDimitry Andric           cast<RegisterSDNode>(CopyFromRegOp->getOperand(1));
2620b57cec5SDimitry Andric       Reg = RegNode->getReg();
2638bcb0991SDimitry Andric       CanHandleRegImmOpt &= (Register::isVirtualRegister(Reg) ||
2640b57cec5SDimitry Andric                              AVR::PTRDISPREGSRegClass.contains(Reg));
2650b57cec5SDimitry Andric     } else {
2660b57cec5SDimitry Andric       CanHandleRegImmOpt = false;
2670b57cec5SDimitry Andric     }
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric     // If we detect proper case - correct virtual register class
2700b57cec5SDimitry Andric     // if needed and go to another inlineasm operand.
2710b57cec5SDimitry Andric     if (CanHandleRegImmOpt) {
2720b57cec5SDimitry Andric       SDValue Base, Disp;
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric       if (RI.getRegClass(Reg) != &AVR::PTRDISPREGSRegClass) {
2750b57cec5SDimitry Andric         SDLoc dl(CopyFromRegOp);
2760b57cec5SDimitry Andric 
2775ffd83dbSDimitry Andric         Register VReg = RI.createVirtualRegister(&AVR::PTRDISPREGSRegClass);
2780b57cec5SDimitry Andric 
2790b57cec5SDimitry Andric         SDValue CopyToReg =
2800b57cec5SDimitry Andric             CurDAG->getCopyToReg(CopyFromRegOp, dl, VReg, CopyFromRegOp);
2810b57cec5SDimitry Andric 
2820b57cec5SDimitry Andric         SDValue NewCopyFromRegOp =
2830b57cec5SDimitry Andric             CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(DL));
2840b57cec5SDimitry Andric 
2850b57cec5SDimitry Andric         Base = NewCopyFromRegOp;
2860b57cec5SDimitry Andric       } else {
2870b57cec5SDimitry Andric         Base = CopyFromRegOp;
2880b57cec5SDimitry Andric       }
2890b57cec5SDimitry Andric 
2900b57cec5SDimitry Andric       if (ImmNode->getValueType(0) != MVT::i8) {
29106c3fb27SDimitry Andric         Disp = CurDAG->getTargetConstant(ImmNode->getZExtValue(), dl, MVT::i8);
2920b57cec5SDimitry Andric       } else {
2930b57cec5SDimitry Andric         Disp = ImmOp;
2940b57cec5SDimitry Andric       }
2950b57cec5SDimitry Andric 
2960b57cec5SDimitry Andric       OutOps.push_back(Base);
2970b57cec5SDimitry Andric       OutOps.push_back(Disp);
2980b57cec5SDimitry Andric 
2990b57cec5SDimitry Andric       return false;
3000b57cec5SDimitry Andric     }
3010b57cec5SDimitry Andric   }
3020b57cec5SDimitry Andric 
3030b57cec5SDimitry Andric   // More generic case.
3040b57cec5SDimitry Andric   // Create chain that puts Op into pointer register
3050b57cec5SDimitry Andric   // and return that register.
3065ffd83dbSDimitry Andric   Register VReg = RI.createVirtualRegister(&AVR::PTRDISPREGSRegClass);
3070b57cec5SDimitry Andric 
3080b57cec5SDimitry Andric   SDValue CopyToReg = CurDAG->getCopyToReg(Op, dl, VReg, Op);
3090b57cec5SDimitry Andric   SDValue CopyFromReg =
3100b57cec5SDimitry Andric       CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(DL));
3110b57cec5SDimitry Andric 
3120b57cec5SDimitry Andric   OutOps.push_back(CopyFromReg);
3130b57cec5SDimitry Andric 
3140b57cec5SDimitry Andric   return false;
3150b57cec5SDimitry Andric }
3160b57cec5SDimitry Andric 
3170b57cec5SDimitry Andric template <> bool AVRDAGToDAGISel::select<ISD::FrameIndex>(SDNode *N) {
3180b57cec5SDimitry Andric   auto DL = CurDAG->getDataLayout();
3190b57cec5SDimitry Andric 
3200b57cec5SDimitry Andric   // Convert the frameindex into a temp instruction that will hold the
3210b57cec5SDimitry Andric   // effective address of the final stack slot.
3220b57cec5SDimitry Andric   int FI = cast<FrameIndexSDNode>(N)->getIndex();
3230b57cec5SDimitry Andric   SDValue TFI =
3240b57cec5SDimitry Andric       CurDAG->getTargetFrameIndex(FI, getTargetLowering()->getPointerTy(DL));
3250b57cec5SDimitry Andric 
326349cc55cSDimitry Andric   CurDAG->SelectNodeTo(N, AVR::FRMIDX, getTargetLowering()->getPointerTy(DL),
327349cc55cSDimitry Andric                        TFI, CurDAG->getTargetConstant(0, SDLoc(N), MVT::i16));
3280b57cec5SDimitry Andric   return true;
3290b57cec5SDimitry Andric }
3300b57cec5SDimitry Andric 
3310b57cec5SDimitry Andric template <> bool AVRDAGToDAGISel::select<ISD::STORE>(SDNode *N) {
3320b57cec5SDimitry Andric   // Use the STD{W}SPQRr pseudo instruction when passing arguments through
3330b57cec5SDimitry Andric   // the stack on function calls for further expansion during the PEI phase.
3340b57cec5SDimitry Andric   const StoreSDNode *ST = cast<StoreSDNode>(N);
3350b57cec5SDimitry Andric   SDValue BasePtr = ST->getBasePtr();
3360b57cec5SDimitry Andric 
3370b57cec5SDimitry Andric   // Early exit when the base pointer is a frame index node or a constant.
3380b57cec5SDimitry Andric   if (isa<FrameIndexSDNode>(BasePtr) || isa<ConstantSDNode>(BasePtr) ||
3390b57cec5SDimitry Andric       BasePtr.isUndef()) {
3400b57cec5SDimitry Andric     return false;
3410b57cec5SDimitry Andric   }
3420b57cec5SDimitry Andric 
3430b57cec5SDimitry Andric   const RegisterSDNode *RN = dyn_cast<RegisterSDNode>(BasePtr.getOperand(0));
3440b57cec5SDimitry Andric   // Only stores where SP is the base pointer are valid.
3450b57cec5SDimitry Andric   if (!RN || (RN->getReg() != AVR::SP)) {
3460b57cec5SDimitry Andric     return false;
3470b57cec5SDimitry Andric   }
3480b57cec5SDimitry Andric 
349647cbc5dSDimitry Andric   int CST = (int)BasePtr.getConstantOperandVal(1);
3500b57cec5SDimitry Andric   SDValue Chain = ST->getChain();
3510b57cec5SDimitry Andric   EVT VT = ST->getValue().getValueType();
3520b57cec5SDimitry Andric   SDLoc DL(N);
3530b57cec5SDimitry Andric   SDValue Offset = CurDAG->getTargetConstant(CST, DL, MVT::i16);
3540b57cec5SDimitry Andric   SDValue Ops[] = {BasePtr.getOperand(0), Offset, ST->getValue(), Chain};
3550b57cec5SDimitry Andric   unsigned Opc = (VT == MVT::i16) ? AVR::STDWSPQRr : AVR::STDSPQRr;
3560b57cec5SDimitry Andric 
3570b57cec5SDimitry Andric   SDNode *ResNode = CurDAG->getMachineNode(Opc, DL, MVT::Other, Ops);
3580b57cec5SDimitry Andric 
3590b57cec5SDimitry Andric   // Transfer memory operands.
3600b57cec5SDimitry Andric   CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {ST->getMemOperand()});
3610b57cec5SDimitry Andric 
3620b57cec5SDimitry Andric   ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
3630b57cec5SDimitry Andric   CurDAG->RemoveDeadNode(N);
3640b57cec5SDimitry Andric 
3650b57cec5SDimitry Andric   return true;
3660b57cec5SDimitry Andric }
3670b57cec5SDimitry Andric 
3680b57cec5SDimitry Andric template <> bool AVRDAGToDAGISel::select<ISD::LOAD>(SDNode *N) {
3690b57cec5SDimitry Andric   const LoadSDNode *LD = cast<LoadSDNode>(N);
3700b57cec5SDimitry Andric   if (!AVR::isProgramMemoryAccess(LD)) {
3710b57cec5SDimitry Andric     // Check if the opcode can be converted into an indexed load.
3720b57cec5SDimitry Andric     return selectIndexedLoad(N);
3730b57cec5SDimitry Andric   }
3740b57cec5SDimitry Andric 
37504eeddc0SDimitry Andric   if (!Subtarget->hasLPM())
37604eeddc0SDimitry Andric     report_fatal_error("cannot load from program memory on this mcu");
37704eeddc0SDimitry Andric 
37804eeddc0SDimitry Andric   int ProgMemBank = AVR::getProgramMemoryBank(LD);
37904eeddc0SDimitry Andric   if (ProgMemBank < 0 || ProgMemBank > 5)
38004eeddc0SDimitry Andric     report_fatal_error("unexpected program memory bank");
38106c3fb27SDimitry Andric   if (ProgMemBank > 0 && !Subtarget->hasELPM())
38206c3fb27SDimitry Andric     report_fatal_error("unexpected program memory bank");
3830b57cec5SDimitry Andric 
3840b57cec5SDimitry Andric   // This is a flash memory load, move the pointer into R31R30 and emit
3850b57cec5SDimitry Andric   // the lpm instruction.
3860b57cec5SDimitry Andric   MVT VT = LD->getMemoryVT().getSimpleVT();
3870b57cec5SDimitry Andric   SDValue Chain = LD->getChain();
3880b57cec5SDimitry Andric   SDValue Ptr = LD->getBasePtr();
3890b57cec5SDimitry Andric   SDNode *ResNode;
3900b57cec5SDimitry Andric   SDLoc DL(N);
3910b57cec5SDimitry Andric 
3920b57cec5SDimitry Andric   Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, Ptr, SDValue());
3930b57cec5SDimitry Andric   Ptr = CurDAG->getCopyFromReg(Chain, DL, AVR::R31R30, MVT::i16,
3940b57cec5SDimitry Andric                                Chain.getValue(1));
3950b57cec5SDimitry Andric 
3960b57cec5SDimitry Andric   // Check if the opcode can be converted into an indexed load.
39704eeddc0SDimitry Andric   if (unsigned LPMOpc = selectIndexedProgMemLoad(LD, VT, ProgMemBank)) {
3980b57cec5SDimitry Andric     // It is legal to fold the load into an indexed load.
39904eeddc0SDimitry Andric     if (ProgMemBank == 0) {
400349cc55cSDimitry Andric       ResNode =
40104eeddc0SDimitry Andric           CurDAG->getMachineNode(LPMOpc, DL, VT, MVT::i16, MVT::Other, Ptr);
40204eeddc0SDimitry Andric     } else {
40304eeddc0SDimitry Andric       // Do not combine the LDI instruction into the ELPM pseudo instruction,
40404eeddc0SDimitry Andric       // since it may be reused by other ELPM pseudo instructions.
40504eeddc0SDimitry Andric       SDValue NC = CurDAG->getTargetConstant(ProgMemBank, DL, MVT::i8);
40604eeddc0SDimitry Andric       auto *NP = CurDAG->getMachineNode(AVR::LDIRdK, DL, MVT::i8, NC);
40704eeddc0SDimitry Andric       ResNode = CurDAG->getMachineNode(LPMOpc, DL, VT, MVT::i16, MVT::Other,
40804eeddc0SDimitry Andric                                        Ptr, SDValue(NP, 0));
40904eeddc0SDimitry Andric     }
4100b57cec5SDimitry Andric   } else {
4110b57cec5SDimitry Andric     // Selecting an indexed load is not legal, fallback to a normal load.
4120b57cec5SDimitry Andric     switch (VT.SimpleTy) {
4130b57cec5SDimitry Andric     case MVT::i8:
41404eeddc0SDimitry Andric       if (ProgMemBank == 0) {
41506c3fb27SDimitry Andric         unsigned Opc = Subtarget->hasLPMX() ? AVR::LPMRdZ : AVR::LPMBRdZ;
41604eeddc0SDimitry Andric         ResNode =
41706c3fb27SDimitry Andric             CurDAG->getMachineNode(Opc, DL, MVT::i8, MVT::Other, Ptr);
41804eeddc0SDimitry Andric       } else {
41904eeddc0SDimitry Andric         // Do not combine the LDI instruction into the ELPM pseudo instruction,
42004eeddc0SDimitry Andric         // since it may be reused by other ELPM pseudo instructions.
42104eeddc0SDimitry Andric         SDValue NC = CurDAG->getTargetConstant(ProgMemBank, DL, MVT::i8);
42204eeddc0SDimitry Andric         auto *NP = CurDAG->getMachineNode(AVR::LDIRdK, DL, MVT::i8, NC);
42304eeddc0SDimitry Andric         ResNode = CurDAG->getMachineNode(AVR::ELPMBRdZ, DL, MVT::i8, MVT::Other,
42404eeddc0SDimitry Andric                                          Ptr, SDValue(NP, 0));
42504eeddc0SDimitry Andric       }
4260b57cec5SDimitry Andric       break;
4270b57cec5SDimitry Andric     case MVT::i16:
42804eeddc0SDimitry Andric       if (ProgMemBank == 0) {
42904eeddc0SDimitry Andric         ResNode =
43004eeddc0SDimitry Andric             CurDAG->getMachineNode(AVR::LPMWRdZ, DL, MVT::i16, MVT::Other, Ptr);
43104eeddc0SDimitry Andric       } else {
43204eeddc0SDimitry Andric         // Do not combine the LDI instruction into the ELPM pseudo instruction,
43304eeddc0SDimitry Andric         // since LDI requires the destination register in range R16~R31.
43404eeddc0SDimitry Andric         SDValue NC = CurDAG->getTargetConstant(ProgMemBank, DL, MVT::i8);
43504eeddc0SDimitry Andric         auto *NP = CurDAG->getMachineNode(AVR::LDIRdK, DL, MVT::i8, NC);
43604eeddc0SDimitry Andric         ResNode = CurDAG->getMachineNode(AVR::ELPMWRdZ, DL, MVT::i16,
43704eeddc0SDimitry Andric                                          MVT::Other, Ptr, SDValue(NP, 0));
43804eeddc0SDimitry Andric       }
4390b57cec5SDimitry Andric       break;
4400b57cec5SDimitry Andric     default:
4410b57cec5SDimitry Andric       llvm_unreachable("Unsupported VT!");
4420b57cec5SDimitry Andric     }
4430b57cec5SDimitry Andric   }
4440b57cec5SDimitry Andric 
4450b57cec5SDimitry Andric   // Transfer memory operands.
4460b57cec5SDimitry Andric   CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {LD->getMemOperand()});
4470b57cec5SDimitry Andric 
4480b57cec5SDimitry Andric   ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
4490b57cec5SDimitry Andric   ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1));
4500b57cec5SDimitry Andric   CurDAG->RemoveDeadNode(N);
4510b57cec5SDimitry Andric 
4520b57cec5SDimitry Andric   return true;
4530b57cec5SDimitry Andric }
4540b57cec5SDimitry Andric 
4550b57cec5SDimitry Andric template <> bool AVRDAGToDAGISel::select<AVRISD::CALL>(SDNode *N) {
45606c3fb27SDimitry Andric   SDValue InGlue;
4570b57cec5SDimitry Andric   SDValue Chain = N->getOperand(0);
4580b57cec5SDimitry Andric   SDValue Callee = N->getOperand(1);
4590b57cec5SDimitry Andric   unsigned LastOpNum = N->getNumOperands() - 1;
4600b57cec5SDimitry Andric 
4610b57cec5SDimitry Andric   // Direct calls are autogenerated.
4620b57cec5SDimitry Andric   unsigned Op = Callee.getOpcode();
4630b57cec5SDimitry Andric   if (Op == ISD::TargetGlobalAddress || Op == ISD::TargetExternalSymbol) {
4640b57cec5SDimitry Andric     return false;
4650b57cec5SDimitry Andric   }
4660b57cec5SDimitry Andric 
4670b57cec5SDimitry Andric   // Skip the incoming flag if present
4680b57cec5SDimitry Andric   if (N->getOperand(LastOpNum).getValueType() == MVT::Glue) {
4690b57cec5SDimitry Andric     --LastOpNum;
4700b57cec5SDimitry Andric   }
4710b57cec5SDimitry Andric 
4720b57cec5SDimitry Andric   SDLoc DL(N);
47306c3fb27SDimitry Andric   Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, Callee, InGlue);
4740b57cec5SDimitry Andric   SmallVector<SDValue, 8> Ops;
4750b57cec5SDimitry Andric   Ops.push_back(CurDAG->getRegister(AVR::R31R30, MVT::i16));
4760b57cec5SDimitry Andric 
4770b57cec5SDimitry Andric   // Map all operands into the new node.
4780b57cec5SDimitry Andric   for (unsigned i = 2, e = LastOpNum + 1; i != e; ++i) {
4790b57cec5SDimitry Andric     Ops.push_back(N->getOperand(i));
4800b57cec5SDimitry Andric   }
4810b57cec5SDimitry Andric 
4820b57cec5SDimitry Andric   Ops.push_back(Chain);
4830b57cec5SDimitry Andric   Ops.push_back(Chain.getValue(1));
4840b57cec5SDimitry Andric 
485bdd1243dSDimitry Andric   SDNode *ResNode = CurDAG->getMachineNode(
486bdd1243dSDimitry Andric       Subtarget->hasEIJMPCALL() ? AVR::EICALL : AVR::ICALL, DL, MVT::Other,
487bdd1243dSDimitry Andric       MVT::Glue, Ops);
4880b57cec5SDimitry Andric 
4890b57cec5SDimitry Andric   ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
4900b57cec5SDimitry Andric   ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1));
4910b57cec5SDimitry Andric   CurDAG->RemoveDeadNode(N);
4920b57cec5SDimitry Andric 
4930b57cec5SDimitry Andric   return true;
4940b57cec5SDimitry Andric }
4950b57cec5SDimitry Andric 
4960b57cec5SDimitry Andric template <> bool AVRDAGToDAGISel::select<ISD::BRIND>(SDNode *N) {
4970b57cec5SDimitry Andric   SDValue Chain = N->getOperand(0);
4980b57cec5SDimitry Andric   SDValue JmpAddr = N->getOperand(1);
4990b57cec5SDimitry Andric 
5000b57cec5SDimitry Andric   SDLoc DL(N);
5010b57cec5SDimitry Andric   // Move the destination address of the indirect branch into R31R30.
5020b57cec5SDimitry Andric   Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, JmpAddr);
5030b57cec5SDimitry Andric   SDNode *ResNode = CurDAG->getMachineNode(AVR::IJMP, DL, MVT::Other, Chain);
5040b57cec5SDimitry Andric 
5050b57cec5SDimitry Andric   ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
5060b57cec5SDimitry Andric   CurDAG->RemoveDeadNode(N);
5070b57cec5SDimitry Andric 
5080b57cec5SDimitry Andric   return true;
5090b57cec5SDimitry Andric }
5100b57cec5SDimitry Andric 
5110b57cec5SDimitry Andric bool AVRDAGToDAGISel::selectMultiplication(llvm::SDNode *N) {
5120b57cec5SDimitry Andric   SDLoc DL(N);
5130b57cec5SDimitry Andric   MVT Type = N->getSimpleValueType(0);
5140b57cec5SDimitry Andric 
5150b57cec5SDimitry Andric   assert(Type == MVT::i8 && "unexpected value type");
5160b57cec5SDimitry Andric 
5170b57cec5SDimitry Andric   bool isSigned = N->getOpcode() == ISD::SMUL_LOHI;
5180b57cec5SDimitry Andric   unsigned MachineOp = isSigned ? AVR::MULSRdRr : AVR::MULRdRr;
5190b57cec5SDimitry Andric 
5200b57cec5SDimitry Andric   SDValue Lhs = N->getOperand(0);
5210b57cec5SDimitry Andric   SDValue Rhs = N->getOperand(1);
5220b57cec5SDimitry Andric   SDNode *Mul = CurDAG->getMachineNode(MachineOp, DL, MVT::Glue, Lhs, Rhs);
5230b57cec5SDimitry Andric   SDValue InChain = CurDAG->getEntryNode();
5240b57cec5SDimitry Andric   SDValue InGlue = SDValue(Mul, 0);
5250b57cec5SDimitry Andric 
5260b57cec5SDimitry Andric   // Copy the low half of the result, if it is needed.
5270b57cec5SDimitry Andric   if (N->hasAnyUseOfValue(0)) {
5280b57cec5SDimitry Andric     SDValue CopyFromLo =
5290b57cec5SDimitry Andric         CurDAG->getCopyFromReg(InChain, DL, AVR::R0, Type, InGlue);
5300b57cec5SDimitry Andric 
5310b57cec5SDimitry Andric     ReplaceUses(SDValue(N, 0), CopyFromLo);
5320b57cec5SDimitry Andric 
5330b57cec5SDimitry Andric     InChain = CopyFromLo.getValue(1);
5340b57cec5SDimitry Andric     InGlue = CopyFromLo.getValue(2);
5350b57cec5SDimitry Andric   }
5360b57cec5SDimitry Andric 
5370b57cec5SDimitry Andric   // Copy the high half of the result, if it is needed.
5380b57cec5SDimitry Andric   if (N->hasAnyUseOfValue(1)) {
5390b57cec5SDimitry Andric     SDValue CopyFromHi =
5400b57cec5SDimitry Andric         CurDAG->getCopyFromReg(InChain, DL, AVR::R1, Type, InGlue);
5410b57cec5SDimitry Andric 
5420b57cec5SDimitry Andric     ReplaceUses(SDValue(N, 1), CopyFromHi);
5430b57cec5SDimitry Andric 
5440b57cec5SDimitry Andric     InChain = CopyFromHi.getValue(1);
5450b57cec5SDimitry Andric     InGlue = CopyFromHi.getValue(2);
5460b57cec5SDimitry Andric   }
5470b57cec5SDimitry Andric 
5480b57cec5SDimitry Andric   CurDAG->RemoveDeadNode(N);
5490b57cec5SDimitry Andric 
5500b57cec5SDimitry Andric   // We need to clear R1. This is currently done (dirtily)
5510b57cec5SDimitry Andric   // using a custom inserter.
5520b57cec5SDimitry Andric 
5530b57cec5SDimitry Andric   return true;
5540b57cec5SDimitry Andric }
5550b57cec5SDimitry Andric 
5560b57cec5SDimitry Andric void AVRDAGToDAGISel::Select(SDNode *N) {
5570b57cec5SDimitry Andric   // If we have a custom node, we already have selected!
5580b57cec5SDimitry Andric   if (N->isMachineOpcode()) {
5590b57cec5SDimitry Andric     LLVM_DEBUG(errs() << "== "; N->dump(CurDAG); errs() << "\n");
5600b57cec5SDimitry Andric     N->setNodeId(-1);
5610b57cec5SDimitry Andric     return;
5620b57cec5SDimitry Andric   }
5630b57cec5SDimitry Andric 
5640b57cec5SDimitry Andric   // See if subclasses can handle this node.
5650b57cec5SDimitry Andric   if (trySelect(N))
5660b57cec5SDimitry Andric     return;
5670b57cec5SDimitry Andric 
5680b57cec5SDimitry Andric   // Select the default instruction
5690b57cec5SDimitry Andric   SelectCode(N);
5700b57cec5SDimitry Andric }
5710b57cec5SDimitry Andric 
5720b57cec5SDimitry Andric bool AVRDAGToDAGISel::trySelect(SDNode *N) {
5730b57cec5SDimitry Andric   unsigned Opcode = N->getOpcode();
5740b57cec5SDimitry Andric   SDLoc DL(N);
5750b57cec5SDimitry Andric 
5760b57cec5SDimitry Andric   switch (Opcode) {
5770b57cec5SDimitry Andric   // Nodes we fully handle.
578349cc55cSDimitry Andric   case ISD::FrameIndex:
579349cc55cSDimitry Andric     return select<ISD::FrameIndex>(N);
580349cc55cSDimitry Andric   case ISD::BRIND:
581349cc55cSDimitry Andric     return select<ISD::BRIND>(N);
5820b57cec5SDimitry Andric   case ISD::UMUL_LOHI:
583349cc55cSDimitry Andric   case ISD::SMUL_LOHI:
584349cc55cSDimitry Andric     return selectMultiplication(N);
5850b57cec5SDimitry Andric 
5860b57cec5SDimitry Andric   // Nodes we handle partially. Other cases are autogenerated
587349cc55cSDimitry Andric   case ISD::STORE:
588349cc55cSDimitry Andric     return select<ISD::STORE>(N);
589349cc55cSDimitry Andric   case ISD::LOAD:
590349cc55cSDimitry Andric     return select<ISD::LOAD>(N);
591349cc55cSDimitry Andric   case AVRISD::CALL:
592349cc55cSDimitry Andric     return select<AVRISD::CALL>(N);
593349cc55cSDimitry Andric   default:
594349cc55cSDimitry Andric     return false;
5950b57cec5SDimitry Andric   }
5960b57cec5SDimitry Andric }
5970b57cec5SDimitry Andric 
598bdd1243dSDimitry Andric FunctionPass *llvm::createAVRISelDag(AVRTargetMachine &TM,
5995f757f3fSDimitry Andric                                      CodeGenOptLevel OptLevel) {
6000fca6ea1SDimitry Andric   return new AVRDAGToDAGISelLegacy(TM, OptLevel);
6010b57cec5SDimitry Andric }
602