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 "AVRMachineFunctionInfo.h"
15#include "AVRRegisterInfo.h"
16#include "AVRTargetMachine.h"
17#include "MCTargetDesc/AVRMCTargetDesc.h"
18
19#include "llvm/CodeGen/ISDOpcodes.h"
20#include "llvm/CodeGen/MachineFrameInfo.h"
21#include "llvm/CodeGen/MachineInstrBuilder.h"
22#include "llvm/CodeGen/MachineRegisterInfo.h"
23#include "llvm/CodeGen/SelectionDAGISel.h"
24#include "llvm/CodeGen/SelectionDAGNodes.h"
25#include "llvm/Support/Casting.h"
26#include "llvm/Support/Debug.h"
27#include "llvm/Support/ErrorHandling.h"
28#include "llvm/Support/raw_ostream.h"
29
30#define DEBUG_TYPE "avr-isel"
31#define PASS_NAME "AVR DAG->DAG Instruction Selection"
32
33using namespace llvm;
34
35namespace {
36
37/// Lowers LLVM IR (in DAG form) to AVR MC instructions (in DAG form).
38class AVRDAGToDAGISel : public SelectionDAGISel {
39public:
40 AVRDAGToDAGISel() = delete;
41
42 AVRDAGToDAGISel(AVRTargetMachine &TM, CodeGenOptLevel OptLevel)
43 : SelectionDAGISel(TM, OptLevel), Subtarget(nullptr) {}
44
45 bool runOnMachineFunction(MachineFunction &MF) override;
46
47 void PostprocessISelDAG() override;
48
49 bool SelectAddr(SDNode *Op, SDValue N, SDValue &Base, SDValue &Disp);
50
51 bool selectAlignedFrameLoad(SDNode *N);
52 bool selectAlignedFrameStore(SDNode *N);
53 bool selectIndexedLoad(SDNode *N);
54
55 unsigned selectIndexedProgMemLoad(const LoadSDNode *LD, MVT VT, int Bank);
56
57 bool SelectInlineAsmMemoryOperand(const SDValue &Op,
58 InlineAsm::ConstraintCode ConstraintCode,
59 std::vector<SDValue> &OutOps) override;
60
61// Include the pieces autogenerated from the target description.
62#include "AVRGenDAGISel.inc"
63
64private:
65 bool isPostProcessDone;
66
67 void Select(SDNode *N) override;
68 bool trySelect(SDNode *N);
69
70 template <unsigned NodeType> bool select(SDNode *N);
71 bool selectMultiplication(SDNode *N);
72
73 const AVRSubtarget *Subtarget;
74};
75
76class AVRDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
77public:
78 static char ID;
79 AVRDAGToDAGISelLegacy(AVRTargetMachine &TM, CodeGenOptLevel OptLevel)
80 : SelectionDAGISelLegacy(
81 ID, std::make_unique<AVRDAGToDAGISel>(args&: TM, args&: OptLevel)) {}
82};
83
84} // namespace
85
86char AVRDAGToDAGISelLegacy::ID = 0;
87
88INITIALIZE_PASS(AVRDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
89
90bool AVRDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
91 Subtarget = &MF.getSubtarget<AVRSubtarget>();
92 isPostProcessDone = false;
93
94 AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
95
96 // If our function has aligned allocas (e.g. `alloca i16, align 16`), we will
97 // need an aligned stack register to address them.
98 //
99 // Since we don't know this information upfront, assume we *will* need aligned
100 // stack register and aligned stack space - if this proves false,
101 // post-processing below will undo these two:
102 AFI->AlignedStackReg =
103 MF.getRegInfo().createVirtualRegister(RegClass: &AVR::DLDREGSRegClass);
104
105 AFI->AlignedStackObjectIdx =
106 MF.getFrameInfo().CreateStackObject(Size: 1, Alignment: Align(1), isSpillSlot: false);
107
108 // We've just allocated a virtual register, so let's drop the "NoVRegs" flag
109 // in case it was active.
110 MF.getProperties().resetNoVRegs();
111
112 return SelectionDAGISel::runOnMachineFunction(mf&: MF);
113}
114
115void AVRDAGToDAGISel::PostprocessISelDAG() {
116 if (isPostProcessDone) {
117 // Sometimes post-processing gets run multiple times on a single function -
118 // because our algorithm is not idempotent (we generate FRMSP instruction
119 // and reset function's alignment), it can only run once per function.
120 //
121 // This flags gets toggled on at the end of this function and it gets reset
122 // during `runOnMachineFunction()`.
123 return;
124 }
125
126 MachineFrameInfo &MFI = MF->getFrameInfo();
127 AVRMachineFunctionInfo *AFI = MF->getInfo<AVRMachineFunctionInfo>();
128
129 uint64_t Offset = 0;
130 uint64_t Alignment = 1;
131
132 // Move all aligned objects into their own stack, `AvrAlign`.
133 for (int FI = 0, MaxFI = MFI.getObjectIndexEnd(); FI != MaxFI; ++FI) {
134 if (MFI.getObjectAlign(ObjectIdx: FI).value() > 1) {
135 Offset = alignTo(Size: Offset, A: MFI.getObjectAlign(ObjectIdx: FI));
136
137 MFI.setStackID(ObjectIdx: FI, ID: TargetStackID::AvrAlign);
138
139 // Usually offsets are assigned by the prologue/epilogue inserter, but PEI
140 // doesn't touch objects that lay outside the default stack - so, seizing
141 // the day, let's assign the offset ourselves.
142 MFI.setObjectOffset(ObjectIdx: FI, SPOffset: Offset);
143
144 Offset += MFI.getObjectSize(ObjectIdx: FI);
145 Alignment = std::max(a: Alignment, b: MFI.getObjectAlign(ObjectIdx: FI).value());
146 }
147 }
148
149 // If we had any aligned objects, allocate the aligned stack register.
150 if (Offset > 0) {
151 BuildMI(BB: &MF->front(), MIMD: DebugLoc(), MCID: TII->get(Opcode: AVR::FRMSP))
152 .addReg(RegNo: AFI->AlignedStackReg, Flags: RegState::Define)
153 .addImm(Val: Alignment);
154
155 MFI.setObjectSize(ObjectIdx: AFI->AlignedStackObjectIdx, Size: Offset + Alignment - 1);
156 MFI.setMaxAlign(Align(1));
157 } else {
158 MFI.RemoveStackObject(ObjectIdx: AFI->AlignedStackObjectIdx);
159 }
160
161 isPostProcessDone = true;
162}
163
164bool AVRDAGToDAGISel::SelectAddr(SDNode *Op, SDValue N, SDValue &Base,
165 SDValue &Disp) {
166 SDLoc dl(Op);
167 auto DL = CurDAG->getDataLayout();
168 MVT PtrVT = getTargetLowering()->getPointerTy(DL);
169
170 // if the address is a frame index get the TargetFrameIndex.
171 if (const FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Val&: N)) {
172 Base = CurDAG->getTargetFrameIndex(FI: FIN->getIndex(), VT: PtrVT);
173 Disp = CurDAG->getTargetConstant(Val: 0, DL: dl, VT: MVT::i8);
174
175 return true;
176 }
177
178 // Match simple Reg + uimm6 operands.
179 if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB &&
180 !CurDAG->isBaseWithConstantOffset(Op: N)) {
181 return false;
182 }
183
184 if (const ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Val: N.getOperand(i: 1))) {
185 int RHSC = (int)RHS->getZExtValue();
186
187 // Convert negative offsets into positives ones.
188 if (N.getOpcode() == ISD::SUB) {
189 RHSC = -RHSC;
190 }
191
192 // <#Frame index + const>
193 // Allow folding offsets bigger than 63 so the frame pointer can be used
194 // directly instead of copying it around by adjusting and restoring it for
195 // each access.
196 if (N.getOperand(i: 0).getOpcode() == ISD::FrameIndex) {
197 int FI = cast<FrameIndexSDNode>(Val: N.getOperand(i: 0))->getIndex();
198
199 Base = CurDAG->getTargetFrameIndex(FI, VT: PtrVT);
200 Disp = CurDAG->getTargetConstant(Val: RHSC, DL: dl, VT: MVT::i16);
201
202 return true;
203 }
204
205 // The value type of the memory instruction determines what is the maximum
206 // offset allowed.
207 MVT VT = cast<MemSDNode>(Val: Op)->getMemoryVT().getSimpleVT();
208
209 // We only accept offsets that fit in 6 bits (unsigned), with the exception
210 // of 16-bit loads - those can only go up to 62, because we desugar them
211 // into a pair of 8-bit loads like `ldd rx, RHSC` + `ldd ry, RHSC + 1`.
212 bool OkI8 = VT == MVT::i8 && RHSC <= 63;
213 bool OkI16 = VT == MVT::i16 && RHSC <= 62;
214
215 if (OkI8 || OkI16) {
216 Base = N.getOperand(i: 0);
217 Disp = CurDAG->getTargetConstant(Val: RHSC, DL: dl, VT: MVT::i8);
218
219 return true;
220 }
221 }
222
223 return false;
224}
225
226bool AVRDAGToDAGISel::selectAlignedFrameLoad(SDNode *N) {
227 LoadSDNode *LD = cast<LoadSDNode>(Val: N);
228 const SDValue LDB = LD->getBasePtr();
229
230 // ---
231
232 int InIndex;
233 int InOffset;
234
235 switch (LDB->getOpcode()) {
236 case ISD::FrameIndex:
237 InIndex = cast<FrameIndexSDNode>(Val: LDB)->getIndex();
238 InOffset = 0;
239 break;
240
241 case ISD::ADD:
242 case ISD::OR:
243 if (LDB->getOperand(Num: 0)->getOpcode() == ISD::FrameIndex &&
244 LDB->getOperand(Num: 1)->getOpcode() == ISD::Constant) {
245 InIndex = cast<FrameIndexSDNode>(Val: LDB->getOperand(Num: 0))->getIndex();
246 InOffset = cast<ConstantSDNode>(Val: LDB->getOperand(Num: 1))->getZExtValue();
247 } else {
248 return false;
249 }
250 break;
251
252 default:
253 return false;
254 }
255
256 // ---
257
258 uint64_t Alignment = MF->getFrameInfo().getObjectAlign(ObjectIdx: InIndex).value();
259
260 if (Alignment == 1) {
261 return false;
262 }
263
264 // ---
265
266 unsigned Opcode;
267
268 switch (LD->getMemoryVT().getSimpleVT().SimpleTy) {
269 case MVT::i8:
270 Opcode = AVR::LDRdPtr;
271 break;
272 case MVT::i16:
273 Opcode = AVR::LDWRdPtr;
274 break;
275 default:
276 return false;
277 }
278
279 // ---
280
281 MVT PointerTy = getTargetLowering()->getPointerTy(DL: CurDAG->getDataLayout());
282 Register StackReg = MF->getInfo<AVRMachineFunctionInfo>()->AlignedStackReg;
283
284 SDValue Index = CurDAG->getTargetFrameIndex(FI: InIndex, VT: PointerTy);
285 SDValue Offset = CurDAG->getTargetConstant(Val: InOffset, DL: SDLoc(N), VT: MVT::i16);
286
287 SDNode *ResNode =
288 CurDAG->getMachineNode(Opcode: AVR::FRMIDX, dl: SDLoc(N), VT: PointerTy, Op1: Index, Op2: Offset,
289 Op3: CurDAG->getRegister(Reg: StackReg, VT: PointerTy));
290
291 CurDAG->SelectNodeTo(N, MachineOpc: Opcode, VT1: LD->getMemoryVT().getSimpleVT(), VT2: MVT::Other,
292 Op1: SDValue(ResNode, 0), Op2: LD->getChain());
293
294 return true;
295}
296
297bool AVRDAGToDAGISel::selectAlignedFrameStore(SDNode *N) {
298 StoreSDNode *ST = cast<StoreSDNode>(Val: N);
299 const SDValue STB = ST->getBasePtr();
300
301 // ---
302
303 int InIndex;
304 int InOffset;
305
306 switch (STB->getOpcode()) {
307 case ISD::FrameIndex:
308 InIndex = cast<FrameIndexSDNode>(Val: STB)->getIndex();
309 InOffset = 0;
310 break;
311
312 case ISD::ADD:
313 case ISD::OR:
314 if (STB->getOperand(Num: 0)->getOpcode() == ISD::FrameIndex &&
315 STB->getOperand(Num: 1)->getOpcode() == ISD::Constant) {
316 InIndex = cast<FrameIndexSDNode>(Val: STB->getOperand(Num: 0))->getIndex();
317 InOffset = cast<ConstantSDNode>(Val: STB->getOperand(Num: 1))->getZExtValue();
318 } else {
319 return false;
320 }
321 break;
322
323 default:
324 return false;
325 }
326
327 // ---
328
329 uint64_t Alignment = MF->getFrameInfo().getObjectAlign(ObjectIdx: InIndex).value();
330
331 if (Alignment == 1) {
332 return false;
333 }
334
335 // ---
336
337 unsigned Opcode;
338
339 switch (ST->getMemoryVT().getSimpleVT().SimpleTy) {
340 case MVT::i8:
341 Opcode = AVR::STPtrRr;
342 break;
343 case MVT::i16:
344 Opcode = AVR::STWPtrRr;
345 break;
346 default:
347 return false;
348 }
349
350 // ---
351
352 MVT PointerTy = getTargetLowering()->getPointerTy(DL: CurDAG->getDataLayout());
353 Register StackReg = MF->getInfo<AVRMachineFunctionInfo>()->AlignedStackReg;
354
355 SDValue Index = CurDAG->getTargetFrameIndex(FI: InIndex, VT: PointerTy);
356 SDValue Offset = CurDAG->getTargetConstant(Val: InOffset, DL: SDLoc(N), VT: MVT::i16);
357
358 SDNode *AddrNode =
359 CurDAG->getMachineNode(Opcode: AVR::FRMIDX, dl: SDLoc(N), VT: PointerTy, Op1: Index, Op2: Offset,
360 Op3: CurDAG->getRegister(Reg: StackReg, VT: PointerTy));
361
362 SDNode *ResNode = CurDAG->getMachineNode(
363 Opcode, dl: SDLoc(N), VT: MVT::Other,
364 Ops: {SDValue(AddrNode, 0), ST->getValue(), ST->getChain()});
365
366 CurDAG->setNodeMemRefs(N: cast<MachineSDNode>(Val: ResNode), NewMemRefs: {ST->getMemOperand()});
367
368 ReplaceUses(F: SDValue(N, 0), T: SDValue(ResNode, 0));
369 CurDAG->RemoveDeadNode(N);
370
371 return true;
372}
373
374bool AVRDAGToDAGISel::selectIndexedLoad(SDNode *N) {
375 const LoadSDNode *LD = cast<LoadSDNode>(Val: N);
376 ISD::MemIndexedMode AM = LD->getAddressingMode();
377 MVT VT = LD->getMemoryVT().getSimpleVT();
378 auto PtrVT = getTargetLowering()->getPointerTy(DL: CurDAG->getDataLayout());
379
380 // We only care if this load uses a POSTINC or PREDEC mode.
381 if ((LD->getExtensionType() != ISD::NON_EXTLOAD) ||
382 (AM != ISD::POST_INC && AM != ISD::PRE_DEC)) {
383
384 return false;
385 }
386
387 unsigned Opcode = 0;
388 bool isPre = (AM == ISD::PRE_DEC);
389 int Offs = cast<ConstantSDNode>(Val: LD->getOffset())->getSExtValue();
390
391 switch (VT.SimpleTy) {
392 case MVT::i8: {
393 if ((!isPre && Offs != 1) || (isPre && Offs != -1)) {
394 return false;
395 }
396
397 Opcode = (isPre) ? AVR::LDRdPtrPd : AVR::LDRdPtrPi;
398 break;
399 }
400 case MVT::i16: {
401 if ((!isPre && Offs != 2) || (isPre && Offs != -2)) {
402 return false;
403 }
404
405 Opcode = (isPre) ? AVR::LDWRdPtrPd : AVR::LDWRdPtrPi;
406 break;
407 }
408 default:
409 return false;
410 }
411
412 SDNode *ResNode =
413 CurDAG->getMachineNode(Opcode, dl: SDLoc(N), VT1: VT, VT2: PtrVT, VT3: MVT::Other,
414 Op1: LD->getBasePtr(), Op2: LD->getChain());
415 ReplaceUses(F: N, T: ResNode);
416 CurDAG->RemoveDeadNode(N);
417
418 return true;
419}
420
421unsigned AVRDAGToDAGISel::selectIndexedProgMemLoad(const LoadSDNode *LD, MVT VT,
422 int Bank) {
423 // Progmem indexed loads only work in POSTINC mode.
424 if (LD->getExtensionType() != ISD::NON_EXTLOAD ||
425 LD->getAddressingMode() != ISD::POST_INC)
426 return 0;
427
428 // Feature ELPM is needed for loading from extended program memory.
429 assert((Bank == 0 || Subtarget->hasELPM()) &&
430 "cannot load from extended program memory on this mcu");
431
432 unsigned Opcode = 0;
433 int Offs = cast<ConstantSDNode>(Val: LD->getOffset())->getSExtValue();
434
435 if (VT.SimpleTy == MVT::i8 && Offs == 1 && Bank == 0)
436 Opcode = AVR::LPMRdZPi;
437
438 // TODO: Implements the expansion of the following pseudo instructions.
439 // LPMWRdZPi: type == MVT::i16, offset == 2, Bank == 0.
440 // ELPMBRdZPi: type == MVT::i8, offset == 1, Bank > 0.
441 // ELPMWRdZPi: type == MVT::i16, offset == 2, Bank > 0.
442
443 return Opcode;
444}
445
446bool AVRDAGToDAGISel::SelectInlineAsmMemoryOperand(
447 const SDValue &Op, InlineAsm::ConstraintCode ConstraintCode,
448 std::vector<SDValue> &OutOps) {
449 assert((ConstraintCode == InlineAsm::ConstraintCode::m ||
450 ConstraintCode == InlineAsm::ConstraintCode::Q) &&
451 "Unexpected asm memory constraint");
452
453 MachineRegisterInfo &RI = MF->getRegInfo();
454 const AVRSubtarget &STI = MF->getSubtarget<AVRSubtarget>();
455 const TargetLowering &TL = *STI.getTargetLowering();
456 SDLoc dl(Op);
457 auto DL = CurDAG->getDataLayout();
458
459 const RegisterSDNode *RegNode = dyn_cast<RegisterSDNode>(Val: Op);
460
461 // If address operand is of PTRDISPREGS class, all is OK, then.
462 if (RegNode &&
463 RI.getRegClass(Reg: RegNode->getReg()) == &AVR::PTRDISPREGSRegClass) {
464 OutOps.push_back(x: Op);
465 return false;
466 }
467
468 if (Op->getOpcode() == ISD::FrameIndex) {
469 SDValue Base, Disp;
470
471 if (SelectAddr(Op: Op.getNode(), N: Op, Base, Disp)) {
472 OutOps.push_back(x: Base);
473 OutOps.push_back(x: Disp);
474
475 return false;
476 }
477
478 return true;
479 }
480
481 // Select global addresses.
482 if (Op.getOpcode() == AVRISD::WRAPPER) {
483 SDValue Sub = Op.getOperand(i: 0);
484 if (Sub.getOpcode() == ISD::TargetGlobalAddress &&
485 (Sub.getValueType() == MVT::i16 || Sub.getValueType() == MVT::i8)) {
486 OutOps.push_back(x: Sub);
487 return false;
488 }
489 }
490
491 // If Op is add 'register, immediate' and
492 // register is either virtual register or register of PTRDISPREGSRegClass
493 if (Op->getOpcode() == ISD::ADD || Op->getOpcode() == ISD::SUB) {
494 SDValue CopyFromRegOp = Op->getOperand(Num: 0);
495 SDValue ImmOp = Op->getOperand(Num: 1);
496 ConstantSDNode *ImmNode = dyn_cast<ConstantSDNode>(Val&: ImmOp);
497
498 unsigned Reg;
499 bool CanHandleRegImmOpt = ImmNode && ImmNode->getAPIntValue().ult(RHS: 64);
500
501 if (CopyFromRegOp->getOpcode() == ISD::CopyFromReg) {
502 RegisterSDNode *RegNode =
503 cast<RegisterSDNode>(Val: CopyFromRegOp->getOperand(Num: 1));
504 Reg = RegNode->getReg();
505 CanHandleRegImmOpt &= (Register::isVirtualRegister(Reg) ||
506 AVR::PTRDISPREGSRegClass.contains(Reg));
507 } else {
508 CanHandleRegImmOpt = false;
509 }
510
511 // If we detect proper case - correct virtual register class
512 // if needed and go to another inlineasm operand.
513 if (CanHandleRegImmOpt) {
514 SDValue Base, Disp;
515
516 if (RI.getRegClass(Reg) != &AVR::PTRDISPREGSRegClass) {
517 SDLoc dl(CopyFromRegOp);
518
519 Register VReg = RI.createVirtualRegister(RegClass: &AVR::PTRDISPREGSRegClass);
520
521 SDValue CopyToReg =
522 CurDAG->getCopyToReg(Chain: CopyFromRegOp, dl, Reg: VReg, N: CopyFromRegOp);
523
524 SDValue NewCopyFromRegOp =
525 CurDAG->getCopyFromReg(Chain: CopyToReg, dl, Reg: VReg, VT: TL.getPointerTy(DL));
526
527 Base = NewCopyFromRegOp;
528 } else {
529 Base = CopyFromRegOp;
530 }
531
532 if (ImmNode->getValueType(ResNo: 0) != MVT::i8) {
533 Disp = CurDAG->getTargetConstant(Val: ImmNode->getZExtValue(), DL: dl, VT: MVT::i8);
534 } else {
535 Disp = ImmOp;
536 }
537
538 OutOps.push_back(x: Base);
539 OutOps.push_back(x: Disp);
540
541 return false;
542 }
543 }
544
545 // More generic case.
546 // Create chain that puts Op into pointer register
547 // and return that register.
548 Register VReg = RI.createVirtualRegister(RegClass: &AVR::PTRDISPREGSRegClass);
549
550 SDValue CopyToReg = CurDAG->getCopyToReg(Chain: Op, dl, Reg: VReg, N: Op);
551 SDValue CopyFromReg =
552 CurDAG->getCopyFromReg(Chain: CopyToReg, dl, Reg: VReg, VT: TL.getPointerTy(DL));
553
554 OutOps.push_back(x: CopyFromReg);
555
556 return false;
557}
558
559// Convert the frameindex into a temp instruction that will hold the effective
560// address of the final stack slot.
561template <> bool AVRDAGToDAGISel::select<ISD::FrameIndex>(SDNode *N) {
562 auto DL = CurDAG->getDataLayout();
563 auto PointerTy = getTargetLowering()->getPointerTy(DL);
564
565 int FI = cast<FrameIndexSDNode>(Val: N)->getIndex();
566 SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT: PointerTy);
567 SDValue Offset = CurDAG->getTargetConstant(Val: 0, DL: SDLoc(N), VT: MVT::i16);
568 uint64_t Alignment = MF->getFrameInfo().getObjectAlign(ObjectIdx: FI).value();
569
570 if (Alignment == 1) {
571 CurDAG->SelectNodeTo(N, MachineOpc: AVR::FRMIDX, VT: PointerTy, Op1: TFI, Op2: Offset,
572 Op3: CurDAG->getRegister(Reg: AVR::R29R28, VT: PointerTy));
573 } else {
574 auto StackReg = MF->getInfo<AVRMachineFunctionInfo>()->AlignedStackReg;
575
576 CurDAG->SelectNodeTo(N, MachineOpc: AVR::FRMIDX, VT: PointerTy, Op1: TFI, Op2: Offset,
577 Op3: CurDAG->getRegister(Reg: StackReg, VT: PointerTy));
578 }
579
580 return true;
581}
582
583template <> bool AVRDAGToDAGISel::select<ISD::STORE>(SDNode *N) {
584 if (selectAlignedFrameStore(N)) {
585 return true;
586 }
587
588 // Use the STD{W}SPQRr pseudo instruction when passing arguments through
589 // the stack on function calls for further expansion during the PEI phase.
590 const StoreSDNode *ST = cast<StoreSDNode>(Val: N);
591 SDValue BasePtr = ST->getBasePtr();
592
593 // Early exit when the base pointer is a frame index node or a constant.
594 if (isa<FrameIndexSDNode>(Val: BasePtr) || isa<ConstantSDNode>(Val: BasePtr) ||
595 BasePtr.isUndef()) {
596 return false;
597 }
598
599 const RegisterSDNode *RN = dyn_cast<RegisterSDNode>(Val: BasePtr.getOperand(i: 0));
600 // Only stores where SP is the base pointer are valid.
601 if (!RN || (RN->getReg() != AVR::SP)) {
602 return false;
603 }
604
605 int CST = (int)BasePtr.getConstantOperandVal(i: 1);
606 SDValue Chain = ST->getChain();
607 EVT VT = ST->getValue().getValueType();
608 SDLoc DL(N);
609 SDValue Offset = CurDAG->getTargetConstant(Val: CST, DL, VT: MVT::i16);
610 SDValue Ops[] = {BasePtr.getOperand(i: 0), Offset, ST->getValue(), Chain};
611 unsigned Opc = (VT == MVT::i16) ? AVR::STDWSPQRr : AVR::STDSPQRr;
612
613 SDNode *ResNode = CurDAG->getMachineNode(Opcode: Opc, dl: DL, VT: MVT::Other, Ops);
614
615 // Transfer memory operands.
616 CurDAG->setNodeMemRefs(N: cast<MachineSDNode>(Val: ResNode), NewMemRefs: {ST->getMemOperand()});
617
618 ReplaceUses(F: SDValue(N, 0), T: SDValue(ResNode, 0));
619 CurDAG->RemoveDeadNode(N);
620
621 return true;
622}
623
624template <> bool AVRDAGToDAGISel::select<ISD::LOAD>(SDNode *N) {
625 const LoadSDNode *LD = cast<LoadSDNode>(Val: N);
626 if (!AVR::isProgramMemoryAccess(N: LD)) {
627 return selectAlignedFrameLoad(N) || selectIndexedLoad(N);
628 }
629
630 if (!Subtarget->hasLPM())
631 report_fatal_error(reason: "cannot load from program memory on this mcu");
632
633 int ProgMemBank = AVR::getProgramMemoryBank(N: LD);
634 if (ProgMemBank < 0 || ProgMemBank > 5)
635 report_fatal_error(reason: "unexpected program memory bank");
636 if (ProgMemBank > 0 && !Subtarget->hasELPM())
637 report_fatal_error(reason: "unexpected program memory bank");
638
639 // This is a flash memory load, move the pointer into R31R30 and emit
640 // the lpm instruction.
641 MVT VT = LD->getMemoryVT().getSimpleVT();
642 SDValue Chain = LD->getChain();
643 SDValue Ptr = LD->getBasePtr();
644 SDNode *ResNode;
645 SDLoc DL(N);
646
647 Chain = CurDAG->getCopyToReg(Chain, dl: DL, Reg: AVR::R31R30, N: Ptr, Glue: SDValue());
648 Ptr = CurDAG->getCopyFromReg(Chain, dl: DL, Reg: AVR::R31R30, VT: MVT::i16,
649 Glue: Chain.getValue(R: 1));
650
651 // Check if the opcode can be converted into an indexed load.
652 if (unsigned LPMOpc = selectIndexedProgMemLoad(LD, VT, Bank: ProgMemBank)) {
653 // It is legal to fold the load into an indexed load.
654 if (ProgMemBank == 0) {
655 ResNode =
656 CurDAG->getMachineNode(Opcode: LPMOpc, dl: DL, VT1: VT, VT2: MVT::i16, VT3: MVT::Other, Ops: Ptr);
657 } else {
658 // Do not combine the LDI instruction into the ELPM pseudo instruction,
659 // since it may be reused by other ELPM pseudo instructions.
660 SDValue NC = CurDAG->getTargetConstant(Val: ProgMemBank, DL, VT: MVT::i8);
661 auto *NP = CurDAG->getMachineNode(Opcode: AVR::LDIRdK, dl: DL, VT: MVT::i8, Op1: NC);
662 ResNode = CurDAG->getMachineNode(Opcode: LPMOpc, dl: DL, VT1: VT, VT2: MVT::i16, VT3: MVT::Other,
663 Op1: Ptr, Op2: SDValue(NP, 0));
664 }
665 } else {
666 // Selecting an indexed load is not legal, fallback to a normal load.
667 switch (VT.SimpleTy) {
668 case MVT::i8:
669 if (ProgMemBank == 0) {
670 unsigned Opc = Subtarget->hasLPMX() ? AVR::LPMRdZ : AVR::LPMBRdZ;
671 ResNode = CurDAG->getMachineNode(Opcode: Opc, dl: DL, VT1: MVT::i8, VT2: MVT::Other, Ops: Ptr);
672 } else {
673 // Do not combine the LDI instruction into the ELPM pseudo instruction,
674 // since it may be reused by other ELPM pseudo instructions.
675 SDValue NC = CurDAG->getTargetConstant(Val: ProgMemBank, DL, VT: MVT::i8);
676 auto *NP = CurDAG->getMachineNode(Opcode: AVR::LDIRdK, dl: DL, VT: MVT::i8, Op1: NC);
677 ResNode = CurDAG->getMachineNode(Opcode: AVR::ELPMBRdZ, dl: DL, VT1: MVT::i8, VT2: MVT::Other,
678 Op1: Ptr, Op2: SDValue(NP, 0));
679 }
680 break;
681 case MVT::i16:
682 if (ProgMemBank == 0) {
683 ResNode =
684 CurDAG->getMachineNode(Opcode: AVR::LPMWRdZ, dl: DL, VT1: MVT::i16, VT2: MVT::Other, Ops: Ptr);
685 } else {
686 // Do not combine the LDI instruction into the ELPM pseudo instruction,
687 // since LDI requires the destination register in range R16~R31.
688 SDValue NC = CurDAG->getTargetConstant(Val: ProgMemBank, DL, VT: MVT::i8);
689 auto *NP = CurDAG->getMachineNode(Opcode: AVR::LDIRdK, dl: DL, VT: MVT::i8, Op1: NC);
690 ResNode = CurDAG->getMachineNode(Opcode: AVR::ELPMWRdZ, dl: DL, VT1: MVT::i16,
691 VT2: MVT::Other, Op1: Ptr, Op2: SDValue(NP, 0));
692 }
693 break;
694 default:
695 llvm_unreachable("Unsupported VT!");
696 }
697 }
698
699 // Transfer memory operands.
700 CurDAG->setNodeMemRefs(N: cast<MachineSDNode>(Val: ResNode), NewMemRefs: {LD->getMemOperand()});
701
702 ReplaceUses(F: SDValue(N, 0), T: SDValue(ResNode, 0));
703 ReplaceUses(F: SDValue(N, 1), T: SDValue(ResNode, 1));
704 CurDAG->RemoveDeadNode(N);
705
706 return true;
707}
708
709template <> bool AVRDAGToDAGISel::select<AVRISD::CALL>(SDNode *N) {
710 SDValue InGlue;
711 SDValue Chain = N->getOperand(Num: 0);
712 SDValue Callee = N->getOperand(Num: 1);
713 unsigned LastOpNum = N->getNumOperands() - 1;
714
715 // Direct calls are autogenerated.
716 unsigned Op = Callee.getOpcode();
717 if (Op == ISD::TargetGlobalAddress || Op == ISD::TargetExternalSymbol) {
718 return false;
719 }
720
721 // Skip the incoming flag if present
722 if (N->getOperand(Num: LastOpNum).getValueType() == MVT::Glue) {
723 --LastOpNum;
724 }
725
726 SDLoc DL(N);
727 Chain = CurDAG->getCopyToReg(Chain, dl: DL, Reg: AVR::R31R30, N: Callee, Glue: InGlue);
728 SmallVector<SDValue, 8> Ops;
729 Ops.push_back(Elt: CurDAG->getRegister(Reg: AVR::R31R30, VT: MVT::i16));
730
731 // Map all operands into the new node.
732 for (unsigned i = 2, e = LastOpNum + 1; i != e; ++i) {
733 Ops.push_back(Elt: N->getOperand(Num: i));
734 }
735
736 Ops.push_back(Elt: Chain);
737 Ops.push_back(Elt: Chain.getValue(R: 1));
738
739 SDNode *ResNode = CurDAG->getMachineNode(
740 Opcode: Subtarget->hasEIJMPCALL() ? AVR::EICALL : AVR::ICALL, dl: DL, VT1: MVT::Other,
741 VT2: MVT::Glue, Ops);
742
743 ReplaceUses(F: SDValue(N, 0), T: SDValue(ResNode, 0));
744 ReplaceUses(F: SDValue(N, 1), T: SDValue(ResNode, 1));
745 CurDAG->RemoveDeadNode(N);
746
747 return true;
748}
749
750template <> bool AVRDAGToDAGISel::select<ISD::BRIND>(SDNode *N) {
751 SDValue Chain = N->getOperand(Num: 0);
752 SDValue JmpAddr = N->getOperand(Num: 1);
753
754 SDLoc DL(N);
755 // Move the destination address of the indirect branch into R31R30.
756 Chain = CurDAG->getCopyToReg(Chain, dl: DL, Reg: AVR::R31R30, N: JmpAddr);
757 SDNode *ResNode = CurDAG->getMachineNode(Opcode: AVR::IJMP, dl: DL, VT: MVT::Other, Op1: Chain);
758
759 ReplaceUses(F: SDValue(N, 0), T: SDValue(ResNode, 0));
760 CurDAG->RemoveDeadNode(N);
761
762 return true;
763}
764
765bool AVRDAGToDAGISel::selectMultiplication(llvm::SDNode *N) {
766 SDLoc DL(N);
767 MVT Type = N->getSimpleValueType(ResNo: 0);
768
769 assert(Type == MVT::i8 && "unexpected value type");
770
771 bool isSigned = N->getOpcode() == ISD::SMUL_LOHI;
772 unsigned MachineOp = isSigned ? AVR::MULSRdRr : AVR::MULRdRr;
773
774 SDValue Lhs = N->getOperand(Num: 0);
775 SDValue Rhs = N->getOperand(Num: 1);
776 SDNode *Mul = CurDAG->getMachineNode(Opcode: MachineOp, dl: DL, VT: MVT::Glue, Op1: Lhs, Op2: Rhs);
777 SDValue InChain = CurDAG->getEntryNode();
778 SDValue InGlue = SDValue(Mul, 0);
779
780 // Copy the low half of the result, if it is needed.
781 if (N->hasAnyUseOfValue(Value: 0)) {
782 SDValue CopyFromLo =
783 CurDAG->getCopyFromReg(Chain: InChain, dl: DL, Reg: AVR::R0, VT: Type, Glue: InGlue);
784
785 ReplaceUses(F: SDValue(N, 0), T: CopyFromLo);
786
787 InChain = CopyFromLo.getValue(R: 1);
788 InGlue = CopyFromLo.getValue(R: 2);
789 }
790
791 // Copy the high half of the result, if it is needed.
792 if (N->hasAnyUseOfValue(Value: 1)) {
793 SDValue CopyFromHi =
794 CurDAG->getCopyFromReg(Chain: InChain, dl: DL, Reg: AVR::R1, VT: Type, Glue: InGlue);
795
796 ReplaceUses(F: SDValue(N, 1), T: CopyFromHi);
797
798 InChain = CopyFromHi.getValue(R: 1);
799 InGlue = CopyFromHi.getValue(R: 2);
800 }
801
802 CurDAG->RemoveDeadNode(N);
803
804 // We need to clear R1. This is currently done (dirtily)
805 // using a custom inserter.
806
807 return true;
808}
809
810void AVRDAGToDAGISel::Select(SDNode *N) {
811 // If we have a custom node, we already have selected!
812 if (N->isMachineOpcode()) {
813 LLVM_DEBUG(errs() << "== "; N->dump(CurDAG); errs() << "\n");
814 N->setNodeId(-1);
815 return;
816 }
817
818 // See if subclasses can handle this node.
819 if (trySelect(N))
820 return;
821
822 // Select the default instruction
823 SelectCode(N);
824}
825
826bool AVRDAGToDAGISel::trySelect(SDNode *N) {
827 unsigned Opcode = N->getOpcode();
828
829 switch (Opcode) {
830 // Nodes we fully handle.
831 case ISD::FrameIndex:
832 return select<ISD::FrameIndex>(N);
833 case ISD::BRIND:
834 return select<ISD::BRIND>(N);
835 case ISD::UMUL_LOHI:
836 case ISD::SMUL_LOHI:
837 return selectMultiplication(N);
838
839 // Nodes we handle partially. Other cases are autogenerated
840 case ISD::STORE:
841 return select<ISD::STORE>(N);
842 case ISD::LOAD:
843 return select<ISD::LOAD>(N);
844 case AVRISD::CALL:
845 return select<AVRISD::CALL>(N);
846 default:
847 return false;
848 }
849}
850
851FunctionPass *llvm::createAVRISelDag(AVRTargetMachine &TM,
852 CodeGenOptLevel OptLevel) {
853 return new AVRDAGToDAGISelLegacy(TM, OptLevel);
854}
855