LLVM: lib/Target/AVR/AVRISelDAGToDAG.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
16
21
22#define DEBUG_TYPE "avr-isel"
23#define PASS_NAME "AVR DAG->DAG Instruction Selection"
24
25using namespace llvm;
26
27namespace {
28
29
31public:
32 AVRDAGToDAGISel() = delete;
33
36
38
40
41 bool selectIndexedLoad(SDNode *N);
42 unsigned selectIndexedProgMemLoad(const LoadSDNode *LD, MVT VT, int Bank);
43
44 bool SelectInlineAsmMemoryOperand(const SDValue &Op,
46 std::vector &OutOps) override;
47
48
49#include "AVRGenDAGISel.inc"
50
51private:
54
55 template bool select(SDNode *N);
56 bool selectMultiplication(SDNode *N);
57
59};
60
62public:
63 static char ID;
66 ID, std::make_unique(TM, OptLevel)) {}
67};
68
69}
70
71char AVRDAGToDAGISelLegacy::ID = 0;
72
74
78}
79
82 SDLoc dl(Op);
83 auto DL = CurDAG->getDataLayout();
84 MVT PtrVT = getTargetLowering()->getPointerTy(DL);
85
86
88 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), PtrVT);
89 Disp = CurDAG->getTargetConstant(0, dl, MVT::i8);
90
91 return true;
92 }
93
94
96 !CurDAG->isBaseWithConstantOffset(N)) {
97 return false;
98 }
99
101 int RHSC = (int)RHS->getZExtValue();
102
103
105 RHSC = -RHSC;
106 }
107
108
109
110
111
114
115 Base = CurDAG->getTargetFrameIndex(FI, PtrVT);
116 Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i16);
117
118 return true;
119 }
120
121
122
124
125
126
127
128 bool OkI8 = VT == MVT::i8 && RHSC <= 63;
129 bool OkI16 = VT == MVT::i16 && RHSC <= 62;
130
131 if (OkI8 || OkI16) {
133 Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i8);
134
135 return true;
136 }
137 }
138
139 return false;
140}
141
142bool AVRDAGToDAGISel::selectIndexedLoad(SDNode *N) {
145 MVT VT = LD->getMemoryVT().getSimpleVT();
146 auto PtrVT = getTargetLowering()->getPointerTy(CurDAG->getDataLayout());
147
148
151
152 return false;
153 }
154
155 unsigned Opcode = 0;
158
160 case MVT::i8: {
161 if ((!isPre && Offs != 1) || (isPre && Offs != -1)) {
162 return false;
163 }
164
165 Opcode = (isPre) ? AVR::LDRdPtrPd : AVR::LDRdPtrPi;
166 break;
167 }
168 case MVT::i16: {
169 if ((!isPre && Offs != 2) || (isPre && Offs != -2)) {
170 return false;
171 }
172
173 Opcode = (isPre) ? AVR::LDWRdPtrPd : AVR::LDWRdPtrPi;
174 break;
175 }
176 default:
177 return false;
178 }
179
180 SDNode *ResNode =
181 CurDAG->getMachineNode(Opcode, SDLoc(N), VT, PtrVT, MVT::Other,
182 LD->getBasePtr(), LD->getChain());
183 ReplaceUses(N, ResNode);
184 CurDAG->RemoveDeadNode(N);
185
186 return true;
187}
188
189unsigned AVRDAGToDAGISel::selectIndexedProgMemLoad(const LoadSDNode *LD, MVT VT,
190 int Bank) {
191
194 return 0;
195
196
197 assert((Bank == 0 || Subtarget->hasELPM()) &&
198 "cannot load from extended program memory on this mcu");
199
200 unsigned Opcode = 0;
202
203 if (VT.SimpleTy == MVT::i8 && Offs == 1 && Bank == 0)
204 Opcode = AVR::LPMRdZPi;
205
206
207
208
209
210
211 return Opcode;
212}
213
214bool AVRDAGToDAGISel::SelectInlineAsmMemoryOperand(
216 std::vector &OutOps) {
217 assert((ConstraintCode == InlineAsm::ConstraintCode::m ||
218 ConstraintCode == InlineAsm::ConstraintCode::Q) &&
219 "Unexpected asm memory constraint");
220
221 MachineRegisterInfo &RI = MF->getRegInfo();
222 const AVRSubtarget &STI = MF->getSubtarget();
224 SDLoc dl(Op);
225 auto DL = CurDAG->getDataLayout();
226
228
229
230 if (RegNode &&
231 RI.getRegClass(RegNode->getReg()) == &AVR::PTRDISPREGSRegClass) {
232 OutOps.push_back(Op);
233 return false;
234 }
235
238
239 if (SelectAddr(Op.getNode(), Op, Base, Disp)) {
240 OutOps.push_back(Base);
241 OutOps.push_back(Disp);
242
243 return false;
244 }
245
246 return true;
247 }
248
249
250
252 SDValue CopyFromRegOp = Op->getOperand(0);
253 SDValue ImmOp = Op->getOperand(1);
255
256 unsigned Reg;
257 bool CanHandleRegImmOpt = ImmNode && ImmNode->getAPIntValue().ult(64);
258
260 RegisterSDNode *RegNode =
263 CanHandleRegImmOpt &= (Register::isVirtualRegister(Reg) ||
264 AVR::PTRDISPREGSRegClass.contains(Reg));
265 } else {
266 CanHandleRegImmOpt = false;
267 }
268
269
270
271 if (CanHandleRegImmOpt) {
273
274 if (RI.getRegClass(Reg) != &AVR::PTRDISPREGSRegClass) {
275 SDLoc dl(CopyFromRegOp);
276
278
280 CurDAG->getCopyToReg(CopyFromRegOp, dl, VReg, CopyFromRegOp);
281
282 SDValue NewCopyFromRegOp =
283 CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(DL));
284
285 Base = NewCopyFromRegOp;
286 } else {
287 Base = CopyFromRegOp;
288 }
289
291 Disp = CurDAG->getTargetConstant(ImmNode->getZExtValue(), dl, MVT::i8);
292 } else {
293 Disp = ImmOp;
294 }
295
296 OutOps.push_back(Base);
297 OutOps.push_back(Disp);
298
299 return false;
300 }
301 }
302
303
304
305
307
310 CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(DL));
311
312 OutOps.push_back(CopyFromReg);
313
314 return false;
315}
316
317template <> bool AVRDAGToDAGISel::selectISD::FrameIndex(SDNode *N) {
318 auto DL = CurDAG->getDataLayout();
319
320
321
324 CurDAG->getTargetFrameIndex(FI, getTargetLowering()->getPointerTy(DL));
325
326 CurDAG->SelectNodeTo(N, AVR::FRMIDX, getTargetLowering()->getPointerTy(DL),
327 TFI, CurDAG->getTargetConstant(0, SDLoc(N), MVT::i16));
328 return true;
329}
330
331template <> bool AVRDAGToDAGISel::selectISD::STORE(SDNode *N) {
332
333
335 SDValue BasePtr = ST->getBasePtr();
336
337
339 BasePtr.isUndef()) {
340 return false;
341 }
342
344
345 if (!RN || (RN->getReg() != AVR::SP)) {
346 return false;
347 }
348
349 int CST = (int)BasePtr.getConstantOperandVal(1);
350 SDValue Chain = ST->getChain();
351 EVT VT = ST->getValue().getValueType();
353 SDValue Offset = CurDAG->getTargetConstant(CST, DL, MVT::i16);
354 SDValue Ops[] = {BasePtr.getOperand(0), Offset, ST->getValue(), Chain};
355 unsigned Opc = (VT == MVT::i16) ? AVR::STDWSPQRr : AVR::STDSPQRr;
356
357 SDNode *ResNode = CurDAG->getMachineNode(Opc, DL, MVT::Other, Ops);
358
359
360 CurDAG->setNodeMemRefs(cast(ResNode), {ST->getMemOperand()});
361
363 CurDAG->RemoveDeadNode(N);
364
365 return true;
366}
367
368template <> bool AVRDAGToDAGISel::selectISD::LOAD(SDNode *N) {
371
372 return selectIndexedLoad(N);
373 }
374
375 if (!Subtarget->hasLPM())
377
379 if (ProgMemBank < 0 || ProgMemBank > 5)
381 if (ProgMemBank > 0 && !Subtarget->hasELPM())
383
384
385
386 MVT VT = LD->getMemoryVT().getSimpleVT();
387 SDValue Chain = LD->getChain();
388 SDValue Ptr = LD->getBasePtr();
391
392 Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, Ptr, SDValue());
393 Ptr = CurDAG->getCopyFromReg(Chain, DL, AVR::R31R30, MVT::i16,
395
396
397 if (unsigned LPMOpc = selectIndexedProgMemLoad(LD, VT, ProgMemBank)) {
398
399 if (ProgMemBank == 0) {
400 ResNode =
401 CurDAG->getMachineNode(LPMOpc, DL, VT, MVT::i16, MVT::Other, Ptr);
402 } else {
403
404
405 SDValue NC = CurDAG->getTargetConstant(ProgMemBank, DL, MVT::i8);
406 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK, DL, MVT::i8, NC);
407 ResNode = CurDAG->getMachineNode(LPMOpc, DL, VT, MVT::i16, MVT::Other,
409 }
410 } else {
411
413 case MVT::i8:
414 if (ProgMemBank == 0) {
415 unsigned Opc = Subtarget->hasLPMX() ? AVR::LPMRdZ : AVR::LPMBRdZ;
416 ResNode = CurDAG->getMachineNode(Opc, DL, MVT::i8, MVT::Other, Ptr);
417 } else {
418
419
420 SDValue NC = CurDAG->getTargetConstant(ProgMemBank, DL, MVT::i8);
421 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK, DL, MVT::i8, NC);
422 ResNode = CurDAG->getMachineNode(AVR::ELPMBRdZ, DL, MVT::i8, MVT::Other,
424 }
425 break;
426 case MVT::i16:
427 if (ProgMemBank == 0) {
428 ResNode =
429 CurDAG->getMachineNode(AVR::LPMWRdZ, DL, MVT::i16, MVT::Other, Ptr);
430 } else {
431
432
433 SDValue NC = CurDAG->getTargetConstant(ProgMemBank, DL, MVT::i8);
434 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK, DL, MVT::i8, NC);
435 ResNode = CurDAG->getMachineNode(AVR::ELPMWRdZ, DL, MVT::i16,
436 MVT::Other, Ptr, SDValue(NP, 0));
437 }
438 break;
439 default:
441 }
442 }
443
444
445 CurDAG->setNodeMemRefs(cast(ResNode), {LD->getMemOperand()});
446
449 CurDAG->RemoveDeadNode(N);
450
451 return true;
452}
453
454template <> bool AVRDAGToDAGISel::selectAVRISD::CALL(SDNode *N) {
456 SDValue Chain = N->getOperand(0);
457 SDValue Callee = N->getOperand(1);
458 unsigned LastOpNum = N->getNumOperands() - 1;
459
460
461 unsigned Op = Callee.getOpcode();
463 return false;
464 }
465
466
467 if (N->getOperand(LastOpNum).getValueType() == MVT::Glue) {
468 --LastOpNum;
469 }
470
472 Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, Callee, InGlue);
474 Ops.push_back(CurDAG->getRegister(AVR::R31R30, MVT::i16));
475
476
477 for (unsigned i = 2, e = LastOpNum + 1; i != e; ++i) {
478 Ops.push_back(N->getOperand(i));
479 }
480
481 Ops.push_back(Chain);
483
484 SDNode *ResNode = CurDAG->getMachineNode(
485 Subtarget->hasEIJMPCALL() ? AVR::EICALL : AVR::ICALL, DL, MVT::Other,
486 MVT::Glue, Ops);
487
490 CurDAG->RemoveDeadNode(N);
491
492 return true;
493}
494
495template <> bool AVRDAGToDAGISel::selectISD::BRIND(SDNode *N) {
496 SDValue Chain = N->getOperand(0);
497 SDValue JmpAddr = N->getOperand(1);
498
500
501 Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, JmpAddr);
502 SDNode *ResNode = CurDAG->getMachineNode(AVR::IJMP, DL, MVT::Other, Chain);
503
505 CurDAG->RemoveDeadNode(N);
506
507 return true;
508}
509
510bool AVRDAGToDAGISel::selectMultiplication(llvm::SDNode *N) {
512 MVT Type = N->getSimpleValueType(0);
513
514 assert(Type == MVT::i8 && "unexpected value type");
515
517 unsigned MachineOp = isSigned ? AVR::MULSRdRr : AVR::MULRdRr;
518
519 SDValue Lhs = N->getOperand(0);
520 SDValue Rhs = N->getOperand(1);
521 SDNode *Mul = CurDAG->getMachineNode(MachineOp, DL, MVT::Glue, Lhs, Rhs);
522 SDValue InChain = CurDAG->getEntryNode();
524
525
526 if (N->hasAnyUseOfValue(0)) {
528 CurDAG->getCopyFromReg(InChain, DL, AVR::R0, Type, InGlue);
529
530 ReplaceUses(SDValue(N, 0), CopyFromLo);
531
532 InChain = CopyFromLo.getValue(1);
533 InGlue = CopyFromLo.getValue(2);
534 }
535
536
537 if (N->hasAnyUseOfValue(1)) {
539 CurDAG->getCopyFromReg(InChain, DL, AVR::R1, Type, InGlue);
540
541 ReplaceUses(SDValue(N, 1), CopyFromHi);
542
543 InChain = CopyFromHi.getValue(1);
544 InGlue = CopyFromHi.getValue(2);
545 }
546
547 CurDAG->RemoveDeadNode(N);
548
549
550
551
552 return true;
553}
554
555void AVRDAGToDAGISel::Select(SDNode *N) {
556
557 if (N->isMachineOpcode()) {
559 N->setNodeId(-1);
560 return;
561 }
562
563
564 if (trySelect(N))
565 return;
566
567
568 SelectCode(N);
569}
570
571bool AVRDAGToDAGISel::trySelect(SDNode *N) {
572 unsigned Opcode = N->getOpcode();
573
574 switch (Opcode) {
575
578 case ISD::BRIND:
582 return selectMultiplication(N);
583
584
585 case ISD::STORE:
587 case ISD::LOAD:
589 case AVRISD::CALL:
591 default:
592 return false;
593 }
594}
595
598 return new AVRDAGToDAGISelLegacy(TM, OptLevel);
599}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Register Bank Select
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
bool AVRDAGToDAGISel::select< ISD::LOAD >(SDNode *N)
Definition AVRISelDAGToDAG.cpp:368
bool AVRDAGToDAGISel::select< ISD::FrameIndex >(SDNode *N)
Definition AVRISelDAGToDAG.cpp:317
bool AVRDAGToDAGISel::select< ISD::BRIND >(SDNode *N)
Definition AVRISelDAGToDAG.cpp:495
bool AVRDAGToDAGISel::select< AVRISD::CALL >(SDNode *N)
Definition AVRISelDAGToDAG.cpp:454
bool AVRDAGToDAGISel::select< ISD::STORE >(SDNode *N)
Definition AVRISelDAGToDAG.cpp:331
static bool isSigned(unsigned int Opcode)
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
Promote Memory to Register
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
bool ult(const APInt &RHS) const
Unsigned less than comparison.
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.
This class is used to represent ISD::LOAD nodes.
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
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.
bool isProgramMemoryAccess(MemSDNode const *N)
int getProgramMemoryBank(MemSDNode const *N)
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ SMUL_LOHI
SMUL_LOHI/UMUL_LOHI - Multiply two integers of type iN, producing a signed/unsigned value of type i[2...
@ ADD
Simple integer binary arithmetic operators.
@ CopyFromReg
CopyFromReg - This node indicates that the input value is a virtual or physical register that is defi...
@ TargetGlobalAddress
TargetGlobalAddress - Like GlobalAddress, but the DAG does no folding or anything else with this node...
@ CopyToReg
CopyToReg - This node has three operands: a chain, a register number to set to this value,...
MemIndexedMode
MemIndexedMode enum - This enum defines the load / store indexed addressing modes.
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast - Return the argument parameter cast to the specified type.
FunctionPass * createAVRISelDag(AVRTargetMachine &TM, CodeGenOptLevel OptLevel)
Definition AVRISelDAGToDAG.cpp:596
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
CodeGenOptLevel
Code generation optimization level.
bool isa(const From &Val)
isa - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast - Return the argument parameter cast to the specified type.