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

source code of llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp