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