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