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