LLVM 20.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->getSignedTargetConstant(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->getSignedTargetConstant(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->getSignedTargetConstant(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
711[[maybe_unused]] static bool allowARIDWithDisp(SDNode *Parent) {
712 if (!Parent)
713 return false;
714 switch (Parent->getOpcode()) {
715 case ISD::LOAD:
716 case ISD::STORE:
717 case ISD::ATOMIC_LOAD:
719 return true;
720 default:
721 return false;
722 }
723}
724
725bool M68kDAGToDAGISel::SelectARID(SDNode *Parent, SDValue N, SDValue &Disp,
726 SDValue &Base) {
727 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARID: ");
728 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARID);
729
730 if (!matchAddress(N, AM))
731 return false;
732
733 if (AM.isPCRelative()) {
734 LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");
735 return false;
736 }
737
738 // If this is a frame index, grab it
739 if (getFrameIndexAddress(AM, SDLoc(N), Disp, Base)) {
740 LLVM_DEBUG(dbgs() << "SUCCESS matched FI\n");
741 return true;
742 }
743
744 if (AM.hasIndexReg()) {
745 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");
746 return false;
747 }
748
749 if (!AM.hasBaseReg()) {
750 LLVM_DEBUG(dbgs() << "REJECT: No Base reg\n");
751 return false;
752 }
753
754 Base = AM.BaseReg;
755
756 if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {
757 assert((!AM.Disp || allowARIDWithDisp(Parent)) &&
758 "Should not be any displacement");
759 LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");
760 return true;
761 }
762
763 // Give a chance to AddrType::ARI
764 if (AM.Disp == 0) {
765 LLVM_DEBUG(dbgs() << "REJECT: No displacement\n");
766 return false;
767 }
768
769 Disp = getI16Imm(AM.Disp, SDLoc(N));
770
771 LLVM_DEBUG(dbgs() << "SUCCESS\n");
772 return true;
773}
774
775static bool isAddressBase(const SDValue &N) {
776 switch (N.getOpcode()) {
777 case ISD::ADD:
778 case ISD::ADDC:
779 return llvm::any_of(N.getNode()->ops(),
780 [](const SDUse &U) { return isAddressBase(U.get()); });
781 case M68kISD::Wrapper:
784 return true;
785 default:
786 return false;
787 }
788}
789
790static bool AllowARIIWithZeroDisp(SDNode *Parent) {
791 if (!Parent)
792 return false;
793 switch (Parent->getOpcode()) {
794 case ISD::LOAD:
795 case ISD::STORE:
796 case ISD::ATOMIC_LOAD:
799 return true;
800 default:
801 return false;
802 }
803}
804
805bool M68kDAGToDAGISel::SelectARII(SDNode *Parent, SDValue N, SDValue &Disp,
806 SDValue &Base, SDValue &Index) {
807 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARII);
808 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARII: ");
809
810 if (!matchAddress(N, AM))
811 return false;
812
813 if (AM.isPCRelative()) {
814 LLVM_DEBUG(dbgs() << "REJECT: PC relative\n");
815 return false;
816 }
817
818 if (!AM.hasIndexReg()) {
819 LLVM_DEBUG(dbgs() << "REJECT: No Index\n");
820 return false;
821 }
822
823 if (!AM.hasBaseReg()) {
824 LLVM_DEBUG(dbgs() << "REJECT: No Base\n");
825 return false;
826 }
827
828 if (!isAddressBase(AM.BaseReg) && isAddressBase(AM.IndexReg)) {
829 Base = AM.IndexReg;
830 Index = AM.BaseReg;
831 } else {
832 Base = AM.BaseReg;
833 Index = AM.IndexReg;
834 }
835
836 if (AM.hasSymbolicDisplacement()) {
837 LLVM_DEBUG(dbgs() << "REJECT, Cannot match symbolic displacement\n");
838 return false;
839 }
840
841 // The idea here is that we want to use AddrType::ARII without displacement
842 // only if necessary like memory operations, otherwise this must be lowered
843 // into addition
844 if (AM.Disp == 0 && !AllowARIIWithZeroDisp(Parent)) {
845 LLVM_DEBUG(dbgs() << "REJECT: Displacement is Zero\n");
846 return false;
847 }
848
849 Disp = getI8Imm(AM.Disp, SDLoc(N));
850
851 LLVM_DEBUG(dbgs() << "SUCCESS\n");
852 return true;
853}
854
855bool M68kDAGToDAGISel::SelectAL(SDNode *Parent, SDValue N, SDValue &Sym) {
856 LLVM_DEBUG(dbgs() << "Selecting AddrType::AL: ");
857 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::AL);
858
859 if (!matchAddress(N, AM)) {
860 LLVM_DEBUG(dbgs() << "REJECT: Match failed\n");
861 return false;
862 }
863
864 if (AM.isPCRelative()) {
865 LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");
866 return false;
867 }
868
869 if (AM.hasBase()) {
870 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Base\n");
871 return false;
872 }
873
874 if (AM.hasIndexReg()) {
875 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");
876 return false;
877 }
878
879 if (getSymbolicDisplacement(AM, SDLoc(N), Sym)) {
880 LLVM_DEBUG(dbgs() << "SUCCESS: Matched symbol\n");
881 return true;
882 }
883
884 if (AM.Disp) {
885 Sym = getI32Imm(AM.Disp, SDLoc(N));
886 LLVM_DEBUG(dbgs() << "SUCCESS\n");
887 return true;
888 }
889
890 LLVM_DEBUG(dbgs() << "REJECT: Not Symbol or Disp\n");
891 return false;
892 ;
893}
894
895bool M68kDAGToDAGISel::SelectPCD(SDNode *Parent, SDValue N, SDValue &Disp) {
896 LLVM_DEBUG(dbgs() << "Selecting AddrType::PCD: ");
897 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::PCD);
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: Cannot match Index\n");
909 return false;
910 }
911
912 if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {
913 LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");
914 return true;
915 }
916
917 Disp = getI16Imm(AM.Disp, SDLoc(N));
918
919 LLVM_DEBUG(dbgs() << "SUCCESS\n");
920 return true;
921}
922
923bool M68kDAGToDAGISel::SelectPCI(SDNode *Parent, SDValue N, SDValue &Disp,
924 SDValue &Index) {
925 LLVM_DEBUG(dbgs() << "Selecting AddrType::PCI: ");
926 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::PCI);
927
928 if (!matchAddress(N, AM))
929 return false;
930
931 if (!AM.isPCRelative()) {
932 LLVM_DEBUG(dbgs() << "REJECT: Not PC relative\n");
933 return false;
934 }
935
936 if (!AM.hasIndexReg()) {
937 LLVM_DEBUG(dbgs() << "REJECT: No Index\n");
938 return false;
939 }
940
941 Index = AM.IndexReg;
942
943 if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {
944 assert(!AM.Disp && "Should not be any displacement");
945 LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");
946 return true;
947 }
948
949 Disp = getI8Imm(AM.Disp, SDLoc(N));
950
951 LLVM_DEBUG(dbgs() << "SUCCESS\n");
952 return true;
953}
954
955bool M68kDAGToDAGISel::SelectARI(SDNode *Parent, SDValue N, SDValue &Base) {
956 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARI: ");
957 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARI);
958
959 if (!matchAddress(N, AM)) {
960 LLVM_DEBUG(dbgs() << "REJECT: Match failed\n");
961 return false;
962 }
963
964 if (AM.isPCRelative()) {
965 LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");
966 return false;
967 }
968
969 // AddrType::ARI does not use these
970 if (AM.hasIndexReg() || AM.Disp != 0) {
971 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index or Disp\n");
972 return false;
973 }
974
975 // Must be matched by AddrType::AL
976 if (AM.hasSymbolicDisplacement()) {
977 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Symbolic Disp\n");
978 return false;
979 }
980
981 if (AM.hasBaseReg()) {
982 Base = AM.BaseReg;
983 LLVM_DEBUG(dbgs() << "SUCCESS\n");
984 return true;
985 }
986
987 return false;
988}
989
990bool M68kDAGToDAGISel::SelectInlineAsmMemoryOperand(
991 const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,
992 std::vector<SDValue> &OutOps) {
993 // In order to tell AsmPrinter the exact addressing mode we select here, which
994 // might comprise of multiple SDValues (hence MachineOperands), a 32-bit
995 // immediate value is prepended to the list of selected SDValues to indicate
996 // the addressing mode kind.
997 using AMK = M68k::MemAddrModeKind;
998 auto addKind = [this](SDValue &Opnd, AMK Kind) -> bool {
999 Opnd = CurDAG->getTargetConstant(unsigned(Kind), SDLoc(), MVT::i32);
1000 return true;
1001 };
1002
1003 switch (ConstraintID) {
1004 // Generic memory operand.
1005 case InlineAsm::ConstraintCode::m: {
1006 // Try every supported (memory) addressing modes.
1007 SDValue Operands[4];
1008
1009 // TODO: The ordering of the following SelectXXX is relatively...arbitrary,
1010 // right now we simply sort them by descending complexity. Maybe we should
1011 // adjust this by code model and/or relocation mode in the future.
1012 if (SelectARII(nullptr, Op, Operands[1], Operands[2], Operands[3]) &&
1013 addKind(Operands[0], AMK::f)) {
1014 OutOps.insert(OutOps.end(), &Operands[0], Operands + 4);
1015 return false;
1016 }
1017
1018 if ((SelectPCI(nullptr, Op, Operands[1], Operands[2]) &&
1019 addKind(Operands[0], AMK::k)) ||
1020 (SelectARID(nullptr, Op, Operands[1], Operands[2]) &&
1021 addKind(Operands[0], AMK::p))) {
1022 OutOps.insert(OutOps.end(), &Operands[0], Operands + 3);
1023 return false;
1024 }
1025
1026 if ((SelectPCD(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::q)) ||
1027 (SelectARI(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::j)) ||
1028 (SelectAL(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::b))) {
1029 OutOps.insert(OutOps.end(), {Operands[0], Operands[1]});
1030 return false;
1031 }
1032
1033 return true;
1034 }
1035 // 'Q': Address register indirect addressing.
1036 case InlineAsm::ConstraintCode::Q: {
1037 SDValue AMKind, Base;
1038 // 'j' addressing mode.
1039 // TODO: Add support for 'o' and 'e' after their
1040 // select functions are implemented.
1041 if (SelectARI(nullptr, Op, Base) && addKind(AMKind, AMK::j)) {
1042 OutOps.insert(OutOps.end(), {AMKind, Base});
1043 return false;
1044 }
1045 return true;
1046 }
1047 // 'U': Address register indirect w/ constant offset addressing.
1048 case InlineAsm::ConstraintCode::Um: {
1049 SDValue AMKind, Base, Offset;
1050 // 'p' addressing mode.
1051 if (SelectARID(nullptr, Op, Offset, Base) && addKind(AMKind, AMK::p)) {
1052 OutOps.insert(OutOps.end(), {AMKind, Offset, Base});
1053 return false;
1054 }
1055 return true;
1056 }
1057 default:
1058 return true;
1059 }
1060}
AMDGPU Register Bank Select
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
#define LLVM_DEBUG(...)
Definition: Debug.h:106
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 allowARIDWithDisp(SDNode *Parent)
static bool doesDispFitFI(M68kISelAddressMode &AM)
static bool isAddressBase(const SDValue &N)
#define PASS_NAME
#define DEBUG_TYPE
static bool AllowARIIWithZeroDisp(SDNode *Parent)
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 ...
#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:893
This is an important base class in LLVM.
Definition: Constant.h:42
This class represents an Operation in the Expression.
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:310
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:41
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
@ ATOMIC_STORE
OUTCHAIN = ATOMIC_STORE(INCHAIN, val, ptr) This corresponds to "store atomic" instruction.
Definition: ISDOpcodes.h:1312
@ ADDC
Carry-setting nodes for multiple precision addition and subtraction.
Definition: ISDOpcodes.h:276
@ ADD
Simple integer binary arithmetic operators.
Definition: ISDOpcodes.h:246
@ LOAD
LOAD and STORE have token chains as their first operand, then the same operands as an LLVM load/store...
Definition: ISDOpcodes.h:1102
@ FrameIndex
Definition: ISDOpcodes.h:80
@ ATOMIC_LOAD
Val, OUTCHAIN = ATOMIC_LOAD(INCHAIN, ptr) This corresponds to "load atomic" instruction.
Definition: ISDOpcodes.h:1308
@ ATOMIC_CMP_SWAP
Val, OUTCHAIN = ATOMIC_CMP_SWAP(INCHAIN, ptr, cmp, swap) For double-word atomic operations: ValLo,...
Definition: ISDOpcodes.h:1319
@ GLOBAL_OFFSET_TABLE
The address of the GOT.
Definition: ISDOpcodes.h:93
@ TargetGlobalTLSAddress
Definition: ISDOpcodes.h:171
@ 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:480
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:1746
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:260
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