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