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
AVRDAGToDAGISel(AVRTargetMachine & TM,CodeGenOpt::Level OptLevel)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
INITIALIZE_PASS(AVRDAGToDAGISel,DEBUG_TYPE,PASS_NAME,false,false)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
SelectAddr(SDNode * Op,SDValue N,SDValue & Base,SDValue & Disp)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
selectIndexedLoad(SDNode * N)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
selectIndexedProgMemLoad(const LoadSDNode * LD,MVT VT,int Bank)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
SelectInlineAsmMemoryOperand(const SDValue & Op,unsigned ConstraintCode,std::vector<SDValue> & OutOps)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(
279 ImmNode->getAPIntValue().getZExtValue(), dl, MVT::i8);
280 } else {
281 Disp = ImmOp;
282 }
283
284 OutOps.push_back(Base);
285 OutOps.push_back(Disp);
286
287 return false;
288 }
289 }
290
291 // More generic case.
292 // Create chain that puts Op into pointer register
293 // and return that register.
294 Register VReg = RI.createVirtualRegister(&AVR::PTRDISPREGSRegClass);
295
296 SDValue CopyToReg = CurDAG->getCopyToReg(Op, dl, VReg, Op);
297 SDValue CopyFromReg =
298 CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(DL));
299
300 OutOps.push_back(CopyFromReg);
301
302 return false;
303 }
304
select(SDNode * N)305 template <> bool AVRDAGToDAGISel::select<ISD::FrameIndex>(SDNode *N) {
306 auto DL = CurDAG->getDataLayout();
307
308 // Convert the frameindex into a temp instruction that will hold the
309 // effective address of the final stack slot.
310 int FI = cast<FrameIndexSDNode>(N)->getIndex();
311 SDValue TFI =
312 CurDAG->getTargetFrameIndex(FI, getTargetLowering()->getPointerTy(DL));
313
314 CurDAG->SelectNodeTo(N, AVR::FRMIDX, getTargetLowering()->getPointerTy(DL),
315 TFI, CurDAG->getTargetConstant(0, SDLoc(N), MVT::i16));
316 return true;
317 }
318
select(SDNode * N)319 template <> bool AVRDAGToDAGISel::select<ISD::STORE>(SDNode *N) {
320 // Use the STD{W}SPQRr pseudo instruction when passing arguments through
321 // the stack on function calls for further expansion during the PEI phase.
322 const StoreSDNode *ST = cast<StoreSDNode>(N);
323 SDValue BasePtr = ST->getBasePtr();
324
325 // Early exit when the base pointer is a frame index node or a constant.
326 if (isa<FrameIndexSDNode>(BasePtr) || isa<ConstantSDNode>(BasePtr) ||
327 BasePtr.isUndef()) {
328 return false;
329 }
330
331 const RegisterSDNode *RN = dyn_cast<RegisterSDNode>(BasePtr.getOperand(0));
332 // Only stores where SP is the base pointer are valid.
333 if (!RN || (RN->getReg() != AVR::SP)) {
334 return false;
335 }
336
337 int CST = (int)cast<ConstantSDNode>(BasePtr.getOperand(1))->getZExtValue();
338 SDValue Chain = ST->getChain();
339 EVT VT = ST->getValue().getValueType();
340 SDLoc DL(N);
341 SDValue Offset = CurDAG->getTargetConstant(CST, DL, MVT::i16);
342 SDValue Ops[] = {BasePtr.getOperand(0), Offset, ST->getValue(), Chain};
343 unsigned Opc = (VT == MVT::i16) ? AVR::STDWSPQRr : AVR::STDSPQRr;
344
345 SDNode *ResNode = CurDAG->getMachineNode(Opc, DL, MVT::Other, Ops);
346
347 // Transfer memory operands.
348 CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {ST->getMemOperand()});
349
350 ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
351 CurDAG->RemoveDeadNode(N);
352
353 return true;
354 }
355
select(SDNode * N)356 template <> bool AVRDAGToDAGISel::select<ISD::LOAD>(SDNode *N) {
357 const LoadSDNode *LD = cast<LoadSDNode>(N);
358 if (!AVR::isProgramMemoryAccess(LD)) {
359 // Check if the opcode can be converted into an indexed load.
360 return selectIndexedLoad(N);
361 }
362
363 if (!Subtarget->hasLPM())
364 report_fatal_error("cannot load from program memory on this mcu");
365
366 int ProgMemBank = AVR::getProgramMemoryBank(LD);
367 if (ProgMemBank < 0 || ProgMemBank > 5)
368 report_fatal_error("unexpected program memory bank");
369
370 // This is a flash memory load, move the pointer into R31R30 and emit
371 // the lpm instruction.
372 MVT VT = LD->getMemoryVT().getSimpleVT();
373 SDValue Chain = LD->getChain();
374 SDValue Ptr = LD->getBasePtr();
375 SDNode *ResNode;
376 SDLoc DL(N);
377
378 Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, Ptr, SDValue());
379 Ptr = CurDAG->getCopyFromReg(Chain, DL, AVR::R31R30, MVT::i16,
380 Chain.getValue(1));
381
382 // Check if the opcode can be converted into an indexed load.
383 if (unsigned LPMOpc = selectIndexedProgMemLoad(LD, VT, ProgMemBank)) {
384 // It is legal to fold the load into an indexed load.
385 if (ProgMemBank == 0) {
386 ResNode =
387 CurDAG->getMachineNode(LPMOpc, DL, VT, MVT::i16, MVT::Other, Ptr);
388 } else {
389 // Do not combine the LDI instruction into the ELPM pseudo instruction,
390 // since it may be reused by other ELPM pseudo instructions.
391 SDValue NC = CurDAG->getTargetConstant(ProgMemBank, DL, MVT::i8);
392 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK, DL, MVT::i8, NC);
393 ResNode = CurDAG->getMachineNode(LPMOpc, DL, VT, MVT::i16, MVT::Other,
394 Ptr, SDValue(NP, 0));
395 }
396 } else {
397 // Selecting an indexed load is not legal, fallback to a normal load.
398 switch (VT.SimpleTy) {
399 case MVT::i8:
400 if (ProgMemBank == 0) {
401 ResNode =
402 CurDAG->getMachineNode(AVR::LPMRdZ, DL, MVT::i8, MVT::Other, Ptr);
403 } else {
404 // Do not combine the LDI instruction into the ELPM pseudo instruction,
405 // since it may be reused by other ELPM pseudo instructions.
406 SDValue NC = CurDAG->getTargetConstant(ProgMemBank, DL, MVT::i8);
407 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK, DL, MVT::i8, NC);
408 ResNode = CurDAG->getMachineNode(AVR::ELPMBRdZ, DL, MVT::i8, MVT::Other,
409 Ptr, SDValue(NP, 0));
410 }
411 break;
412 case MVT::i16:
413 if (ProgMemBank == 0) {
414 ResNode =
415 CurDAG->getMachineNode(AVR::LPMWRdZ, DL, MVT::i16, MVT::Other, Ptr);
416 } else {
417 // Do not combine the LDI instruction into the ELPM pseudo instruction,
418 // since LDI requires the destination register in range R16~R31.
419 SDValue NC = CurDAG->getTargetConstant(ProgMemBank, DL, MVT::i8);
420 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK, DL, MVT::i8, NC);
421 ResNode = CurDAG->getMachineNode(AVR::ELPMWRdZ, DL, MVT::i16,
422 MVT::Other, Ptr, SDValue(NP, 0));
423 }
424 break;
425 default:
426 llvm_unreachable("Unsupported VT!");
427 }
428 }
429
430 // Transfer memory operands.
431 CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {LD->getMemOperand()});
432
433 ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
434 ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1));
435 CurDAG->RemoveDeadNode(N);
436
437 return true;
438 }
439
select(SDNode * N)440 template <> bool AVRDAGToDAGISel::select<AVRISD::CALL>(SDNode *N) {
441 SDValue InFlag;
442 SDValue Chain = N->getOperand(0);
443 SDValue Callee = N->getOperand(1);
444 unsigned LastOpNum = N->getNumOperands() - 1;
445
446 // Direct calls are autogenerated.
447 unsigned Op = Callee.getOpcode();
448 if (Op == ISD::TargetGlobalAddress || Op == ISD::TargetExternalSymbol) {
449 return false;
450 }
451
452 // Skip the incoming flag if present
453 if (N->getOperand(LastOpNum).getValueType() == MVT::Glue) {
454 --LastOpNum;
455 }
456
457 SDLoc DL(N);
458 Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, Callee, InFlag);
459 SmallVector<SDValue, 8> Ops;
460 Ops.push_back(CurDAG->getRegister(AVR::R31R30, MVT::i16));
461
462 // Map all operands into the new node.
463 for (unsigned i = 2, e = LastOpNum + 1; i != e; ++i) {
464 Ops.push_back(N->getOperand(i));
465 }
466
467 Ops.push_back(Chain);
468 Ops.push_back(Chain.getValue(1));
469
470 SDNode *ResNode = CurDAG->getMachineNode(
471 Subtarget->hasEIJMPCALL() ? AVR::EICALL : AVR::ICALL, DL, MVT::Other,
472 MVT::Glue, Ops);
473
474 ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
475 ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1));
476 CurDAG->RemoveDeadNode(N);
477
478 return true;
479 }
480
select(SDNode * N)481 template <> bool AVRDAGToDAGISel::select<ISD::BRIND>(SDNode *N) {
482 SDValue Chain = N->getOperand(0);
483 SDValue JmpAddr = N->getOperand(1);
484
485 SDLoc DL(N);
486 // Move the destination address of the indirect branch into R31R30.
487 Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, JmpAddr);
488 SDNode *ResNode = CurDAG->getMachineNode(AVR::IJMP, DL, MVT::Other, Chain);
489
490 ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
491 CurDAG->RemoveDeadNode(N);
492
493 return true;
494 }
495
selectMultiplication(llvm::SDNode * N)496 bool AVRDAGToDAGISel::selectMultiplication(llvm::SDNode *N) {
497 SDLoc DL(N);
498 MVT Type = N->getSimpleValueType(0);
499
500 assert(Type == MVT::i8 && "unexpected value type");
501
502 bool isSigned = N->getOpcode() == ISD::SMUL_LOHI;
503 unsigned MachineOp = isSigned ? AVR::MULSRdRr : AVR::MULRdRr;
504
505 SDValue Lhs = N->getOperand(0);
506 SDValue Rhs = N->getOperand(1);
507 SDNode *Mul = CurDAG->getMachineNode(MachineOp, DL, MVT::Glue, Lhs, Rhs);
508 SDValue InChain = CurDAG->getEntryNode();
509 SDValue InGlue = SDValue(Mul, 0);
510
511 // Copy the low half of the result, if it is needed.
512 if (N->hasAnyUseOfValue(0)) {
513 SDValue CopyFromLo =
514 CurDAG->getCopyFromReg(InChain, DL, AVR::R0, Type, InGlue);
515
516 ReplaceUses(SDValue(N, 0), CopyFromLo);
517
518 InChain = CopyFromLo.getValue(1);
519 InGlue = CopyFromLo.getValue(2);
520 }
521
522 // Copy the high half of the result, if it is needed.
523 if (N->hasAnyUseOfValue(1)) {
524 SDValue CopyFromHi =
525 CurDAG->getCopyFromReg(InChain, DL, AVR::R1, Type, InGlue);
526
527 ReplaceUses(SDValue(N, 1), CopyFromHi);
528
529 InChain = CopyFromHi.getValue(1);
530 InGlue = CopyFromHi.getValue(2);
531 }
532
533 CurDAG->RemoveDeadNode(N);
534
535 // We need to clear R1. This is currently done (dirtily)
536 // using a custom inserter.
537
538 return true;
539 }
540
Select(SDNode * N)541 void AVRDAGToDAGISel::Select(SDNode *N) {
542 // If we have a custom node, we already have selected!
543 if (N->isMachineOpcode()) {
544 LLVM_DEBUG(errs() << "== "; N->dump(CurDAG); errs() << "\n");
545 N->setNodeId(-1);
546 return;
547 }
548
549 // See if subclasses can handle this node.
550 if (trySelect(N))
551 return;
552
553 // Select the default instruction
554 SelectCode(N);
555 }
556
trySelect(SDNode * N)557 bool AVRDAGToDAGISel::trySelect(SDNode *N) {
558 unsigned Opcode = N->getOpcode();
559 SDLoc DL(N);
560
561 switch (Opcode) {
562 // Nodes we fully handle.
563 case ISD::FrameIndex:
564 return select<ISD::FrameIndex>(N);
565 case ISD::BRIND:
566 return select<ISD::BRIND>(N);
567 case ISD::UMUL_LOHI:
568 case ISD::SMUL_LOHI:
569 return selectMultiplication(N);
570
571 // Nodes we handle partially. Other cases are autogenerated
572 case ISD::STORE:
573 return select<ISD::STORE>(N);
574 case ISD::LOAD:
575 return select<ISD::LOAD>(N);
576 case AVRISD::CALL:
577 return select<AVRISD::CALL>(N);
578 default:
579 return false;
580 }
581 }
582
createAVRISelDag(AVRTargetMachine & TM,CodeGenOpt::Level OptLevel)583 FunctionPass *llvm::createAVRISelDag(AVRTargetMachine &TM,
584 CodeGenOpt::Level OptLevel) {
585 return new AVRDAGToDAGISel(TM, OptLevel);
586 }
587