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