1 //===-- AVRISelDAGToDAG.cpp - A dag to dag inst selector for AVR ----------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines an instruction selector for the AVR target. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "AVR.h" 14 #include "AVRTargetMachine.h" 15 #include "MCTargetDesc/AVRMCTargetDesc.h" 16 17 #include "llvm/CodeGen/MachineRegisterInfo.h" 18 #include "llvm/CodeGen/SelectionDAGISel.h" 19 #include "llvm/Support/Debug.h" 20 #include "llvm/Support/raw_ostream.h" 21 22 #define DEBUG_TYPE "avr-isel" 23 #define PASS_NAME "AVR DAG->DAG Instruction Selection" 24 25 using namespace llvm; 26 27 namespace { 28 29 /// Lowers LLVM IR (in DAG form) to AVR MC instructions (in DAG form). 30 class AVRDAGToDAGISel : public SelectionDAGISel { 31 public: 32 static char ID; 33 34 AVRDAGToDAGISel() = delete; 35 36 AVRDAGToDAGISel(AVRTargetMachine &TM, CodeGenOpt::Level OptLevel) 37 : SelectionDAGISel(ID, TM, OptLevel), Subtarget(nullptr) {} 38 39 bool runOnMachineFunction(MachineFunction &MF) override; 40 41 bool SelectAddr(SDNode *Op, SDValue N, SDValue &Base, SDValue &Disp); 42 43 bool selectIndexedLoad(SDNode *N); 44 unsigned selectIndexedProgMemLoad(const LoadSDNode *LD, MVT VT, int Bank); 45 46 bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintCode, 47 std::vector<SDValue> &OutOps) override; 48 49 // Include the pieces autogenerated from the target description. 50 #include "AVRGenDAGISel.inc" 51 52 private: 53 void Select(SDNode *N) override; 54 bool trySelect(SDNode *N); 55 56 template <unsigned NodeType> bool select(SDNode *N); 57 bool selectMultiplication(SDNode *N); 58 59 const AVRSubtarget *Subtarget; 60 }; 61 62 } // namespace 63 64 char AVRDAGToDAGISel::ID = 0; 65 66 INITIALIZE_PASS(AVRDAGToDAGISel, DEBUG_TYPE, PASS_NAME, false, false) 67 68 bool AVRDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { 69 Subtarget = &MF.getSubtarget<AVRSubtarget>(); 70 return SelectionDAGISel::runOnMachineFunction(MF); 71 } 72 73 bool AVRDAGToDAGISel::SelectAddr(SDNode *Op, SDValue N, SDValue &Base, 74 SDValue &Disp) { 75 SDLoc dl(Op); 76 auto DL = CurDAG->getDataLayout(); 77 MVT PtrVT = getTargetLowering()->getPointerTy(DL); 78 79 // if the address is a frame index get the TargetFrameIndex. 80 if (const FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(N)) { 81 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), PtrVT); 82 Disp = CurDAG->getTargetConstant(0, dl, MVT::i8); 83 84 return true; 85 } 86 87 // Match simple Reg + uimm6 operands. 88 if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB && 89 !CurDAG->isBaseWithConstantOffset(N)) { 90 return false; 91 } 92 93 if (const ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { 94 int RHSC = (int)RHS->getZExtValue(); 95 96 // Convert negative offsets into positives ones. 97 if (N.getOpcode() == ISD::SUB) { 98 RHSC = -RHSC; 99 } 100 101 // <#Frame index + const> 102 // Allow folding offsets bigger than 63 so the frame pointer can be used 103 // directly instead of copying it around by adjusting and restoring it for 104 // each access. 105 if (N.getOperand(0).getOpcode() == ISD::FrameIndex) { 106 int FI = cast<FrameIndexSDNode>(N.getOperand(0))->getIndex(); 107 108 Base = CurDAG->getTargetFrameIndex(FI, PtrVT); 109 Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i16); 110 111 return true; 112 } 113 114 // The value type of the memory instruction determines what is the maximum 115 // offset allowed. 116 MVT VT = cast<MemSDNode>(Op)->getMemoryVT().getSimpleVT(); 117 118 // We only accept offsets that fit in 6 bits (unsigned). 119 if (isUInt<6>(RHSC) && (VT == MVT::i8 || VT == MVT::i16)) { 120 Base = N.getOperand(0); 121 Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i8); 122 123 return true; 124 } 125 } 126 127 return false; 128 } 129 130 bool AVRDAGToDAGISel::selectIndexedLoad(SDNode *N) { 131 const LoadSDNode *LD = cast<LoadSDNode>(N); 132 ISD::MemIndexedMode AM = LD->getAddressingMode(); 133 MVT VT = LD->getMemoryVT().getSimpleVT(); 134 auto PtrVT = getTargetLowering()->getPointerTy(CurDAG->getDataLayout()); 135 136 // We only care if this load uses a POSTINC or PREDEC mode. 137 if ((LD->getExtensionType() != ISD::NON_EXTLOAD) || 138 (AM != ISD::POST_INC && AM != ISD::PRE_DEC)) { 139 140 return false; 141 } 142 143 unsigned Opcode = 0; 144 bool isPre = (AM == ISD::PRE_DEC); 145 int Offs = cast<ConstantSDNode>(LD->getOffset())->getSExtValue(); 146 147 switch (VT.SimpleTy) { 148 case MVT::i8: { 149 if ((!isPre && Offs != 1) || (isPre && Offs != -1)) { 150 return false; 151 } 152 153 Opcode = (isPre) ? AVR::LDRdPtrPd : AVR::LDRdPtrPi; 154 break; 155 } 156 case MVT::i16: { 157 if ((!isPre && Offs != 2) || (isPre && Offs != -2)) { 158 return false; 159 } 160 161 Opcode = (isPre) ? AVR::LDWRdPtrPd : AVR::LDWRdPtrPi; 162 break; 163 } 164 default: 165 return false; 166 } 167 168 SDNode *ResNode = 169 CurDAG->getMachineNode(Opcode, SDLoc(N), VT, PtrVT, MVT::Other, 170 LD->getBasePtr(), LD->getChain()); 171 ReplaceUses(N, ResNode); 172 CurDAG->RemoveDeadNode(N); 173 174 return true; 175 } 176 177 unsigned AVRDAGToDAGISel::selectIndexedProgMemLoad(const LoadSDNode *LD, MVT VT, 178 int Bank) { 179 // Progmem indexed loads only work in POSTINC mode. 180 if (LD->getExtensionType() != ISD::NON_EXTLOAD || 181 LD->getAddressingMode() != ISD::POST_INC) 182 return 0; 183 184 // Feature ELPM is needed for loading from extended program memory. 185 assert((Bank == 0 || Subtarget->hasELPM()) && 186 "cannot load from extended program memory on this mcu"); 187 188 unsigned Opcode = 0; 189 int Offs = cast<ConstantSDNode>(LD->getOffset())->getSExtValue(); 190 191 if (VT.SimpleTy == MVT::i8 && Offs == 1 && Bank == 0) 192 Opcode = AVR::LPMRdZPi; 193 194 // TODO: Implements the expansion of the following pseudo instructions. 195 // LPMWRdZPi: type == MVT::i16, offset == 2, Bank == 0. 196 // ELPMBRdZPi: type == MVT::i8, offset == 1, Bank > 0. 197 // ELPMWRdZPi: type == MVT::i16, offset == 2, Bank > 0. 198 199 return Opcode; 200 } 201 202 bool AVRDAGToDAGISel::SelectInlineAsmMemoryOperand( 203 const SDValue &Op, unsigned ConstraintCode, std::vector<SDValue> &OutOps) { 204 assert((ConstraintCode == InlineAsm::Constraint_m || 205 ConstraintCode == InlineAsm::Constraint_Q) && 206 "Unexpected asm memory constraint"); 207 208 MachineRegisterInfo &RI = MF->getRegInfo(); 209 const AVRSubtarget &STI = MF->getSubtarget<AVRSubtarget>(); 210 const TargetLowering &TL = *STI.getTargetLowering(); 211 SDLoc dl(Op); 212 auto DL = CurDAG->getDataLayout(); 213 214 const RegisterSDNode *RegNode = dyn_cast<RegisterSDNode>(Op); 215 216 // If address operand is of PTRDISPREGS class, all is OK, then. 217 if (RegNode && 218 RI.getRegClass(RegNode->getReg()) == &AVR::PTRDISPREGSRegClass) { 219 OutOps.push_back(Op); 220 return false; 221 } 222 223 if (Op->getOpcode() == ISD::FrameIndex) { 224 SDValue Base, Disp; 225 226 if (SelectAddr(Op.getNode(), Op, Base, Disp)) { 227 OutOps.push_back(Base); 228 OutOps.push_back(Disp); 229 230 return false; 231 } 232 233 return true; 234 } 235 236 // If Op is add 'register, immediate' and 237 // register is either virtual register or register of PTRDISPREGSRegClass 238 if (Op->getOpcode() == ISD::ADD || Op->getOpcode() == ISD::SUB) { 239 SDValue CopyFromRegOp = Op->getOperand(0); 240 SDValue ImmOp = Op->getOperand(1); 241 ConstantSDNode *ImmNode = dyn_cast<ConstantSDNode>(ImmOp); 242 243 unsigned Reg; 244 bool CanHandleRegImmOpt = ImmNode && ImmNode->getAPIntValue().ult(64); 245 246 if (CopyFromRegOp->getOpcode() == ISD::CopyFromReg) { 247 RegisterSDNode *RegNode = 248 cast<RegisterSDNode>(CopyFromRegOp->getOperand(1)); 249 Reg = RegNode->getReg(); 250 CanHandleRegImmOpt &= (Register::isVirtualRegister(Reg) || 251 AVR::PTRDISPREGSRegClass.contains(Reg)); 252 } else { 253 CanHandleRegImmOpt = false; 254 } 255 256 // If we detect proper case - correct virtual register class 257 // if needed and go to another inlineasm operand. 258 if (CanHandleRegImmOpt) { 259 SDValue Base, Disp; 260 261 if (RI.getRegClass(Reg) != &AVR::PTRDISPREGSRegClass) { 262 SDLoc dl(CopyFromRegOp); 263 264 Register VReg = RI.createVirtualRegister(&AVR::PTRDISPREGSRegClass); 265 266 SDValue CopyToReg = 267 CurDAG->getCopyToReg(CopyFromRegOp, dl, VReg, CopyFromRegOp); 268 269 SDValue NewCopyFromRegOp = 270 CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(DL)); 271 272 Base = NewCopyFromRegOp; 273 } else { 274 Base = CopyFromRegOp; 275 } 276 277 if (ImmNode->getValueType(0) != MVT::i8) { 278 Disp = CurDAG->getTargetConstant(ImmNode->getZExtValue(), dl, MVT::i8); 279 } else { 280 Disp = ImmOp; 281 } 282 283 OutOps.push_back(Base); 284 OutOps.push_back(Disp); 285 286 return false; 287 } 288 } 289 290 // More generic case. 291 // Create chain that puts Op into pointer register 292 // and return that register. 293 Register VReg = RI.createVirtualRegister(&AVR::PTRDISPREGSRegClass); 294 295 SDValue CopyToReg = CurDAG->getCopyToReg(Op, dl, VReg, Op); 296 SDValue CopyFromReg = 297 CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(DL)); 298 299 OutOps.push_back(CopyFromReg); 300 301 return false; 302 } 303 304 template <> bool AVRDAGToDAGISel::select<ISD::FrameIndex>(SDNode *N) { 305 auto DL = CurDAG->getDataLayout(); 306 307 // Convert the frameindex into a temp instruction that will hold the 308 // effective address of the final stack slot. 309 int FI = cast<FrameIndexSDNode>(N)->getIndex(); 310 SDValue TFI = 311 CurDAG->getTargetFrameIndex(FI, getTargetLowering()->getPointerTy(DL)); 312 313 CurDAG->SelectNodeTo(N, AVR::FRMIDX, getTargetLowering()->getPointerTy(DL), 314 TFI, CurDAG->getTargetConstant(0, SDLoc(N), MVT::i16)); 315 return true; 316 } 317 318 template <> bool AVRDAGToDAGISel::select<ISD::STORE>(SDNode *N) { 319 // Use the STD{W}SPQRr pseudo instruction when passing arguments through 320 // the stack on function calls for further expansion during the PEI phase. 321 const StoreSDNode *ST = cast<StoreSDNode>(N); 322 SDValue BasePtr = ST->getBasePtr(); 323 324 // Early exit when the base pointer is a frame index node or a constant. 325 if (isa<FrameIndexSDNode>(BasePtr) || isa<ConstantSDNode>(BasePtr) || 326 BasePtr.isUndef()) { 327 return false; 328 } 329 330 const RegisterSDNode *RN = dyn_cast<RegisterSDNode>(BasePtr.getOperand(0)); 331 // Only stores where SP is the base pointer are valid. 332 if (!RN || (RN->getReg() != AVR::SP)) { 333 return false; 334 } 335 336 int CST = (int)cast<ConstantSDNode>(BasePtr.getOperand(1))->getZExtValue(); 337 SDValue Chain = ST->getChain(); 338 EVT VT = ST->getValue().getValueType(); 339 SDLoc DL(N); 340 SDValue Offset = CurDAG->getTargetConstant(CST, DL, MVT::i16); 341 SDValue Ops[] = {BasePtr.getOperand(0), Offset, ST->getValue(), Chain}; 342 unsigned Opc = (VT == MVT::i16) ? AVR::STDWSPQRr : AVR::STDSPQRr; 343 344 SDNode *ResNode = CurDAG->getMachineNode(Opc, DL, MVT::Other, Ops); 345 346 // Transfer memory operands. 347 CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {ST->getMemOperand()}); 348 349 ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0)); 350 CurDAG->RemoveDeadNode(N); 351 352 return true; 353 } 354 355 template <> bool AVRDAGToDAGISel::select<ISD::LOAD>(SDNode *N) { 356 const LoadSDNode *LD = cast<LoadSDNode>(N); 357 if (!AVR::isProgramMemoryAccess(LD)) { 358 // Check if the opcode can be converted into an indexed load. 359 return selectIndexedLoad(N); 360 } 361 362 if (!Subtarget->hasLPM()) 363 report_fatal_error("cannot load from program memory on this mcu"); 364 365 int ProgMemBank = AVR::getProgramMemoryBank(LD); 366 if (ProgMemBank < 0 || ProgMemBank > 5) 367 report_fatal_error("unexpected program memory bank"); 368 if (ProgMemBank > 0 && !Subtarget->hasELPM()) 369 report_fatal_error("unexpected program memory bank"); 370 371 // This is a flash memory load, move the pointer into R31R30 and emit 372 // the lpm instruction. 373 MVT VT = LD->getMemoryVT().getSimpleVT(); 374 SDValue Chain = LD->getChain(); 375 SDValue Ptr = LD->getBasePtr(); 376 SDNode *ResNode; 377 SDLoc DL(N); 378 379 Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, Ptr, SDValue()); 380 Ptr = CurDAG->getCopyFromReg(Chain, DL, AVR::R31R30, MVT::i16, 381 Chain.getValue(1)); 382 383 // Check if the opcode can be converted into an indexed load. 384 if (unsigned LPMOpc = selectIndexedProgMemLoad(LD, VT, ProgMemBank)) { 385 // It is legal to fold the load into an indexed load. 386 if (ProgMemBank == 0) { 387 ResNode = 388 CurDAG->getMachineNode(LPMOpc, DL, VT, MVT::i16, MVT::Other, Ptr); 389 } else { 390 // Do not combine the LDI instruction into the ELPM pseudo instruction, 391 // since it may be reused by other ELPM pseudo instructions. 392 SDValue NC = CurDAG->getTargetConstant(ProgMemBank, DL, MVT::i8); 393 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK, DL, MVT::i8, NC); 394 ResNode = CurDAG->getMachineNode(LPMOpc, DL, VT, MVT::i16, MVT::Other, 395 Ptr, SDValue(NP, 0)); 396 } 397 } else { 398 // Selecting an indexed load is not legal, fallback to a normal load. 399 switch (VT.SimpleTy) { 400 case MVT::i8: 401 if (ProgMemBank == 0) { 402 unsigned Opc = Subtarget->hasLPMX() ? AVR::LPMRdZ : AVR::LPMBRdZ; 403 ResNode = 404 CurDAG->getMachineNode(Opc, DL, MVT::i8, MVT::Other, Ptr); 405 } else { 406 // Do not combine the LDI instruction into the ELPM pseudo instruction, 407 // since it may be reused by other ELPM pseudo instructions. 408 SDValue NC = CurDAG->getTargetConstant(ProgMemBank, DL, MVT::i8); 409 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK, DL, MVT::i8, NC); 410 ResNode = CurDAG->getMachineNode(AVR::ELPMBRdZ, DL, MVT::i8, MVT::Other, 411 Ptr, SDValue(NP, 0)); 412 } 413 break; 414 case MVT::i16: 415 if (ProgMemBank == 0) { 416 ResNode = 417 CurDAG->getMachineNode(AVR::LPMWRdZ, DL, MVT::i16, MVT::Other, Ptr); 418 } else { 419 // Do not combine the LDI instruction into the ELPM pseudo instruction, 420 // since LDI requires the destination register in range R16~R31. 421 SDValue NC = CurDAG->getTargetConstant(ProgMemBank, DL, MVT::i8); 422 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK, DL, MVT::i8, NC); 423 ResNode = CurDAG->getMachineNode(AVR::ELPMWRdZ, DL, MVT::i16, 424 MVT::Other, Ptr, SDValue(NP, 0)); 425 } 426 break; 427 default: 428 llvm_unreachable("Unsupported VT!"); 429 } 430 } 431 432 // Transfer memory operands. 433 CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {LD->getMemOperand()}); 434 435 ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0)); 436 ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1)); 437 CurDAG->RemoveDeadNode(N); 438 439 return true; 440 } 441 442 template <> bool AVRDAGToDAGISel::select<AVRISD::CALL>(SDNode *N) { 443 SDValue InGlue; 444 SDValue Chain = N->getOperand(0); 445 SDValue Callee = N->getOperand(1); 446 unsigned LastOpNum = N->getNumOperands() - 1; 447 448 // Direct calls are autogenerated. 449 unsigned Op = Callee.getOpcode(); 450 if (Op == ISD::TargetGlobalAddress || Op == ISD::TargetExternalSymbol) { 451 return false; 452 } 453 454 // Skip the incoming flag if present 455 if (N->getOperand(LastOpNum).getValueType() == MVT::Glue) { 456 --LastOpNum; 457 } 458 459 SDLoc DL(N); 460 Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, Callee, InGlue); 461 SmallVector<SDValue, 8> Ops; 462 Ops.push_back(CurDAG->getRegister(AVR::R31R30, MVT::i16)); 463 464 // Map all operands into the new node. 465 for (unsigned i = 2, e = LastOpNum + 1; i != e; ++i) { 466 Ops.push_back(N->getOperand(i)); 467 } 468 469 Ops.push_back(Chain); 470 Ops.push_back(Chain.getValue(1)); 471 472 SDNode *ResNode = CurDAG->getMachineNode( 473 Subtarget->hasEIJMPCALL() ? AVR::EICALL : AVR::ICALL, DL, MVT::Other, 474 MVT::Glue, Ops); 475 476 ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0)); 477 ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1)); 478 CurDAG->RemoveDeadNode(N); 479 480 return true; 481 } 482 483 template <> bool AVRDAGToDAGISel::select<ISD::BRIND>(SDNode *N) { 484 SDValue Chain = N->getOperand(0); 485 SDValue JmpAddr = N->getOperand(1); 486 487 SDLoc DL(N); 488 // Move the destination address of the indirect branch into R31R30. 489 Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, JmpAddr); 490 SDNode *ResNode = CurDAG->getMachineNode(AVR::IJMP, DL, MVT::Other, Chain); 491 492 ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0)); 493 CurDAG->RemoveDeadNode(N); 494 495 return true; 496 } 497 498 bool AVRDAGToDAGISel::selectMultiplication(llvm::SDNode *N) { 499 SDLoc DL(N); 500 MVT Type = N->getSimpleValueType(0); 501 502 assert(Type == MVT::i8 && "unexpected value type"); 503 504 bool isSigned = N->getOpcode() == ISD::SMUL_LOHI; 505 unsigned MachineOp = isSigned ? AVR::MULSRdRr : AVR::MULRdRr; 506 507 SDValue Lhs = N->getOperand(0); 508 SDValue Rhs = N->getOperand(1); 509 SDNode *Mul = CurDAG->getMachineNode(MachineOp, DL, MVT::Glue, Lhs, Rhs); 510 SDValue InChain = CurDAG->getEntryNode(); 511 SDValue InGlue = SDValue(Mul, 0); 512 513 // Copy the low half of the result, if it is needed. 514 if (N->hasAnyUseOfValue(0)) { 515 SDValue CopyFromLo = 516 CurDAG->getCopyFromReg(InChain, DL, AVR::R0, Type, InGlue); 517 518 ReplaceUses(SDValue(N, 0), CopyFromLo); 519 520 InChain = CopyFromLo.getValue(1); 521 InGlue = CopyFromLo.getValue(2); 522 } 523 524 // Copy the high half of the result, if it is needed. 525 if (N->hasAnyUseOfValue(1)) { 526 SDValue CopyFromHi = 527 CurDAG->getCopyFromReg(InChain, DL, AVR::R1, Type, InGlue); 528 529 ReplaceUses(SDValue(N, 1), CopyFromHi); 530 531 InChain = CopyFromHi.getValue(1); 532 InGlue = CopyFromHi.getValue(2); 533 } 534 535 CurDAG->RemoveDeadNode(N); 536 537 // We need to clear R1. This is currently done (dirtily) 538 // using a custom inserter. 539 540 return true; 541 } 542 543 void AVRDAGToDAGISel::Select(SDNode *N) { 544 // If we have a custom node, we already have selected! 545 if (N->isMachineOpcode()) { 546 LLVM_DEBUG(errs() << "== "; N->dump(CurDAG); errs() << "\n"); 547 N->setNodeId(-1); 548 return; 549 } 550 551 // See if subclasses can handle this node. 552 if (trySelect(N)) 553 return; 554 555 // Select the default instruction 556 SelectCode(N); 557 } 558 559 bool AVRDAGToDAGISel::trySelect(SDNode *N) { 560 unsigned Opcode = N->getOpcode(); 561 SDLoc DL(N); 562 563 switch (Opcode) { 564 // Nodes we fully handle. 565 case ISD::FrameIndex: 566 return select<ISD::FrameIndex>(N); 567 case ISD::BRIND: 568 return select<ISD::BRIND>(N); 569 case ISD::UMUL_LOHI: 570 case ISD::SMUL_LOHI: 571 return selectMultiplication(N); 572 573 // Nodes we handle partially. Other cases are autogenerated 574 case ISD::STORE: 575 return select<ISD::STORE>(N); 576 case ISD::LOAD: 577 return select<ISD::LOAD>(N); 578 case AVRISD::CALL: 579 return select<AVRISD::CALL>(N); 580 default: 581 return false; 582 } 583 } 584 585 FunctionPass *llvm::createAVRISelDag(AVRTargetMachine &TM, 586 CodeGenOpt::Level OptLevel) { 587 return new AVRDAGToDAGISel(TM, OptLevel); 588 } 589