LLVM 17.0.0git
M68kISelDAGToDAG.cpp
Go to the documentation of this file.
1//===-- M68kISelDAGToDAG.cpp - M68k Dag to Dag Inst Selector ----*- C++ -*-===//
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/// \file
10/// This file defines an instruction selector for the M68K target.
11///
12//===----------------------------------------------------------------------===//
13
14#include "M68k.h"
15
16#include "M68kMachineFunction.h"
17#include "M68kRegisterInfo.h"
18#include "M68kTargetMachine.h"
19
27#include "llvm/IR/CFG.h"
28#include "llvm/IR/GlobalValue.h"
30#include "llvm/IR/Intrinsics.h"
31#include "llvm/IR/Type.h"
33#include "llvm/Support/Debug.h"
38
39using namespace llvm;
40
41#define DEBUG_TYPE "m68k-isel"
42#define PASS_NAME "M68k DAG->DAG Pattern Instruction Selection"
43
44namespace {
45
46// For reference, the full order of operands for memory references is:
47// (Operand), Displacement, Base, Index, Scale
48struct M68kISelAddressMode {
49 enum class AddrType {
50 ARI, // Address Register Indirect
51 ARIPI, // Address Register Indirect with Postincrement
52 ARIPD, // Address Register Indirect with Postdecrement
53 ARID, // Address Register Indirect with Displacement
54 ARII, // Address Register Indirect with Index
55 PCD, // Program Counter Indirect with Displacement
56 PCI, // Program Counter Indirect with Index
57 AL, // Absolute
58 };
59 AddrType AM;
60
61 enum class Base { RegBase, FrameIndexBase };
63
64 int64_t Disp;
65
66 // This is really a union, discriminated by BaseType!
67 SDValue BaseReg;
68 int BaseFrameIndex;
69
70 SDValue IndexReg;
71 unsigned Scale;
72
73 const GlobalValue *GV;
74 const Constant *CP;
75 const BlockAddress *BlockAddr;
76 const char *ES;
77 MCSymbol *MCSym;
78 int JT;
79 Align Alignment; // CP alignment.
80
81 unsigned char SymbolFlags; // M68kII::MO_*
82
83 M68kISelAddressMode(AddrType AT)
84 : AM(AT), BaseType(Base::RegBase), Disp(0), BaseFrameIndex(0), IndexReg(),
85 Scale(1), GV(nullptr), CP(nullptr), BlockAddr(nullptr), ES(nullptr),
86 MCSym(nullptr), JT(-1), Alignment(), SymbolFlags(M68kII::MO_NO_FLAG) {}
87
88 bool hasSymbolicDisplacement() const {
89 return GV != nullptr || CP != nullptr || ES != nullptr ||
90 MCSym != nullptr || JT != -1 || BlockAddr != nullptr;
91 }
92
93 bool hasBase() const {
94 return BaseType == Base::FrameIndexBase || BaseReg.getNode() != nullptr;
95 }
96
97 bool hasFrameIndex() const { return BaseType == Base::FrameIndexBase; }
98
99 bool hasBaseReg() const {
100 return BaseType == Base::RegBase && BaseReg.getNode() != nullptr;
101 }
102
103 bool hasIndexReg() const {
104 return BaseType == Base::RegBase && IndexReg.getNode() != nullptr;
105 }
106
107 /// True if address mode type supports displacement
108 bool isDispAddrType() const {
109 return AM == AddrType::ARII || AM == AddrType::PCI ||
110 AM == AddrType::ARID || AM == AddrType::PCD || AM == AddrType::AL;
111 }
112
113 unsigned getDispSize() const {
114 switch (AM) {
115 default:
116 return 0;
117 case AddrType::ARII:
118 case AddrType::PCI:
119 return 8;
120 // These two in the next chip generations can hold upto 32 bit
121 case AddrType::ARID:
122 case AddrType::PCD:
123 return 16;
124 case AddrType::AL:
125 return 32;
126 }
127 }
128
129 bool hasDisp() const { return getDispSize() != 0; }
130 bool isDisp8() const { return getDispSize() == 8; }
131 bool isDisp16() const { return getDispSize() == 16; }
132 bool isDisp32() const { return getDispSize() == 32; }
133
134 /// Return true if this addressing mode is already PC-relative.
135 bool isPCRelative() const {
136 if (BaseType != Base::RegBase)
137 return false;
138 if (auto *RegNode = dyn_cast_or_null<RegisterSDNode>(BaseReg.getNode()))
139 return RegNode->getReg() == M68k::PC;
140 return false;
141 }
142
143 void setBaseReg(SDValue Reg) {
144 BaseType = Base::RegBase;
145 BaseReg = Reg;
146 }
147
148 void setIndexReg(SDValue Reg) { IndexReg = Reg; }
149
150#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
151 void dump() {
152 dbgs() << "M68kISelAddressMode " << this;
153 dbgs() << "\nDisp: " << Disp;
154 dbgs() << ", BaseReg: ";
155 if (BaseReg.getNode())
156 BaseReg.getNode()->dump();
157 else
158 dbgs() << "null";
159 dbgs() << ", BaseFI: " << BaseFrameIndex;
160 dbgs() << ", IndexReg: ";
161 if (IndexReg.getNode()) {
162 IndexReg.getNode()->dump();
163 } else {
164 dbgs() << "null";
165 dbgs() << ", Scale: " << Scale;
166 }
167 dbgs() << '\n';
168 }
169#endif
170};
171} // end anonymous namespace
172
173namespace {
174
175class M68kDAGToDAGISel : public SelectionDAGISel {
176public:
177 static char ID;
178
179 M68kDAGToDAGISel() = delete;
180
181 explicit M68kDAGToDAGISel(M68kTargetMachine &TM)
182 : SelectionDAGISel(ID, TM), Subtarget(nullptr) {}
183
184 bool runOnMachineFunction(MachineFunction &MF) override;
185 bool IsProfitableToFold(SDValue N, SDNode *U, SDNode *Root) const override;
186
187private:
188 /// Keep a pointer to the M68kSubtarget around so that we can
189 /// make the right decision when generating code for different targets.
190 const M68kSubtarget *Subtarget;
191
192// Include the pieces autogenerated from the target description.
193#include "M68kGenDAGISel.inc"
194
195 /// getTargetMachine - Return a reference to the TargetMachine, casted
196 /// to the target-specific type.
197 const M68kTargetMachine &getTargetMachine() {
198 return static_cast<const M68kTargetMachine &>(TM);
199 }
200
201 void Select(SDNode *N) override;
202
203 // Insert instructions to initialize the global base register in the
204 // first MBB of the function.
205 // HMM... do i need this?
206 void initGlobalBaseReg(MachineFunction &MF);
207
208 bool foldOffsetIntoAddress(uint64_t Offset, M68kISelAddressMode &AM);
209
210 bool matchLoadInAddress(LoadSDNode *N, M68kISelAddressMode &AM);
211 bool matchAddress(SDValue N, M68kISelAddressMode &AM);
212 bool matchAddressBase(SDValue N, M68kISelAddressMode &AM);
213 bool matchAddressRecursively(SDValue N, M68kISelAddressMode &AM,
214 unsigned Depth);
215 bool matchADD(SDValue &N, M68kISelAddressMode &AM, unsigned Depth);
216 bool matchWrapper(SDValue N, M68kISelAddressMode &AM);
217
218 std::pair<bool, SDNode *> selectNode(SDNode *Node);
219
220 bool SelectARI(SDNode *Parent, SDValue N, SDValue &Base);
221 bool SelectARIPI(SDNode *Parent, SDValue N, SDValue &Base);
222 bool SelectARIPD(SDNode *Parent, SDValue N, SDValue &Base);
223 bool SelectARID(SDNode *Parent, SDValue N, SDValue &Imm, SDValue &Base);
224 bool SelectARII(SDNode *Parent, SDValue N, SDValue &Imm, SDValue &Base,
225 SDValue &Index);
226 bool SelectAL(SDNode *Parent, SDValue N, SDValue &Sym);
227 bool SelectPCD(SDNode *Parent, SDValue N, SDValue &Imm);
228 bool SelectPCI(SDNode *Parent, SDValue N, SDValue &Imm, SDValue &Index);
229
230 bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
231 std::vector<SDValue> &OutOps) override;
232
233 // If Address Mode represents Frame Index store FI in Disp and
234 // Displacement bit size in Base. These values are read symmetrically by
235 // M68kRegisterInfo::eliminateFrameIndex method
236 inline bool getFrameIndexAddress(M68kISelAddressMode &AM, const SDLoc &DL,
237 SDValue &Disp, SDValue &Base) {
238 if (AM.BaseType == M68kISelAddressMode::Base::FrameIndexBase) {
239 Disp = getI32Imm(AM.Disp, DL);
240 Base = CurDAG->getTargetFrameIndex(
241 AM.BaseFrameIndex, TLI->getPointerTy(CurDAG->getDataLayout()));
242 return true;
243 }
244
245 return false;
246 }
247
248 // Gets a symbol plus optional displacement
249 inline bool getSymbolicDisplacement(M68kISelAddressMode &AM, const SDLoc &DL,
250 SDValue &Sym) {
251 if (AM.GV) {
252 Sym = CurDAG->getTargetGlobalAddress(AM.GV, SDLoc(), MVT::i32, AM.Disp,
253 AM.SymbolFlags);
254 return true;
255 }
256
257 if (AM.CP) {
258 Sym = CurDAG->getTargetConstantPool(AM.CP, MVT::i32, AM.Alignment,
259 AM.Disp, AM.SymbolFlags);
260 return true;
261 }
262
263 if (AM.ES) {
264 assert(!AM.Disp && "Non-zero displacement is ignored with ES.");
265 Sym = CurDAG->getTargetExternalSymbol(AM.ES, MVT::i32, AM.SymbolFlags);
266 return true;
267 }
268
269 if (AM.MCSym) {
270 assert(!AM.Disp && "Non-zero displacement is ignored with MCSym.");
271 assert(AM.SymbolFlags == 0 && "oo");
272 Sym = CurDAG->getMCSymbol(AM.MCSym, MVT::i32);
273 return true;
274 }
275
276 if (AM.JT != -1) {
277 assert(!AM.Disp && "Non-zero displacement is ignored with JT.");
278 Sym = CurDAG->getTargetJumpTable(AM.JT, MVT::i32, AM.SymbolFlags);
279 return true;
280 }
281
282 if (AM.BlockAddr) {
283 Sym = CurDAG->getTargetBlockAddress(AM.BlockAddr, MVT::i32, AM.Disp,
284 AM.SymbolFlags);
285 return true;
286 }
287
288 return false;
289 }
290
291 /// Return a target constant with the specified value of type i8.
292 inline SDValue getI8Imm(int64_t Imm, const SDLoc &DL) {
293 return CurDAG->getTargetConstant(Imm, DL, MVT::i8);
294 }
295
296 /// Return a target constant with the specified value of type i8.
297 inline SDValue getI16Imm(int64_t Imm, const SDLoc &DL) {
298 return CurDAG->getTargetConstant(Imm, DL, MVT::i16);
299 }
300
301 /// Return a target constant with the specified value, of type i32.
302 inline SDValue getI32Imm(int64_t Imm, const SDLoc &DL) {
303 return CurDAG->getTargetConstant(Imm, DL, MVT::i32);
304 }
305
306 /// Return a reference to the TargetInstrInfo, casted to the target-specific
307 /// type.
308 const M68kInstrInfo *getInstrInfo() const {
309 return Subtarget->getInstrInfo();
310 }
311
312 /// Return an SDNode that returns the value of the global base register.
313 /// Output instructions required to initialize the global base register,
314 /// if necessary.
315 SDNode *getGlobalBaseReg();
316};
317
318char M68kDAGToDAGISel::ID;
319
320} // namespace
321
322INITIALIZE_PASS(M68kDAGToDAGISel, DEBUG_TYPE, PASS_NAME, false, false)
323
324bool M68kDAGToDAGISel::IsProfitableToFold(SDValue N, SDNode *U,
325 SDNode *Root) const {
326 if (OptLevel == CodeGenOpt::None)
327 return false;
328
329 if (U == Root) {
330 switch (U->getOpcode()) {
331 default:
332 return true;
333 case M68kISD::SUB:
334 case ISD::SUB:
335 // Prefer NEG instruction when zero subtracts a value.
336 // e.g.
337 // move.l #0, %d0
338 // sub.l (4,%sp), %d0
339 // vs.
340 // move.l (4,%sp), %d0
341 // neg.l %d0
342 if (llvm::isNullConstant(U->getOperand(0)))
343 return false;
344 break;
345 }
346 }
347
348 return true;
349}
350
351bool M68kDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
352 Subtarget = &MF.getSubtarget<M68kSubtarget>();
354}
355
356/// This pass converts a legalized DAG into a M68k-specific DAG,
357/// ready for instruction scheduling.
359 return new M68kDAGToDAGISel(TM);
360}
361
362static bool doesDispFitFI(M68kISelAddressMode &AM) {
363 if (!AM.isDispAddrType())
364 return false;
365 // -1 to make sure that resolved FI will fit into Disp field
366 return isIntN(AM.getDispSize() - 1, AM.Disp);
367}
368
369static bool doesDispFit(M68kISelAddressMode &AM, int64_t Val) {
370 if (!AM.isDispAddrType())
371 return false;
372 return isIntN(AM.getDispSize(), Val);
373}
374
375/// Return an SDNode that returns the value of the global base register.
376/// Output instructions required to initialize the global base register,
377/// if necessary.
378SDNode *M68kDAGToDAGISel::getGlobalBaseReg() {
379 unsigned GlobalBaseReg = getInstrInfo()->getGlobalBaseReg(MF);
380 auto &DL = MF->getDataLayout();
381 return CurDAG->getRegister(GlobalBaseReg, TLI->getPointerTy(DL)).getNode();
382}
383
384bool M68kDAGToDAGISel::foldOffsetIntoAddress(uint64_t Offset,
385 M68kISelAddressMode &AM) {
386 // Cannot combine ExternalSymbol displacements with integer offsets.
387 if (Offset != 0 && (AM.ES || AM.MCSym))
388 return false;
389
390 int64_t Val = AM.Disp + Offset;
391
392 if (doesDispFit(AM, Val)) {
393 AM.Disp = Val;
394 return true;
395 }
396
397 return false;
398}
399
400//===----------------------------------------------------------------------===//
401// Matchers
402//===----------------------------------------------------------------------===//
403
404/// Helper for MatchAddress. Add the specified node to the
405/// specified addressing mode without any further recursion.
406bool M68kDAGToDAGISel::matchAddressBase(SDValue N, M68kISelAddressMode &AM) {
407 // Is the base register already occupied?
408 if (AM.hasBase()) {
409 // If so, check to see if the scale index register is set.
410 if (!AM.hasIndexReg()) {
411 AM.IndexReg = N;
412 AM.Scale = 1;
413 return true;
414 }
415
416 // Otherwise, we cannot select it.
417 return false;
418 }
419
420 // Default, generate it as a register.
421 AM.BaseType = M68kISelAddressMode::Base::RegBase;
422 AM.BaseReg = N;
423 return true;
424}
425
426/// TODO Add TLS support
427bool M68kDAGToDAGISel::matchLoadInAddress(LoadSDNode *N,
428 M68kISelAddressMode &AM) {
429 return false;
430}
431
432bool M68kDAGToDAGISel::matchAddressRecursively(SDValue N,
433 M68kISelAddressMode &AM,
434 unsigned Depth) {
435 SDLoc DL(N);
436
437 // Limit recursion.
438 if (Depth > 5)
439 return matchAddressBase(N, AM);
440
441 // If this is already a %PC relative address, we can only merge immediates
442 // into it. Instead of handling this in every case, we handle it here.
443 // PC relative addressing: %PC + 16-bit displacement!
444 if (AM.isPCRelative()) {
445 // FIXME JumpTable and ExternalSymbol address currently don't like
446 // displacements. It isn't very important, but should be fixed for
447 // consistency.
448
449 if (ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(N))
450 if (foldOffsetIntoAddress(Cst->getSExtValue(), AM))
451 return true;
452 return false;
453 }
454
455 switch (N.getOpcode()) {
456 default:
457 break;
458
459 case ISD::Constant: {
460 uint64_t Val = cast<ConstantSDNode>(N)->getSExtValue();
461 if (foldOffsetIntoAddress(Val, AM))
462 return true;
463 break;
464 }
465
466 case M68kISD::Wrapper:
468 if (matchWrapper(N, AM))
469 return true;
470 break;
471
472 case ISD::LOAD:
473 if (matchLoadInAddress(cast<LoadSDNode>(N), AM))
474 return true;
475 break;
476
477 case ISD::OR:
478 // We want to look through a transform in InstCombine and DAGCombiner that
479 // turns 'add' into 'or', so we can treat this 'or' exactly like an 'add'.
480 // Example: (or (and x, 1), (shl y, 3)) --> (add (and x, 1), (shl y, 3))
481 // An 'lea' can then be used to match the shift (multiply) and add:
482 // and $1, %esi
483 // lea (%rsi, %rdi, 8), %rax
484 if (CurDAG->haveNoCommonBitsSet(N.getOperand(0), N.getOperand(1)) &&
485 matchADD(N, AM, Depth))
486 return true;
487 break;
488
489 case ISD::ADD:
490 if (matchADD(N, AM, Depth))
491 return true;
492 break;
493
494 case ISD::FrameIndex:
495 if (AM.isDispAddrType() &&
496 AM.BaseType == M68kISelAddressMode::Base::RegBase &&
497 AM.BaseReg.getNode() == nullptr && doesDispFitFI(AM)) {
498 AM.BaseType = M68kISelAddressMode::Base::FrameIndexBase;
499 AM.BaseFrameIndex = cast<FrameIndexSDNode>(N)->getIndex();
500 return true;
501 }
502 break;
503 }
504
505 return matchAddressBase(N, AM);
506}
507
508/// Add the specified node to the specified addressing mode, returning true if
509/// it cannot be done. This just pattern matches for the addressing mode.
510bool M68kDAGToDAGISel::matchAddress(SDValue N, M68kISelAddressMode &AM) {
511 // TODO: Post-processing: Convert lea(,%reg,2) to lea(%reg,%reg), which has
512 // a smaller encoding and avoids a scaled-index.
513 // And make sure it is an indexed mode
514
515 // TODO: Post-processing: Convert foo to foo(%pc), even in non-PIC mode,
516 // because it has a smaller encoding.
517 // Make sure this must be done only if PC* modes are currently being matched
518 return matchAddressRecursively(N, AM, 0);
519}
520
521bool M68kDAGToDAGISel::matchADD(SDValue &N, M68kISelAddressMode &AM,
522 unsigned Depth) {
523 // Add an artificial use to this node so that we can keep track of
524 // it if it gets CSE'd with a different node.
525 HandleSDNode Handle(N);
526
527 M68kISelAddressMode Backup = AM;
528 if (matchAddressRecursively(N.getOperand(0), AM, Depth + 1) &&
529 matchAddressRecursively(Handle.getValue().getOperand(1), AM, Depth + 1)) {
530 return true;
531 }
532 AM = Backup;
533
534 // Try again after commuting the operands.
535 if (matchAddressRecursively(Handle.getValue().getOperand(1), AM, Depth + 1) &&
536 matchAddressRecursively(Handle.getValue().getOperand(0), AM, Depth + 1)) {
537 return true;
538 }
539 AM = Backup;
540
541 // If we couldn't fold both operands into the address at the same time,
542 // see if we can just put each operand into a register and fold at least
543 // the add.
544 if (!AM.hasBase() && !AM.hasIndexReg()) {
545 N = Handle.getValue();
546 AM.BaseReg = N.getOperand(0);
547 AM.IndexReg = N.getOperand(1);
548 AM.Scale = 1;
549 return true;
550 }
551
552 N = Handle.getValue();
553 return false;
554}
555
556/// Try to match M68kISD::Wrapper and M68kISD::WrapperPC nodes into an
557/// addressing mode. These wrap things that will resolve down into a symbol
558/// reference. If no match is possible, this returns true, otherwise it returns
559/// false.
560bool M68kDAGToDAGISel::matchWrapper(SDValue N, M68kISelAddressMode &AM) {
561 // If the addressing mode already has a symbol as the displacement, we can
562 // never match another symbol.
563 if (AM.hasSymbolicDisplacement())
564 return false;
565
566 SDValue N0 = N.getOperand(0);
567
568 if (N.getOpcode() == M68kISD::WrapperPC) {
569
570 // If cannot match here just restore the old version
571 M68kISelAddressMode Backup = AM;
572
573 if (AM.hasBase()) {
574 return false;
575 }
576
577 if (auto *G = dyn_cast<GlobalAddressSDNode>(N0)) {
578 AM.GV = G->getGlobal();
579 AM.SymbolFlags = G->getTargetFlags();
580 if (!foldOffsetIntoAddress(G->getOffset(), AM)) {
581 AM = Backup;
582 return false;
583 }
584 } else if (auto *CP = dyn_cast<ConstantPoolSDNode>(N0)) {
585 AM.CP = CP->getConstVal();
586 AM.Alignment = CP->getAlign();
587 AM.SymbolFlags = CP->getTargetFlags();
588 if (!foldOffsetIntoAddress(CP->getOffset(), AM)) {
589 AM = Backup;
590 return false;
591 }
592 } else if (auto *S = dyn_cast<ExternalSymbolSDNode>(N0)) {
593 AM.ES = S->getSymbol();
594 AM.SymbolFlags = S->getTargetFlags();
595 } else if (auto *S = dyn_cast<MCSymbolSDNode>(N0)) {
596 AM.MCSym = S->getMCSymbol();
597 } else if (auto *J = dyn_cast<JumpTableSDNode>(N0)) {
598 AM.JT = J->getIndex();
599 AM.SymbolFlags = J->getTargetFlags();
600 } else if (auto *BA = dyn_cast<BlockAddressSDNode>(N0)) {
601 AM.BlockAddr = BA->getBlockAddress();
602 AM.SymbolFlags = BA->getTargetFlags();
603 if (!foldOffsetIntoAddress(BA->getOffset(), AM)) {
604 AM = Backup;
605 return false;
606 }
607 } else
608 llvm_unreachable("Unhandled symbol reference node.");
609
610 AM.setBaseReg(CurDAG->getRegister(M68k::PC, MVT::i32));
611 return true;
612 }
613
614 // This wrapper requires 32bit disp/imm field for Medium CM
615 if (!AM.isDisp32()) {
616 return false;
617 }
618
619 if (N.getOpcode() == M68kISD::Wrapper) {
620 if (auto *G = dyn_cast<GlobalAddressSDNode>(N0)) {
621 AM.GV = G->getGlobal();
622 AM.Disp += G->getOffset();
623 AM.SymbolFlags = G->getTargetFlags();
624 } else if (auto *CP = dyn_cast<ConstantPoolSDNode>(N0)) {
625 AM.CP = CP->getConstVal();
626 AM.Alignment = CP->getAlign();
627 AM.Disp += CP->getOffset();
628 AM.SymbolFlags = CP->getTargetFlags();
629 } else if (auto *S = dyn_cast<ExternalSymbolSDNode>(N0)) {
630 AM.ES = S->getSymbol();
631 AM.SymbolFlags = S->getTargetFlags();
632 } else if (auto *S = dyn_cast<MCSymbolSDNode>(N0)) {
633 AM.MCSym = S->getMCSymbol();
634 } else if (auto *J = dyn_cast<JumpTableSDNode>(N0)) {
635 AM.JT = J->getIndex();
636 AM.SymbolFlags = J->getTargetFlags();
637 } else if (auto *BA = dyn_cast<BlockAddressSDNode>(N0)) {
638 AM.BlockAddr = BA->getBlockAddress();
639 AM.Disp += BA->getOffset();
640 AM.SymbolFlags = BA->getTargetFlags();
641 } else
642 llvm_unreachable("Unhandled symbol reference node.");
643 return true;
644 }
645
646 return false;
647}
648
649//===----------------------------------------------------------------------===//
650// Selectors
651//===----------------------------------------------------------------------===//
652
653void M68kDAGToDAGISel::Select(SDNode *Node) {
654 unsigned Opcode = Node->getOpcode();
655 SDLoc DL(Node);
656
657 LLVM_DEBUG(dbgs() << "Selecting: "; Node->dump(CurDAG); dbgs() << '\n');
658
659 if (Node->isMachineOpcode()) {
660 LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << '\n');
661 Node->setNodeId(-1);
662 return; // Already selected.
663 }
664
665 switch (Opcode) {
666 default:
667 break;
668
670 ReplaceNode(Node, getGlobalBaseReg());
671 return;
672 }
673
674 SelectCode(Node);
675}
676
677bool M68kDAGToDAGISel::SelectARIPI(SDNode *Parent, SDValue N, SDValue &Base) {
678 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARIPI: ");
679 LLVM_DEBUG(dbgs() << "NOT IMPLEMENTED\n");
680 return false;
681}
682
683bool M68kDAGToDAGISel::SelectARIPD(SDNode *Parent, SDValue N, SDValue &Base) {
684 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARIPD: ");
685 LLVM_DEBUG(dbgs() << "NOT IMPLEMENTED\n");
686 return false;
687}
688
689bool M68kDAGToDAGISel::SelectARID(SDNode *Parent, SDValue N, SDValue &Disp,
690 SDValue &Base) {
691 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARID: ");
692 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARID);
693
694 if (!matchAddress(N, AM))
695 return false;
696
697 if (AM.isPCRelative()) {
698 LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");
699 return false;
700 }
701
702 // If this is a frame index, grab it
703 if (getFrameIndexAddress(AM, SDLoc(N), Disp, Base)) {
704 LLVM_DEBUG(dbgs() << "SUCCESS matched FI\n");
705 return true;
706 }
707
708 if (AM.hasIndexReg()) {
709 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");
710 return false;
711 }
712
713 if (!AM.hasBaseReg()) {
714 LLVM_DEBUG(dbgs() << "REJECT: No Base reg\n");
715 return false;
716 }
717
718 if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {
719 assert(!AM.Disp && "Should not be any displacement");
720 LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");
721 return true;
722 }
723
724 // Give a chance to AddrType::ARI
725 if (AM.Disp == 0) {
726 LLVM_DEBUG(dbgs() << "REJECT: No displacement\n");
727 return false;
728 }
729
730 Base = AM.BaseReg;
731 Disp = getI16Imm(AM.Disp, SDLoc(N));
732
733 LLVM_DEBUG(dbgs() << "SUCCESS\n");
734 return true;
735}
736
737static bool isAddressBase(const SDValue &N) {
738 switch (N.getOpcode()) {
739 case ISD::ADD:
740 case ISD::ADDC:
741 return llvm::any_of(N.getNode()->ops(),
742 [](const SDUse &U) { return isAddressBase(U.get()); });
743 case M68kISD::Wrapper:
746 return true;
747 default:
748 return false;
749 }
750}
751
752bool M68kDAGToDAGISel::SelectARII(SDNode *Parent, SDValue N, SDValue &Disp,
754 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARII);
755 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARII: ");
756
757 if (!matchAddress(N, AM))
758 return false;
759
760 if (AM.isPCRelative()) {
761 LLVM_DEBUG(dbgs() << "REJECT: PC relative\n");
762 return false;
763 }
764
765 if (!AM.hasIndexReg()) {
766 LLVM_DEBUG(dbgs() << "REJECT: No Index\n");
767 return false;
768 }
769
770 if (!AM.hasBaseReg()) {
771 LLVM_DEBUG(dbgs() << "REJECT: No Base\n");
772 return false;
773 }
774
775 if (!isAddressBase(AM.BaseReg) && isAddressBase(AM.IndexReg)) {
776 Base = AM.IndexReg;
777 Index = AM.BaseReg;
778 } else {
779 Base = AM.BaseReg;
780 Index = AM.IndexReg;
781 }
782
783 if (AM.hasSymbolicDisplacement()) {
784 LLVM_DEBUG(dbgs() << "REJECT, Cannot match symbolic displacement\n");
785 return false;
786 }
787
788 // The idea here is that we want to use AddrType::ARII without displacement
789 // only if necessary like memory operations, otherwise this must be lowered
790 // into addition
791 if (AM.Disp == 0 && (!Parent || (Parent->getOpcode() != ISD::LOAD &&
792 Parent->getOpcode() != ISD::STORE))) {
793 LLVM_DEBUG(dbgs() << "REJECT: Displacement is Zero\n");
794 return false;
795 }
796
797 Disp = getI8Imm(AM.Disp, SDLoc(N));
798
799 LLVM_DEBUG(dbgs() << "SUCCESS\n");
800 return true;
801}
802
803bool M68kDAGToDAGISel::SelectAL(SDNode *Parent, SDValue N, SDValue &Sym) {
804 LLVM_DEBUG(dbgs() << "Selecting AddrType::AL: ");
805 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::AL);
806
807 if (!matchAddress(N, AM)) {
808 LLVM_DEBUG(dbgs() << "REJECT: Match failed\n");
809 return false;
810 }
811
812 if (AM.isPCRelative()) {
813 LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");
814 return false;
815 }
816
817 if (AM.hasBase()) {
818 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Base\n");
819 return false;
820 }
821
822 if (AM.hasIndexReg()) {
823 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");
824 return false;
825 }
826
827 if (getSymbolicDisplacement(AM, SDLoc(N), Sym)) {
828 LLVM_DEBUG(dbgs() << "SUCCESS: Matched symbol\n");
829 return true;
830 }
831
832 if (AM.Disp) {
833 Sym = getI32Imm(AM.Disp, SDLoc(N));
834 LLVM_DEBUG(dbgs() << "SUCCESS\n");
835 return true;
836 }
837
838 LLVM_DEBUG(dbgs() << "REJECT: Not Symbol or Disp\n");
839 return false;
840 ;
841}
842
843bool M68kDAGToDAGISel::SelectPCD(SDNode *Parent, SDValue N, SDValue &Disp) {
844 LLVM_DEBUG(dbgs() << "Selecting AddrType::PCD: ");
845 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::PCD);
846
847 if (!matchAddress(N, AM))
848 return false;
849
850 if (!AM.isPCRelative()) {
851 LLVM_DEBUG(dbgs() << "REJECT: Not PC relative\n");
852 return false;
853 }
854
855 if (AM.hasIndexReg()) {
856 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");
857 return false;
858 }
859
860 if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {
861 LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");
862 return true;
863 }
864
865 Disp = getI16Imm(AM.Disp, SDLoc(N));
866
867 LLVM_DEBUG(dbgs() << "SUCCESS\n");
868 return true;
869}
870
871bool M68kDAGToDAGISel::SelectPCI(SDNode *Parent, SDValue N, SDValue &Disp,
872 SDValue &Index) {
873 LLVM_DEBUG(dbgs() << "Selecting AddrType::PCI: ");
874 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::PCI);
875
876 if (!matchAddress(N, AM))
877 return false;
878
879 if (!AM.isPCRelative()) {
880 LLVM_DEBUG(dbgs() << "REJECT: Not PC relative\n");
881 return false;
882 }
883
884 if (!AM.hasIndexReg()) {
885 LLVM_DEBUG(dbgs() << "REJECT: No Index\n");
886 return false;
887 }
888
889 Index = AM.IndexReg;
890
891 if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {
892 assert(!AM.Disp && "Should not be any displacement");
893 LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");
894 return true;
895 }
896
897 Disp = getI8Imm(AM.Disp, SDLoc(N));
898
899 LLVM_DEBUG(dbgs() << "SUCCESS\n");
900 return true;
901}
902
903bool M68kDAGToDAGISel::SelectARI(SDNode *Parent, SDValue N, SDValue &Base) {
904 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARI: ");
905 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARI);
906
907 if (!matchAddress(N, AM)) {
908 LLVM_DEBUG(dbgs() << "REJECT: Match failed\n");
909 return false;
910 }
911
912 if (AM.isPCRelative()) {
913 LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");
914 return false;
915 }
916
917 // AddrType::ARI does not use these
918 if (AM.hasIndexReg() || AM.Disp != 0) {
919 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index or Disp\n");
920 return false;
921 }
922
923 // Must be matched by AddrType::AL
924 if (AM.hasSymbolicDisplacement()) {
925 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Symbolic Disp\n");
926 return false;
927 }
928
929 if (AM.hasBaseReg()) {
930 Base = AM.BaseReg;
931 LLVM_DEBUG(dbgs() << "SUCCESS\n");
932 return true;
933 }
934
935 return false;
936}
937
938bool M68kDAGToDAGISel::SelectInlineAsmMemoryOperand(
939 const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) {
940 // In order to tell AsmPrinter the exact addressing mode we select here, which
941 // might comprise of multiple SDValues (hence MachineOperands), a 32-bit
942 // immediate value is prepended to the list of selected SDValues to indicate
943 // the addressing mode kind.
944 using AMK = M68k::MemAddrModeKind;
945 auto addKind = [this](SDValue &Opnd, AMK Kind) -> bool {
946 Opnd = CurDAG->getTargetConstant(unsigned(Kind), SDLoc(), MVT::i32);
947 return true;
948 };
949
950 switch (ConstraintID) {
951 // Generic memory operand.
953 // Try every supported (memory) addressing modes.
954 SDValue Operands[4];
955
956 // TODO: The ordering of the following SelectXXX is relatively...arbitrary,
957 // right now we simply sort them by descending complexity. Maybe we should
958 // adjust this by code model and/or relocation mode in the future.
959 if (SelectARII(nullptr, Op, Operands[1], Operands[2], Operands[3]) &&
960 addKind(Operands[0], AMK::f)) {
961 OutOps.insert(OutOps.end(), &Operands[0], Operands + 4);
962 return false;
963 }
964
965 if ((SelectPCI(nullptr, Op, Operands[1], Operands[2]) &&
966 addKind(Operands[0], AMK::k)) ||
967 (SelectARID(nullptr, Op, Operands[1], Operands[2]) &&
968 addKind(Operands[0], AMK::p))) {
969 OutOps.insert(OutOps.end(), &Operands[0], Operands + 3);
970 return false;
971 }
972
973 if ((SelectPCD(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::q)) ||
974 (SelectARI(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::j)) ||
975 (SelectAL(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::b))) {
976 OutOps.insert(OutOps.end(), {Operands[0], Operands[1]});
977 return false;
978 }
979
980 return true;
981 }
982 // 'Q': Address register indirect addressing.
984 SDValue AMKind, Base;
985 // 'j' addressing mode.
986 // TODO: Add support for 'o' and 'e' after their
987 // select functions are implemented.
988 if (SelectARI(nullptr, Op, Base) && addKind(AMKind, AMK::j)) {
989 OutOps.insert(OutOps.end(), {AMKind, Base});
990 return false;
991 }
992 return true;
993 }
994 // 'U': Address register indirect w/ constant offset addressing.
996 SDValue AMKind, Base, Offset;
997 // 'p' addressing mode.
998 if (SelectARID(nullptr, Op, Offset, Base) && addKind(AMKind, AMK::p)) {
999 OutOps.insert(OutOps.end(), {AMKind, Offset, Base});
1000 return false;
1001 }
1002 return true;
1003 }
1004 default:
1005 return true;
1006 }
1007}
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
amdgpu AMDGPU Register Bank Select
#define LLVM_DEBUG(X)
Definition: Debug.h:101
This file provides various utilities for inspecting and working with the control flow graph in LLVM I...
static bool doesDispFit(M68kISelAddressMode &AM, int64_t Val)
static bool doesDispFitFI(M68kISelAddressMode &AM)
static bool isAddressBase(const SDValue &N)
#define PASS_NAME
#define DEBUG_TYPE
This file declares the M68k specific subclass of MachineFunctionInfo.
This file contains the M68k implementation of the TargetRegisterInfo class.
This file declares the M68k specific subclass of TargetMachine.
This file contains the entry points for global functions defined in the M68k target library,...
#define G(x, y, z)
Definition: MD5.cpp:56
mir Rename Register Operands
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
const char LLVMTargetMachineRef TM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
DEMANGLE_DUMP_METHOD void dump() const
The address of a basic block.
Definition: Constants.h:875
This is an important base class in LLVM.
Definition: Constant.h:41
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:308
This class is used to form a handle around another node that is persistent and is updated across invo...
This class is used to represent ISD::LOAD nodes.
const M68kInstrInfo * getInstrInfo() const override
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:41
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
void dump() const
Dump this node, for debugging.
unsigned getOpcode() const
Return the SelectionDAG opcode value for this node.
Represents a use of a SDNode.
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
SDNode * getNode() const
get the SDNode which holds the desired result
SelectionDAGISel - This is the common base class used for SelectionDAG-based pattern-matching instruc...
virtual bool IsProfitableToFold(SDValue N, SDNode *U, SDNode *Root) const
IsProfitableToFold - Returns true if it's profitable to fold the specific operand node N of U during ...
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector< SDValue > &OutOps)
SelectInlineAsmMemoryOperand - Select the specified address as a target addressing mode,...
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
@ ADDC
Carry-setting nodes for multiple precision addition and subtraction.
Definition: ISDOpcodes.h:269
@ ADD
Simple integer binary arithmetic operators.
Definition: ISDOpcodes.h:239
@ LOAD
LOAD and STORE have token chains as their first operand, then the same operands as an LLVM load/store...
Definition: ISDOpcodes.h:978
@ FrameIndex
Definition: ISDOpcodes.h:80
@ WrapperPC
Special wrapper used under M68k PIC mode for PC relative displacements.
@ Wrapper
A wrapper node for TargetConstantPool, TargetExternalSymbol, and TargetGlobalAddress.
@ GlobalBaseReg
The result of the mflr at function entry, used for PIC code.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
@ Offset
Definition: DWP.cpp:406
bool isNullConstant(SDValue V)
Returns true if V is a constant integer zero.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1789
FunctionPass * createM68kISelDag(M68kTargetMachine &TM)
This pass converts a legalized DAG into a M68k-specific DAG, ready for instruction scheduling.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
bool isIntN(unsigned N, int64_t x)
Checks if an signed integer fits into the given (dynamic) bit width.
Definition: MathExtras.h:261
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39