LLVM 19.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 M68kDAGToDAGISel() = delete;
178
179 explicit M68kDAGToDAGISel(M68kTargetMachine &TM)
180 : SelectionDAGISel(TM), Subtarget(nullptr) {}
181
182 bool runOnMachineFunction(MachineFunction &MF) override;
183 bool IsProfitableToFold(SDValue N, SDNode *U, SDNode *Root) const override;
184
185private:
186 /// Keep a pointer to the M68kSubtarget around so that we can
187 /// make the right decision when generating code for different targets.
188 const M68kSubtarget *Subtarget;
189
190// Include the pieces autogenerated from the target description.
191#include "M68kGenDAGISel.inc"
192
193 /// getTargetMachine - Return a reference to the TargetMachine, casted
194 /// to the target-specific type.
195 const M68kTargetMachine &getTargetMachine() {
196 return static_cast<const M68kTargetMachine &>(TM);
197 }
198
199 void Select(SDNode *N) override;
200
201 // Insert instructions to initialize the global base register in the
202 // first MBB of the function.
203 // HMM... do i need this?
204 void initGlobalBaseReg(MachineFunction &MF);
205
206 bool foldOffsetIntoAddress(uint64_t Offset, M68kISelAddressMode &AM);
207
208 bool matchLoadInAddress(LoadSDNode *N, M68kISelAddressMode &AM);
209 bool matchAddress(SDValue N, M68kISelAddressMode &AM);
210 bool matchAddressBase(SDValue N, M68kISelAddressMode &AM);
211 bool matchAddressRecursively(SDValue N, M68kISelAddressMode &AM,
212 unsigned Depth);
213 bool matchADD(SDValue &N, M68kISelAddressMode &AM, unsigned Depth);
214 bool matchWrapper(SDValue N, M68kISelAddressMode &AM);
215
216 std::pair<bool, SDNode *> selectNode(SDNode *Node);
217
218 bool SelectARI(SDNode *Parent, SDValue N, SDValue &Base);
219 bool SelectARIPI(SDNode *Parent, SDValue N, SDValue &Base);
220 bool SelectARIPD(SDNode *Parent, SDValue N, SDValue &Base);
221 bool SelectARID(SDNode *Parent, SDValue N, SDValue &Imm, SDValue &Base);
222 bool SelectARII(SDNode *Parent, SDValue N, SDValue &Imm, SDValue &Base,
223 SDValue &Index);
224 bool SelectAL(SDNode *Parent, SDValue N, SDValue &Sym);
225 bool SelectPCD(SDNode *Parent, SDValue N, SDValue &Imm);
226 bool SelectPCI(SDNode *Parent, SDValue N, SDValue &Imm, SDValue &Index);
227
229 InlineAsm::ConstraintCode ConstraintID,
230 std::vector<SDValue> &OutOps) override;
231
232 // If Address Mode represents Frame Index store FI in Disp and
233 // Displacement bit size in Base. These values are read symmetrically by
234 // M68kRegisterInfo::eliminateFrameIndex method
235 inline bool getFrameIndexAddress(M68kISelAddressMode &AM, const SDLoc &DL,
236 SDValue &Disp, SDValue &Base) {
237 if (AM.BaseType == M68kISelAddressMode::Base::FrameIndexBase) {
238 Disp = getI32Imm(AM.Disp, DL);
239 Base = CurDAG->getTargetFrameIndex(
240 AM.BaseFrameIndex, TLI->getPointerTy(CurDAG->getDataLayout()));
241 return true;
242 }
243
244 return false;
245 }
246
247 // Gets a symbol plus optional displacement
248 inline bool getSymbolicDisplacement(M68kISelAddressMode &AM, const SDLoc &DL,
249 SDValue &Sym) {
250 if (AM.GV) {
251 Sym = CurDAG->getTargetGlobalAddress(AM.GV, SDLoc(), MVT::i32, AM.Disp,
252 AM.SymbolFlags);
253 return true;
254 }
255
256 if (AM.CP) {
257 Sym = CurDAG->getTargetConstantPool(AM.CP, MVT::i32, AM.Alignment,
258 AM.Disp, AM.SymbolFlags);
259 return true;
260 }
261
262 if (AM.ES) {
263 assert(!AM.Disp && "Non-zero displacement is ignored with ES.");
264 Sym = CurDAG->getTargetExternalSymbol(AM.ES, MVT::i32, AM.SymbolFlags);
265 return true;
266 }
267
268 if (AM.MCSym) {
269 assert(!AM.Disp && "Non-zero displacement is ignored with MCSym.");
270 assert(AM.SymbolFlags == 0 && "oo");
271 Sym = CurDAG->getMCSymbol(AM.MCSym, MVT::i32);
272 return true;
273 }
274
275 if (AM.JT != -1) {
276 assert(!AM.Disp && "Non-zero displacement is ignored with JT.");
277 Sym = CurDAG->getTargetJumpTable(AM.JT, MVT::i32, AM.SymbolFlags);
278 return true;
279 }
280
281 if (AM.BlockAddr) {
282 Sym = CurDAG->getTargetBlockAddress(AM.BlockAddr, MVT::i32, AM.Disp,
283 AM.SymbolFlags);
284 return true;
285 }
286
287 return false;
288 }
289
290 /// Return a target constant with the specified value of type i8.
291 inline SDValue getI8Imm(int64_t Imm, const SDLoc &DL) {
292 return CurDAG->getTargetConstant(Imm, DL, MVT::i8);
293 }
294
295 /// Return a target constant with the specified value of type i8.
296 inline SDValue getI16Imm(int64_t Imm, const SDLoc &DL) {
297 return CurDAG->getTargetConstant(Imm, DL, MVT::i16);
298 }
299
300 /// Return a target constant with the specified value, of type i32.
301 inline SDValue getI32Imm(int64_t Imm, const SDLoc &DL) {
302 return CurDAG->getTargetConstant(Imm, DL, MVT::i32);
303 }
304
305 /// Return a reference to the TargetInstrInfo, casted to the target-specific
306 /// type.
307 const M68kInstrInfo *getInstrInfo() const {
308 return Subtarget->getInstrInfo();
309 }
310
311 /// Return an SDNode that returns the value of the global base register.
312 /// Output instructions required to initialize the global base register,
313 /// if necessary.
314 SDNode *getGlobalBaseReg();
315};
316
317class M68kDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
318public:
319 static char ID;
320 explicit M68kDAGToDAGISelLegacy(M68kTargetMachine &TM)
321 : SelectionDAGISelLegacy(ID, std::make_unique<M68kDAGToDAGISel>(TM)) {}
322};
323
324char M68kDAGToDAGISelLegacy::ID;
325
326} // namespace
327
328INITIALIZE_PASS(M68kDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
329
330bool M68kDAGToDAGISel::IsProfitableToFold(SDValue N, SDNode *U,
331 SDNode *Root) const {
332 if (OptLevel == CodeGenOptLevel::None)
333 return false;
334
335 if (U == Root) {
336 switch (U->getOpcode()) {
337 default:
338 return true;
339 case M68kISD::SUB:
340 case ISD::SUB:
341 // Prefer NEG instruction when zero subtracts a value.
342 // e.g.
343 // move.l #0, %d0
344 // sub.l (4,%sp), %d0
345 // vs.
346 // move.l (4,%sp), %d0
347 // neg.l %d0
348 if (llvm::isNullConstant(U->getOperand(0)))
349 return false;
350 break;
351 }
352 }
353
354 return true;
355}
356
357bool M68kDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
358 Subtarget = &MF.getSubtarget<M68kSubtarget>();
360}
361
362/// This pass converts a legalized DAG into a M68k-specific DAG,
363/// ready for instruction scheduling.
365 return new M68kDAGToDAGISelLegacy(TM);
366}
367
368static bool doesDispFitFI(M68kISelAddressMode &AM) {
369 if (!AM.isDispAddrType())
370 return false;
371 // -1 to make sure that resolved FI will fit into Disp field
372 return isIntN(AM.getDispSize() - 1, AM.Disp);
373}
374
375static bool doesDispFit(M68kISelAddressMode &AM, int64_t Val) {
376 if (!AM.isDispAddrType())
377 return false;
378 return isIntN(AM.getDispSize(), Val);
379}
380
381/// Return an SDNode that returns the value of the global base register.
382/// Output instructions required to initialize the global base register,
383/// if necessary.
384SDNode *M68kDAGToDAGISel::getGlobalBaseReg() {
385 unsigned GlobalBaseReg = getInstrInfo()->getGlobalBaseReg(MF);
386 auto &DL = MF->getDataLayout();
387 return CurDAG->getRegister(GlobalBaseReg, TLI->getPointerTy(DL)).getNode();
388}
389
390bool M68kDAGToDAGISel::foldOffsetIntoAddress(uint64_t Offset,
391 M68kISelAddressMode &AM) {
392 // Cannot combine ExternalSymbol displacements with integer offsets.
393 if (Offset != 0 && (AM.ES || AM.MCSym))
394 return false;
395
396 int64_t Val = AM.Disp + Offset;
397
398 if (doesDispFit(AM, Val)) {
399 AM.Disp = Val;
400 return true;
401 }
402
403 return false;
404}
405
406//===----------------------------------------------------------------------===//
407// Matchers
408//===----------------------------------------------------------------------===//
409
410/// Helper for MatchAddress. Add the specified node to the
411/// specified addressing mode without any further recursion.
412bool M68kDAGToDAGISel::matchAddressBase(SDValue N, M68kISelAddressMode &AM) {
413 // Is the base register already occupied?
414 if (AM.hasBase()) {
415 // If so, check to see if the scale index register is set.
416 if (!AM.hasIndexReg()) {
417 AM.IndexReg = N;
418 AM.Scale = 1;
419 return true;
420 }
421
422 // Otherwise, we cannot select it.
423 return false;
424 }
425
426 // Default, generate it as a register.
427 AM.BaseType = M68kISelAddressMode::Base::RegBase;
428 AM.BaseReg = N;
429 return true;
430}
431
432/// TODO Add TLS support
433bool M68kDAGToDAGISel::matchLoadInAddress(LoadSDNode *N,
434 M68kISelAddressMode &AM) {
435 return false;
436}
437
438bool M68kDAGToDAGISel::matchAddressRecursively(SDValue N,
439 M68kISelAddressMode &AM,
440 unsigned Depth) {
441 SDLoc DL(N);
442
443 // Limit recursion.
444 if (Depth > 5)
445 return matchAddressBase(N, AM);
446
447 // If this is already a %PC relative address, we can only merge immediates
448 // into it. Instead of handling this in every case, we handle it here.
449 // PC relative addressing: %PC + 16-bit displacement!
450 if (AM.isPCRelative()) {
451 // FIXME JumpTable and ExternalSymbol address currently don't like
452 // displacements. It isn't very important, but should be fixed for
453 // consistency.
454
455 if (ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(N))
456 if (foldOffsetIntoAddress(Cst->getSExtValue(), AM))
457 return true;
458 return false;
459 }
460
461 switch (N.getOpcode()) {
462 default:
463 break;
464
465 case ISD::Constant: {
466 uint64_t Val = cast<ConstantSDNode>(N)->getSExtValue();
467 if (foldOffsetIntoAddress(Val, AM))
468 return true;
469 break;
470 }
471
472 case M68kISD::Wrapper:
474 if (matchWrapper(N, AM))
475 return true;
476 break;
477
478 case ISD::LOAD:
479 if (matchLoadInAddress(cast<LoadSDNode>(N), AM))
480 return true;
481 break;
482
483 case ISD::OR:
484 // We want to look through a transform in InstCombine and DAGCombiner that
485 // turns 'add' into 'or', so we can treat this 'or' exactly like an 'add'.
486 // Example: (or (and x, 1), (shl y, 3)) --> (add (and x, 1), (shl y, 3))
487 // An 'lea' can then be used to match the shift (multiply) and add:
488 // and $1, %esi
489 // lea (%rsi, %rdi, 8), %rax
490 if (CurDAG->haveNoCommonBitsSet(N.getOperand(0), N.getOperand(1)) &&
491 matchADD(N, AM, Depth))
492 return true;
493 break;
494
495 case ISD::ADD:
496 if (matchADD(N, AM, Depth))
497 return true;
498 break;
499
500 case ISD::FrameIndex:
501 if (AM.isDispAddrType() &&
502 AM.BaseType == M68kISelAddressMode::Base::RegBase &&
503 AM.BaseReg.getNode() == nullptr && doesDispFitFI(AM)) {
504 AM.BaseType = M68kISelAddressMode::Base::FrameIndexBase;
505 AM.BaseFrameIndex = cast<FrameIndexSDNode>(N)->getIndex();
506 return true;
507 }
508 break;
509
511 GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(N);
512 AM.GV = GA->getGlobal();
513 AM.SymbolFlags = GA->getTargetFlags();
514 return true;
515 }
516 }
517
518 return matchAddressBase(N, AM);
519}
520
521/// Add the specified node to the specified addressing mode, returning true if
522/// it cannot be done. This just pattern matches for the addressing mode.
523bool M68kDAGToDAGISel::matchAddress(SDValue N, M68kISelAddressMode &AM) {
524 // TODO: Post-processing: Convert lea(,%reg,2) to lea(%reg,%reg), which has
525 // a smaller encoding and avoids a scaled-index.
526 // And make sure it is an indexed mode
527
528 // TODO: Post-processing: Convert foo to foo(%pc), even in non-PIC mode,
529 // because it has a smaller encoding.
530 // Make sure this must be done only if PC* modes are currently being matched
531 return matchAddressRecursively(N, AM, 0);
532}
533
534bool M68kDAGToDAGISel::matchADD(SDValue &N, M68kISelAddressMode &AM,
535 unsigned Depth) {
536 // Add an artificial use to this node so that we can keep track of
537 // it if it gets CSE'd with a different node.
538 HandleSDNode Handle(N);
539
540 M68kISelAddressMode Backup = AM;
541 if (matchAddressRecursively(N.getOperand(0), AM, Depth + 1) &&
542 matchAddressRecursively(Handle.getValue().getOperand(1), AM, Depth + 1)) {
543 return true;
544 }
545 AM = Backup;
546
547 // Try again after commuting the operands.
548 if (matchAddressRecursively(Handle.getValue().getOperand(1), AM, Depth + 1) &&
549 matchAddressRecursively(Handle.getValue().getOperand(0), AM, Depth + 1)) {
550 return true;
551 }
552 AM = Backup;
553
554 // If we couldn't fold both operands into the address at the same time,
555 // see if we can just put each operand into a register and fold at least
556 // the add.
557 if (!AM.hasBase() && !AM.hasIndexReg()) {
558 N = Handle.getValue();
559 AM.BaseReg = N.getOperand(0);
560 AM.IndexReg = N.getOperand(1);
561 AM.Scale = 1;
562 return true;
563 }
564
565 N = Handle.getValue();
566 return false;
567}
568
569/// Try to match M68kISD::Wrapper and M68kISD::WrapperPC nodes into an
570/// addressing mode. These wrap things that will resolve down into a symbol
571/// reference. If no match is possible, this returns true, otherwise it returns
572/// false.
573bool M68kDAGToDAGISel::matchWrapper(SDValue N, M68kISelAddressMode &AM) {
574 // If the addressing mode already has a symbol as the displacement, we can
575 // never match another symbol.
576 if (AM.hasSymbolicDisplacement())
577 return false;
578
579 SDValue N0 = N.getOperand(0);
580
581 if (N.getOpcode() == M68kISD::WrapperPC) {
582
583 // If cannot match here just restore the old version
584 M68kISelAddressMode Backup = AM;
585
586 if (AM.hasBase()) {
587 return false;
588 }
589
590 if (auto *G = dyn_cast<GlobalAddressSDNode>(N0)) {
591 AM.GV = G->getGlobal();
592 AM.SymbolFlags = G->getTargetFlags();
593 if (!foldOffsetIntoAddress(G->getOffset(), AM)) {
594 AM = Backup;
595 return false;
596 }
597 } else if (auto *CP = dyn_cast<ConstantPoolSDNode>(N0)) {
598 AM.CP = CP->getConstVal();
599 AM.Alignment = CP->getAlign();
600 AM.SymbolFlags = CP->getTargetFlags();
601 if (!foldOffsetIntoAddress(CP->getOffset(), AM)) {
602 AM = Backup;
603 return false;
604 }
605 } else if (auto *S = dyn_cast<ExternalSymbolSDNode>(N0)) {
606 AM.ES = S->getSymbol();
607 AM.SymbolFlags = S->getTargetFlags();
608 } else if (auto *S = dyn_cast<MCSymbolSDNode>(N0)) {
609 AM.MCSym = S->getMCSymbol();
610 } else if (auto *J = dyn_cast<JumpTableSDNode>(N0)) {
611 AM.JT = J->getIndex();
612 AM.SymbolFlags = J->getTargetFlags();
613 } else if (auto *BA = dyn_cast<BlockAddressSDNode>(N0)) {
614 AM.BlockAddr = BA->getBlockAddress();
615 AM.SymbolFlags = BA->getTargetFlags();
616 if (!foldOffsetIntoAddress(BA->getOffset(), AM)) {
617 AM = Backup;
618 return false;
619 }
620 } else
621 llvm_unreachable("Unhandled symbol reference node.");
622
623 AM.setBaseReg(CurDAG->getRegister(M68k::PC, MVT::i32));
624 return true;
625 }
626
627 // This wrapper requires 32bit disp/imm field for Medium CM
628 if (!AM.isDisp32()) {
629 return false;
630 }
631
632 if (N.getOpcode() == M68kISD::Wrapper) {
633 if (auto *G = dyn_cast<GlobalAddressSDNode>(N0)) {
634 AM.GV = G->getGlobal();
635 AM.Disp += G->getOffset();
636 AM.SymbolFlags = G->getTargetFlags();
637 } else if (auto *CP = dyn_cast<ConstantPoolSDNode>(N0)) {
638 AM.CP = CP->getConstVal();
639 AM.Alignment = CP->getAlign();
640 AM.Disp += CP->getOffset();
641 AM.SymbolFlags = CP->getTargetFlags();
642 } else if (auto *S = dyn_cast<ExternalSymbolSDNode>(N0)) {
643 AM.ES = S->getSymbol();
644 AM.SymbolFlags = S->getTargetFlags();
645 } else if (auto *S = dyn_cast<MCSymbolSDNode>(N0)) {
646 AM.MCSym = S->getMCSymbol();
647 } else if (auto *J = dyn_cast<JumpTableSDNode>(N0)) {
648 AM.JT = J->getIndex();
649 AM.SymbolFlags = J->getTargetFlags();
650 } else if (auto *BA = dyn_cast<BlockAddressSDNode>(N0)) {
651 AM.BlockAddr = BA->getBlockAddress();
652 AM.Disp += BA->getOffset();
653 AM.SymbolFlags = BA->getTargetFlags();
654 } else
655 llvm_unreachable("Unhandled symbol reference node.");
656 return true;
657 }
658
659 return false;
660}
661
662//===----------------------------------------------------------------------===//
663// Selectors
664//===----------------------------------------------------------------------===//
665
666void M68kDAGToDAGISel::Select(SDNode *Node) {
667 unsigned Opcode = Node->getOpcode();
668 SDLoc DL(Node);
669
670 LLVM_DEBUG(dbgs() << "Selecting: "; Node->dump(CurDAG); dbgs() << '\n');
671
672 if (Node->isMachineOpcode()) {
673 LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << '\n');
674 Node->setNodeId(-1);
675 return; // Already selected.
676 }
677
678 switch (Opcode) {
679 default:
680 break;
681
683 SDValue GOT = CurDAG->getTargetExternalSymbol(
684 "_GLOBAL_OFFSET_TABLE_", MVT::i32, M68kII::MO_GOTPCREL);
685 MachineSDNode *Res =
686 CurDAG->getMachineNode(M68k::LEA32q, DL, MVT::i32, GOT);
687 ReplaceNode(Node, Res);
688 return;
689 }
690
692 ReplaceNode(Node, getGlobalBaseReg());
693 return;
694 }
695
696 SelectCode(Node);
697}
698
699bool M68kDAGToDAGISel::SelectARIPI(SDNode *Parent, SDValue N, SDValue &Base) {
700 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARIPI: ");
701 LLVM_DEBUG(dbgs() << "NOT IMPLEMENTED\n");
702 return false;
703}
704
705bool M68kDAGToDAGISel::SelectARIPD(SDNode *Parent, SDValue N, SDValue &Base) {
706 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARIPD: ");
707 LLVM_DEBUG(dbgs() << "NOT IMPLEMENTED\n");
708 return false;
709}
710
711bool M68kDAGToDAGISel::SelectARID(SDNode *Parent, SDValue N, SDValue &Disp,
712 SDValue &Base) {
713 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARID: ");
714 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARID);
715
716 if (!matchAddress(N, AM))
717 return false;
718
719 if (AM.isPCRelative()) {
720 LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");
721 return false;
722 }
723
724 // If this is a frame index, grab it
725 if (getFrameIndexAddress(AM, SDLoc(N), Disp, Base)) {
726 LLVM_DEBUG(dbgs() << "SUCCESS matched FI\n");
727 return true;
728 }
729
730 if (AM.hasIndexReg()) {
731 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");
732 return false;
733 }
734
735 if (!AM.hasBaseReg()) {
736 LLVM_DEBUG(dbgs() << "REJECT: No Base reg\n");
737 return false;
738 }
739
740 Base = AM.BaseReg;
741
742 if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {
743 assert(!AM.Disp && "Should not be any displacement");
744 LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");
745 return true;
746 }
747
748 // Give a chance to AddrType::ARI
749 if (AM.Disp == 0) {
750 LLVM_DEBUG(dbgs() << "REJECT: No displacement\n");
751 return false;
752 }
753
754 Disp = getI16Imm(AM.Disp, SDLoc(N));
755
756 LLVM_DEBUG(dbgs() << "SUCCESS\n");
757 return true;
758}
759
760static bool isAddressBase(const SDValue &N) {
761 switch (N.getOpcode()) {
762 case ISD::ADD:
763 case ISD::ADDC:
764 return llvm::any_of(N.getNode()->ops(),
765 [](const SDUse &U) { return isAddressBase(U.get()); });
766 case M68kISD::Wrapper:
769 return true;
770 default:
771 return false;
772 }
773}
774
775bool M68kDAGToDAGISel::SelectARII(SDNode *Parent, SDValue N, SDValue &Disp,
777 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARII);
778 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARII: ");
779
780 if (!matchAddress(N, AM))
781 return false;
782
783 if (AM.isPCRelative()) {
784 LLVM_DEBUG(dbgs() << "REJECT: PC relative\n");
785 return false;
786 }
787
788 if (!AM.hasIndexReg()) {
789 LLVM_DEBUG(dbgs() << "REJECT: No Index\n");
790 return false;
791 }
792
793 if (!AM.hasBaseReg()) {
794 LLVM_DEBUG(dbgs() << "REJECT: No Base\n");
795 return false;
796 }
797
798 if (!isAddressBase(AM.BaseReg) && isAddressBase(AM.IndexReg)) {
799 Base = AM.IndexReg;
800 Index = AM.BaseReg;
801 } else {
802 Base = AM.BaseReg;
803 Index = AM.IndexReg;
804 }
805
806 if (AM.hasSymbolicDisplacement()) {
807 LLVM_DEBUG(dbgs() << "REJECT, Cannot match symbolic displacement\n");
808 return false;
809 }
810
811 // The idea here is that we want to use AddrType::ARII without displacement
812 // only if necessary like memory operations, otherwise this must be lowered
813 // into addition
814 if (AM.Disp == 0 && (!Parent || (Parent->getOpcode() != ISD::LOAD &&
815 Parent->getOpcode() != ISD::STORE))) {
816 LLVM_DEBUG(dbgs() << "REJECT: Displacement is Zero\n");
817 return false;
818 }
819
820 Disp = getI8Imm(AM.Disp, SDLoc(N));
821
822 LLVM_DEBUG(dbgs() << "SUCCESS\n");
823 return true;
824}
825
826bool M68kDAGToDAGISel::SelectAL(SDNode *Parent, SDValue N, SDValue &Sym) {
827 LLVM_DEBUG(dbgs() << "Selecting AddrType::AL: ");
828 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::AL);
829
830 if (!matchAddress(N, AM)) {
831 LLVM_DEBUG(dbgs() << "REJECT: Match failed\n");
832 return false;
833 }
834
835 if (AM.isPCRelative()) {
836 LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");
837 return false;
838 }
839
840 if (AM.hasBase()) {
841 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Base\n");
842 return false;
843 }
844
845 if (AM.hasIndexReg()) {
846 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");
847 return false;
848 }
849
850 if (getSymbolicDisplacement(AM, SDLoc(N), Sym)) {
851 LLVM_DEBUG(dbgs() << "SUCCESS: Matched symbol\n");
852 return true;
853 }
854
855 if (AM.Disp) {
856 Sym = getI32Imm(AM.Disp, SDLoc(N));
857 LLVM_DEBUG(dbgs() << "SUCCESS\n");
858 return true;
859 }
860
861 LLVM_DEBUG(dbgs() << "REJECT: Not Symbol or Disp\n");
862 return false;
863 ;
864}
865
866bool M68kDAGToDAGISel::SelectPCD(SDNode *Parent, SDValue N, SDValue &Disp) {
867 LLVM_DEBUG(dbgs() << "Selecting AddrType::PCD: ");
868 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::PCD);
869
870 if (!matchAddress(N, AM))
871 return false;
872
873 if (!AM.isPCRelative()) {
874 LLVM_DEBUG(dbgs() << "REJECT: Not PC relative\n");
875 return false;
876 }
877
878 if (AM.hasIndexReg()) {
879 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");
880 return false;
881 }
882
883 if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {
884 LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");
885 return true;
886 }
887
888 Disp = getI16Imm(AM.Disp, SDLoc(N));
889
890 LLVM_DEBUG(dbgs() << "SUCCESS\n");
891 return true;
892}
893
894bool M68kDAGToDAGISel::SelectPCI(SDNode *Parent, SDValue N, SDValue &Disp,
895 SDValue &Index) {
896 LLVM_DEBUG(dbgs() << "Selecting AddrType::PCI: ");
897 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::PCI);
898
899 if (!matchAddress(N, AM))
900 return false;
901
902 if (!AM.isPCRelative()) {
903 LLVM_DEBUG(dbgs() << "REJECT: Not PC relative\n");
904 return false;
905 }
906
907 if (!AM.hasIndexReg()) {
908 LLVM_DEBUG(dbgs() << "REJECT: No Index\n");
909 return false;
910 }
911
912 Index = AM.IndexReg;
913
914 if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {
915 assert(!AM.Disp && "Should not be any displacement");
916 LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");
917 return true;
918 }
919
920 Disp = getI8Imm(AM.Disp, SDLoc(N));
921
922 LLVM_DEBUG(dbgs() << "SUCCESS\n");
923 return true;
924}
925
926bool M68kDAGToDAGISel::SelectARI(SDNode *Parent, SDValue N, SDValue &Base) {
927 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARI: ");
928 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARI);
929
930 if (!matchAddress(N, AM)) {
931 LLVM_DEBUG(dbgs() << "REJECT: Match failed\n");
932 return false;
933 }
934
935 if (AM.isPCRelative()) {
936 LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");
937 return false;
938 }
939
940 // AddrType::ARI does not use these
941 if (AM.hasIndexReg() || AM.Disp != 0) {
942 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index or Disp\n");
943 return false;
944 }
945
946 // Must be matched by AddrType::AL
947 if (AM.hasSymbolicDisplacement()) {
948 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Symbolic Disp\n");
949 return false;
950 }
951
952 if (AM.hasBaseReg()) {
953 Base = AM.BaseReg;
954 LLVM_DEBUG(dbgs() << "SUCCESS\n");
955 return true;
956 }
957
958 return false;
959}
960
961bool M68kDAGToDAGISel::SelectInlineAsmMemoryOperand(
962 const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,
963 std::vector<SDValue> &OutOps) {
964 // In order to tell AsmPrinter the exact addressing mode we select here, which
965 // might comprise of multiple SDValues (hence MachineOperands), a 32-bit
966 // immediate value is prepended to the list of selected SDValues to indicate
967 // the addressing mode kind.
968 using AMK = M68k::MemAddrModeKind;
969 auto addKind = [this](SDValue &Opnd, AMK Kind) -> bool {
970 Opnd = CurDAG->getTargetConstant(unsigned(Kind), SDLoc(), MVT::i32);
971 return true;
972 };
973
974 switch (ConstraintID) {
975 // Generic memory operand.
976 case InlineAsm::ConstraintCode::m: {
977 // Try every supported (memory) addressing modes.
978 SDValue Operands[4];
979
980 // TODO: The ordering of the following SelectXXX is relatively...arbitrary,
981 // right now we simply sort them by descending complexity. Maybe we should
982 // adjust this by code model and/or relocation mode in the future.
983 if (SelectARII(nullptr, Op, Operands[1], Operands[2], Operands[3]) &&
984 addKind(Operands[0], AMK::f)) {
985 OutOps.insert(OutOps.end(), &Operands[0], Operands + 4);
986 return false;
987 }
988
989 if ((SelectPCI(nullptr, Op, Operands[1], Operands[2]) &&
990 addKind(Operands[0], AMK::k)) ||
991 (SelectARID(nullptr, Op, Operands[1], Operands[2]) &&
992 addKind(Operands[0], AMK::p))) {
993 OutOps.insert(OutOps.end(), &Operands[0], Operands + 3);
994 return false;
995 }
996
997 if ((SelectPCD(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::q)) ||
998 (SelectARI(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::j)) ||
999 (SelectAL(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::b))) {
1000 OutOps.insert(OutOps.end(), {Operands[0], Operands[1]});
1001 return false;
1002 }
1003
1004 return true;
1005 }
1006 // 'Q': Address register indirect addressing.
1007 case InlineAsm::ConstraintCode::Q: {
1008 SDValue AMKind, Base;
1009 // 'j' addressing mode.
1010 // TODO: Add support for 'o' and 'e' after their
1011 // select functions are implemented.
1012 if (SelectARI(nullptr, Op, Base) && addKind(AMKind, AMK::j)) {
1013 OutOps.insert(OutOps.end(), {AMKind, Base});
1014 return false;
1015 }
1016 return true;
1017 }
1018 // 'U': Address register indirect w/ constant offset addressing.
1019 case InlineAsm::ConstraintCode::Um: {
1020 SDValue AMKind, Base, Offset;
1021 // 'p' addressing mode.
1022 if (SelectARID(nullptr, Op, Offset, Base) && addKind(AMKind, AMK::p)) {
1023 OutOps.insert(OutOps.end(), {AMKind, Offset, Base});
1024 return false;
1025 }
1026 return true;
1027 }
1028 default:
1029 return true;
1030 }
1031}
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
amdgpu AMDGPU Register Bank Select
#define LLVM_DEBUG(X)
Definition: Debug.h:101
Symbol * Sym
Definition: ELF_riscv.cpp:479
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:890
This is an important base class in LLVM.
Definition: Constant.h:41
This class represents an Operation in the Expression.
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:311
const GlobalValue * getGlobal() const
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:40
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
An SDNode that represents everything that will be needed to construct a MachineInstr.
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 SelectInlineAsmMemoryOperand(const SDValue &Op, InlineAsm::ConstraintCode ConstraintID, std::vector< SDValue > &OutOps)
SelectInlineAsmMemoryOperand - Select the specified address as a target addressing mode,...
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 ...
virtual bool runOnMachineFunction(MachineFunction &mf)
#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:270
@ ADD
Simple integer binary arithmetic operators.
Definition: ISDOpcodes.h:240
@ LOAD
LOAD and STORE have token chains as their first operand, then the same operands as an LLVM load/store...
Definition: ISDOpcodes.h:1046
@ FrameIndex
Definition: ISDOpcodes.h:80
@ GLOBAL_OFFSET_TABLE
The address of the GOT.
Definition: ISDOpcodes.h:87
@ TargetGlobalTLSAddress
Definition: ISDOpcodes.h:165
@ MO_GOTPCREL
On a symbol operand this indicates that the immediate is offset to the GOT entry for the symbol name ...
Definition: M68kBaseInfo.h:153
@ 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:456
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:1729
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:244
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39