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