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
26#include "llvm/Support/Debug.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
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)
81 ID, std::make_unique<AVRDAGToDAGISel>(TM, 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
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(&AVR::DLDREGSRegClass);
104
106 MF.getFrameInfo().CreateStackObject(1, Align(1), 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
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;
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(FI).value() > 1) {
136
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(FI, Offset);
143
144 Offset += MFI.getObjectSize(FI);
145 Alignment = std::max(Alignment, MFI.getObjectAlign(FI).value());
146 }
147 }
148
149 // If we had any aligned objects, allocate the aligned stack register.
150 if (Offset > 0) {
151 BuildMI(&MF->front(), DebugLoc(), TII->get(AVR::FRMSP))
152 .addReg(AFI->AlignedStackReg, RegState::Define)
153 .addImm(Alignment);
154
155 MFI.setObjectSize(AFI->AlignedStackObjectIdx, Offset + Alignment - 1);
156 MFI.setMaxAlign(Align(1));
157 } else {
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>(N)) {
172 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), PtrVT);
173 Disp = CurDAG->getTargetConstant(0, dl, 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(N)) {
181 return false;
182 }
183
184 if (const ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(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(0).getOpcode() == ISD::FrameIndex) {
197 int FI = cast<FrameIndexSDNode>(N.getOperand(0))->getIndex();
198
199 Base = CurDAG->getTargetFrameIndex(FI, PtrVT);
200 Disp = CurDAG->getTargetConstant(RHSC, dl, 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>(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(0);
217 Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i8);
218
219 return true;
220 }
221 }
222
223 return false;
224}
225
226bool AVRDAGToDAGISel::selectAlignedFrameLoad(SDNode *N) {
227 LoadSDNode *LD = cast<LoadSDNode>(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>(LDB)->getIndex();
238 InOffset = 0;
239 break;
240
241 case ISD::ADD:
242 case ISD::OR:
243 if (LDB->getOperand(0)->getOpcode() == ISD::FrameIndex &&
244 LDB->getOperand(1)->getOpcode() == ISD::Constant) {
245 InIndex = cast<FrameIndexSDNode>(LDB->getOperand(0))->getIndex();
246 InOffset = cast<ConstantSDNode>(LDB->getOperand(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(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(CurDAG->getDataLayout());
282 Register StackReg = MF->getInfo<AVRMachineFunctionInfo>()->AlignedStackReg;
283
284 SDValue Index = CurDAG->getTargetFrameIndex(InIndex, PointerTy);
285 SDValue Offset = CurDAG->getTargetConstant(InOffset, SDLoc(N), MVT::i16);
286
287 SDNode *ResNode =
288 CurDAG->getMachineNode(AVR::FRMIDX, SDLoc(N), PointerTy, Index, Offset,
289 CurDAG->getRegister(StackReg, PointerTy));
290
291 CurDAG->SelectNodeTo(N, Opcode, LD->getMemoryVT().getSimpleVT(), MVT::Other,
292 SDValue(ResNode, 0), LD->getChain());
293
294 return true;
295}
296
297bool AVRDAGToDAGISel::selectAlignedFrameStore(SDNode *N) {
298 StoreSDNode *ST = cast<StoreSDNode>(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>(STB)->getIndex();
309 InOffset = 0;
310 break;
311
312 case ISD::ADD:
313 case ISD::OR:
314 if (STB->getOperand(0)->getOpcode() == ISD::FrameIndex &&
315 STB->getOperand(1)->getOpcode() == ISD::Constant) {
316 InIndex = cast<FrameIndexSDNode>(STB->getOperand(0))->getIndex();
317 InOffset = cast<ConstantSDNode>(STB->getOperand(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(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(CurDAG->getDataLayout());
353 Register StackReg = MF->getInfo<AVRMachineFunctionInfo>()->AlignedStackReg;
354
355 SDValue Index = CurDAG->getTargetFrameIndex(InIndex, PointerTy);
356 SDValue Offset = CurDAG->getTargetConstant(InOffset, SDLoc(N), MVT::i16);
357
358 SDNode *AddrNode =
359 CurDAG->getMachineNode(AVR::FRMIDX, SDLoc(N), PointerTy, Index, Offset,
360 CurDAG->getRegister(StackReg, PointerTy));
361
362 SDNode *ResNode = CurDAG->getMachineNode(
363 Opcode, SDLoc(N), MVT::Other,
364 {SDValue(AddrNode, 0), ST->getValue(), ST->getChain()});
365
366 CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {ST->getMemOperand()});
367
368 ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
369 CurDAG->RemoveDeadNode(N);
370
371 return true;
372}
373
374bool AVRDAGToDAGISel::selectIndexedLoad(SDNode *N) {
375 const LoadSDNode *LD = cast<LoadSDNode>(N);
376 ISD::MemIndexedMode AM = LD->getAddressingMode();
377 MVT VT = LD->getMemoryVT().getSimpleVT();
378 auto PtrVT = getTargetLowering()->getPointerTy(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>(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, SDLoc(N), VT, PtrVT, MVT::Other,
414 LD->getBasePtr(), LD->getChain());
415 ReplaceUses(N, 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>(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>(Op);
460
461 // If address operand is of PTRDISPREGS class, all is OK, then.
462 if (RegNode &&
463 RI.getRegClass(RegNode->getReg()) == &AVR::PTRDISPREGSRegClass) {
464 OutOps.push_back(Op);
465 return false;
466 }
467
468 if (Op->getOpcode() == ISD::FrameIndex) {
469 SDValue Base, Disp;
470
471 if (SelectAddr(Op.getNode(), Op, Base, Disp)) {
472 OutOps.push_back(Base);
473 OutOps.push_back(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(0);
484 if (Sub.getOpcode() == ISD::TargetGlobalAddress &&
485 (Sub.getValueType() == MVT::i16 || Sub.getValueType() == MVT::i8)) {
486 OutOps.push_back(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(0);
495 SDValue ImmOp = Op->getOperand(1);
496 ConstantSDNode *ImmNode = dyn_cast<ConstantSDNode>(ImmOp);
497
498 unsigned Reg;
499 bool CanHandleRegImmOpt = ImmNode && ImmNode->getAPIntValue().ult(64);
500
501 if (CopyFromRegOp->getOpcode() == ISD::CopyFromReg) {
502 RegisterSDNode *RegNode =
503 cast<RegisterSDNode>(CopyFromRegOp->getOperand(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(&AVR::PTRDISPREGSRegClass);
520
522 CurDAG->getCopyToReg(CopyFromRegOp, dl, VReg, CopyFromRegOp);
523
524 SDValue NewCopyFromRegOp =
525 CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(DL));
526
527 Base = NewCopyFromRegOp;
528 } else {
529 Base = CopyFromRegOp;
530 }
531
532 if (ImmNode->getValueType(0) != MVT::i8) {
533 Disp = CurDAG->getTargetConstant(ImmNode->getZExtValue(), dl, MVT::i8);
534 } else {
535 Disp = ImmOp;
536 }
537
538 OutOps.push_back(Base);
539 OutOps.push_back(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(&AVR::PTRDISPREGSRegClass);
549
550 SDValue CopyToReg = CurDAG->getCopyToReg(Op, dl, VReg, Op);
552 CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(DL));
553
554 OutOps.push_back(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>(N)->getIndex();
566 SDValue TFI = CurDAG->getTargetFrameIndex(FI, PointerTy);
567 SDValue Offset = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i16);
568 uint64_t Alignment = MF->getFrameInfo().getObjectAlign(FI).value();
569
570 if (Alignment == 1) {
571 CurDAG->SelectNodeTo(N, AVR::FRMIDX, PointerTy, TFI, Offset,
572 CurDAG->getRegister(AVR::R29R28, PointerTy));
573 } else {
574 auto StackReg = MF->getInfo<AVRMachineFunctionInfo>()->AlignedStackReg;
575
576 CurDAG->SelectNodeTo(N, AVR::FRMIDX, PointerTy, TFI, Offset,
577 CurDAG->getRegister(StackReg, 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>(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>(BasePtr) || isa<ConstantSDNode>(BasePtr) ||
595 BasePtr.isUndef()) {
596 return false;
597 }
598
599 const RegisterSDNode *RN = dyn_cast<RegisterSDNode>(BasePtr.getOperand(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(1);
606 SDValue Chain = ST->getChain();
607 EVT VT = ST->getValue().getValueType();
608 SDLoc DL(N);
609 SDValue Offset = CurDAG->getTargetConstant(CST, DL, MVT::i16);
610 SDValue Ops[] = {BasePtr.getOperand(0), Offset, ST->getValue(), Chain};
611 unsigned Opc = (VT == MVT::i16) ? AVR::STDWSPQRr : AVR::STDSPQRr;
612
613 SDNode *ResNode = CurDAG->getMachineNode(Opc, DL, MVT::Other, Ops);
614
615 // Transfer memory operands.
616 CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {ST->getMemOperand()});
617
618 ReplaceUses(SDValue(N, 0), 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>(N);
627 return selectAlignedFrameLoad(N) || selectIndexedLoad(N);
628 }
629
630 if (!Subtarget->hasLPM())
631 report_fatal_error("cannot load from program memory on this mcu");
632
633 int ProgMemBank = AVR::getProgramMemoryBank(LD);
634 if (ProgMemBank < 0 || ProgMemBank > 5)
635 report_fatal_error("unexpected program memory bank");
636 if (ProgMemBank > 0 && !Subtarget->hasELPM())
637 report_fatal_error("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, AVR::R31R30, Ptr, SDValue());
648 Ptr = CurDAG->getCopyFromReg(Chain, DL, AVR::R31R30, MVT::i16,
649 Chain.getValue(1));
650
651 // Check if the opcode can be converted into an indexed load.
652 if (unsigned LPMOpc = selectIndexedProgMemLoad(LD, VT, ProgMemBank)) {
653 // It is legal to fold the load into an indexed load.
654 if (ProgMemBank == 0) {
655 ResNode =
656 CurDAG->getMachineNode(LPMOpc, DL, VT, MVT::i16, MVT::Other, 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(ProgMemBank, DL, MVT::i8);
661 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK, DL, MVT::i8, NC);
662 ResNode = CurDAG->getMachineNode(LPMOpc, DL, VT, MVT::i16, MVT::Other,
663 Ptr, 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(Opc, DL, MVT::i8, MVT::Other, 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(ProgMemBank, DL, MVT::i8);
676 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK, DL, MVT::i8, NC);
677 ResNode = CurDAG->getMachineNode(AVR::ELPMBRdZ, DL, MVT::i8, MVT::Other,
678 Ptr, SDValue(NP, 0));
679 }
680 break;
681 case MVT::i16:
682 if (ProgMemBank == 0) {
683 ResNode =
684 CurDAG->getMachineNode(AVR::LPMWRdZ, DL, MVT::i16, MVT::Other, 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(ProgMemBank, DL, MVT::i8);
689 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK, DL, MVT::i8, NC);
690 ResNode = CurDAG->getMachineNode(AVR::ELPMWRdZ, DL, MVT::i16,
691 MVT::Other, Ptr, SDValue(NP, 0));
692 }
693 break;
694 default:
695 llvm_unreachable("Unsupported VT!");
696 }
697 }
698
699 // Transfer memory operands.
700 CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {LD->getMemOperand()});
701
702 ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
703 ReplaceUses(SDValue(N, 1), 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(0);
712 SDValue Callee = N->getOperand(1);
713 unsigned LastOpNum = N->getNumOperands() - 1;
714
715 // Direct calls are autogenerated.
716 unsigned Op = Callee.getOpcode();
718 return false;
719 }
720
721 // Skip the incoming flag if present
722 if (N->getOperand(LastOpNum).getValueType() == MVT::Glue) {
723 --LastOpNum;
724 }
725
726 SDLoc DL(N);
727 Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, Callee, InGlue);
729 Ops.push_back(CurDAG->getRegister(AVR::R31R30, 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(N->getOperand(i));
734 }
735
736 Ops.push_back(Chain);
737 Ops.push_back(Chain.getValue(1));
738
739 SDNode *ResNode = CurDAG->getMachineNode(
740 Subtarget->hasEIJMPCALL() ? AVR::EICALL : AVR::ICALL, DL, MVT::Other,
741 MVT::Glue, Ops);
742
743 ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
744 ReplaceUses(SDValue(N, 1), 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(0);
752 SDValue JmpAddr = N->getOperand(1);
753
754 SDLoc DL(N);
755 // Move the destination address of the indirect branch into R31R30.
756 Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, JmpAddr);
757 SDNode *ResNode = CurDAG->getMachineNode(AVR::IJMP, DL, MVT::Other, Chain);
758
759 ReplaceUses(SDValue(N, 0), 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(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(0);
775 SDValue Rhs = N->getOperand(1);
776 SDNode *Mul = CurDAG->getMachineNode(MachineOp, DL, MVT::Glue, Lhs, 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(0)) {
782 SDValue CopyFromLo =
783 CurDAG->getCopyFromReg(InChain, DL, AVR::R0, Type, InGlue);
784
785 ReplaceUses(SDValue(N, 0), CopyFromLo);
786
787 InChain = CopyFromLo.getValue(1);
788 InGlue = CopyFromLo.getValue(2);
789 }
790
791 // Copy the high half of the result, if it is needed.
792 if (N->hasAnyUseOfValue(1)) {
793 SDValue CopyFromHi =
794 CurDAG->getCopyFromReg(InChain, DL, AVR::R1, Type, InGlue);
795
796 ReplaceUses(SDValue(N, 1), CopyFromHi);
797
798 InChain = CopyFromHi.getValue(1);
799 InGlue = CopyFromHi.getValue(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:
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
852 CodeGenOptLevel OptLevel) {
853 return new AVRDAGToDAGISelLegacy(TM, OptLevel);
854}
return SDValue()
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned 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:1116
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:314
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 condition together with a pair of addresses for...
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:75
int getProgramMemoryBank(MemSDNode const *N)
Definition AVR.h:86
@ SMUL_LOHI
SMUL_LOHI/UMUL_LOHI - Multiply two integers of type iN, producing a signed/unsigned value of type i[2...
Definition ISDOpcodes.h:275
@ ADD
Simple integer binary arithmetic operators.
Definition ISDOpcodes.h:264
@ LOAD
LOAD and STORE have token chains as their first operand, then the same operands as an LLVM load/store...
@ TargetExternalSymbol
Definition ISDOpcodes.h:190
@ 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:230
@ TargetGlobalAddress
TargetGlobalAddress - Like GlobalAddress, but the DAG does no folding or anything else with this node...
Definition ISDOpcodes.h:185
@ CopyToReg
CopyToReg - This node has three operands: a chain, a register number to set to this value,...
Definition ISDOpcodes.h:224
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:578
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
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
FunctionPass * createAVRISelDag(AVRTargetMachine &TM, CodeGenOptLevel OptLevel)
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:144
CodeGenOptLevel
Code generation optimization level.
Definition CodeGen.h:149
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
#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:77
Extended Value Type.
Definition ValueTypes.h:35