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