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