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
20#include "llvm/CodeGen/MachineConstantPool.h"
21#include "llvm/CodeGen/MachineFrameInfo.h"
22#include "llvm/CodeGen/MachineFunction.h"
23#include "llvm/CodeGen/MachineInstrBuilder.h"
24#include "llvm/CodeGen/MachineRegisterInfo.h"
25#include "llvm/CodeGen/SelectionDAGISel.h"
26#include "llvm/CodeGen/SelectionDAGNodes.h"
27#include "llvm/IR/CFG.h"
28#include "llvm/IR/GlobalValue.h"
29#include "llvm/IR/Instructions.h"
30#include "llvm/IR/Intrinsics.h"
31#include "llvm/IR/Type.h"
32#include "llvm/Support/Alignment.h"
33#include "llvm/Support/Debug.h"
34#include "llvm/Support/ErrorHandling.h"
35#include "llvm/Support/MathExtras.h"
36#include "llvm/Support/raw_ostream.h"
37#include "llvm/Target/TargetMachine.h"
38
39using namespace llvm;
40
41#define DEBUG_TYPE "m68k-isel"
42
43namespace {
44
45// For reference, the full order of operands for memory references is:
46// (Operand), Displacement, Base, Index, Scale
47struct M68kISelAddressMode {
48  enum class AddrType {
49    ARI,   // Address Register Indirect
50    ARIPI, // Address Register Indirect with Postincrement
51    ARIPD, // Address Register Indirect with Postdecrement
52    ARID,  // Address Register Indirect with Displacement
53    ARII,  // Address Register Indirect with Index
54    PCD,   // Program Counter Indirect with Displacement
55    PCI,   // Program Counter Indirect with Index
56    AL,    // Absolute
57  };
58  AddrType AM;
59
60  enum class Base { RegBase, FrameIndexBase };
61  Base BaseType;
62
63  int64_t Disp;
64
65  // This is really a union, discriminated by BaseType!
66  SDValue BaseReg;
67  int BaseFrameIndex;
68
69  SDValue IndexReg;
70  unsigned Scale;
71
72  const GlobalValue *GV;
73  const Constant *CP;
74  const BlockAddress *BlockAddr;
75  const char *ES;
76  MCSymbol *MCSym;
77  int JT;
78  Align Alignment; // CP alignment.
79
80  unsigned char SymbolFlags; // M68kII::MO_*
81
82  M68kISelAddressMode(AddrType AT)
83      : AM(AT), BaseType(Base::RegBase), Disp(0), BaseFrameIndex(0), IndexReg(),
84        Scale(1), GV(nullptr), CP(nullptr), BlockAddr(nullptr), ES(nullptr),
85        MCSym(nullptr), JT(-1), Alignment(), SymbolFlags(M68kII::MO_NO_FLAG) {}
86
87  bool hasSymbolicDisplacement() const {
88    return GV != nullptr || CP != nullptr || ES != nullptr ||
89           MCSym != nullptr || JT != -1 || BlockAddr != nullptr;
90  }
91
92  bool hasBase() const {
93    return BaseType == Base::FrameIndexBase || BaseReg.getNode() != nullptr;
94  }
95
96  bool hasFrameIndex() const { return BaseType == Base::FrameIndexBase; }
97
98  bool hasBaseReg() const {
99    return BaseType == Base::RegBase && BaseReg.getNode() != nullptr;
100  }
101
102  bool hasIndexReg() const {
103    return BaseType == Base::RegBase && IndexReg.getNode() != nullptr;
104  }
105
106  /// True if address mode type supports displacement
107  bool isDispAddrType() const {
108    return AM == AddrType::ARII || AM == AddrType::PCI ||
109           AM == AddrType::ARID || AM == AddrType::PCD || AM == AddrType::AL;
110  }
111
112  unsigned getDispSize() const {
113    switch (AM) {
114    default:
115      return 0;
116    case AddrType::ARII:
117    case AddrType::PCI:
118      return 8;
119    // These two in the next chip generations can hold upto 32 bit
120    case AddrType::ARID:
121    case AddrType::PCD:
122      return 16;
123    case AddrType::AL:
124      return 32;
125    }
126  }
127
128  bool hasDisp() const { return getDispSize() != 0; }
129  bool isDisp8() const { return getDispSize() == 8; }
130  bool isDisp16() const { return getDispSize() == 16; }
131  bool isDisp32() const { return getDispSize() == 32; }
132
133  /// Return true if this addressing mode is already PC-relative.
134  bool isPCRelative() const {
135    if (BaseType != Base::RegBase)
136      return false;
137    if (auto *RegNode = dyn_cast_or_null<RegisterSDNode>(BaseReg.getNode()))
138      return RegNode->getReg() == M68k::PC;
139    return false;
140  }
141
142  void setBaseReg(SDValue Reg) {
143    BaseType = Base::RegBase;
144    BaseReg = Reg;
145  }
146
147  void setIndexReg(SDValue Reg) { IndexReg = Reg; }
148
149#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
150  void dump() {
151    dbgs() << "M68kISelAddressMode " << this;
152    dbgs() << "\nDisp: " << Disp;
153    dbgs() << ", BaseReg: ";
154    if (BaseReg.getNode())
155      BaseReg.getNode()->dump();
156    else
157      dbgs() << "null";
158    dbgs() << ", BaseFI: " << BaseFrameIndex;
159    dbgs() << ", IndexReg: ";
160    if (IndexReg.getNode()) {
161      IndexReg.getNode()->dump();
162    } else {
163      dbgs() << "null";
164      dbgs() << ", Scale: " << Scale;
165    }
166    dbgs() << '\n';
167  }
168#endif
169};
170} // end anonymous namespace
171
172namespace {
173
174class M68kDAGToDAGISel : public SelectionDAGISel {
175public:
176  explicit M68kDAGToDAGISel(M68kTargetMachine &TM)
177      : SelectionDAGISel(TM), Subtarget(nullptr) {}
178
179  StringRef getPassName() const override {
180    return "M68k DAG->DAG Pattern Instruction Selection";
181  }
182
183  bool runOnMachineFunction(MachineFunction &MF) 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
228  // If Address Mode represents Frame Index store FI in Disp and
229  // Displacement bit size in Base. These values are read symmetrically by
230  // M68kRegisterInfo::eliminateFrameIndex method
231  inline bool getFrameIndexAddress(M68kISelAddressMode &AM, const SDLoc &DL,
232                                   SDValue &Disp, SDValue &Base) {
233    if (AM.BaseType == M68kISelAddressMode::Base::FrameIndexBase) {
234      Disp = getI32Imm(AM.Disp, DL);
235      Base = CurDAG->getTargetFrameIndex(
236          AM.BaseFrameIndex, TLI->getPointerTy(CurDAG->getDataLayout()));
237      return true;
238    }
239
240    return false;
241  }
242
243  // Gets a symbol plus optional displacement
244  inline bool getSymbolicDisplacement(M68kISelAddressMode &AM, const SDLoc &DL,
245                                      SDValue &Sym) {
246    if (AM.GV) {
247      Sym = CurDAG->getTargetGlobalAddress(AM.GV, SDLoc(), MVT::i32, AM.Disp,
248                                           AM.SymbolFlags);
249      return true;
250    }
251
252    if (AM.CP) {
253      Sym = CurDAG->getTargetConstantPool(AM.CP, MVT::i32, AM.Alignment,
254                                          AM.Disp, AM.SymbolFlags);
255      return true;
256    }
257
258    if (AM.ES) {
259      assert(!AM.Disp && "Non-zero displacement is ignored with ES.");
260      Sym = CurDAG->getTargetExternalSymbol(AM.ES, MVT::i32, AM.SymbolFlags);
261      return true;
262    }
263
264    if (AM.MCSym) {
265      assert(!AM.Disp && "Non-zero displacement is ignored with MCSym.");
266      assert(AM.SymbolFlags == 0 && "oo");
267      Sym = CurDAG->getMCSymbol(AM.MCSym, MVT::i32);
268      return true;
269    }
270
271    if (AM.JT != -1) {
272      assert(!AM.Disp && "Non-zero displacement is ignored with JT.");
273      Sym = CurDAG->getTargetJumpTable(AM.JT, MVT::i32, AM.SymbolFlags);
274      return true;
275    }
276
277    if (AM.BlockAddr) {
278      Sym = CurDAG->getTargetBlockAddress(AM.BlockAddr, MVT::i32, AM.Disp,
279                                          AM.SymbolFlags);
280      return true;
281    }
282
283    return false;
284  }
285
286  /// Return a target constant with the specified value of type i8.
287  inline SDValue getI8Imm(int64_t Imm, const SDLoc &DL) {
288    return CurDAG->getTargetConstant(Imm, DL, MVT::i8);
289  }
290
291  /// Return a target constant with the specified value of type i8.
292  inline SDValue getI16Imm(int64_t Imm, const SDLoc &DL) {
293    return CurDAG->getTargetConstant(Imm, DL, MVT::i16);
294  }
295
296  /// Return a target constant with the specified value, of type i32.
297  inline SDValue getI32Imm(int64_t Imm, const SDLoc &DL) {
298    return CurDAG->getTargetConstant(Imm, DL, MVT::i32);
299  }
300
301  /// Return a reference to the TargetInstrInfo, casted to the target-specific
302  /// type.
303  const M68kInstrInfo *getInstrInfo() const {
304    return Subtarget->getInstrInfo();
305  }
306
307  /// Return an SDNode that returns the value of the global base register.
308  /// Output instructions required to initialize the global base register,
309  /// if necessary.
310  SDNode *getGlobalBaseReg();
311};
312} // namespace
313
314bool M68kDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
315  Subtarget = &static_cast<const M68kSubtarget &>(MF.getSubtarget());
316  return SelectionDAGISel::runOnMachineFunction(MF);
317}
318
319/// This pass converts a legalized DAG into a M68k-specific DAG,
320/// ready for instruction scheduling.
321FunctionPass *llvm::createM68kISelDag(M68kTargetMachine &TM) {
322  return new M68kDAGToDAGISel(TM);
323}
324
325static bool doesDispFitFI(M68kISelAddressMode &AM) {
326  if (!AM.isDispAddrType())
327    return false;
328  // -1 to make sure that resolved FI will fit into Disp field
329  return isIntN(AM.getDispSize() - 1, AM.Disp);
330}
331
332static bool doesDispFit(M68kISelAddressMode &AM, int64_t Val) {
333  if (!AM.isDispAddrType())
334    return false;
335  return isIntN(AM.getDispSize(), Val);
336}
337
338/// Return an SDNode that returns the value of the global base register.
339/// Output instructions required to initialize the global base register,
340/// if necessary.
341SDNode *M68kDAGToDAGISel::getGlobalBaseReg() {
342  unsigned GlobalBaseReg = getInstrInfo()->getGlobalBaseReg(MF);
343  auto &DL = MF->getDataLayout();
344  return CurDAG->getRegister(GlobalBaseReg, TLI->getPointerTy(DL)).getNode();
345}
346
347bool M68kDAGToDAGISel::foldOffsetIntoAddress(uint64_t Offset,
348                                             M68kISelAddressMode &AM) {
349  // Cannot combine ExternalSymbol displacements with integer offsets.
350  if (Offset != 0 && (AM.ES || AM.MCSym))
351    return false;
352
353  int64_t Val = AM.Disp + Offset;
354
355  if (doesDispFit(AM, Val)) {
356    AM.Disp = Val;
357    return true;
358  }
359
360  return false;
361}
362
363//===----------------------------------------------------------------------===//
364// Matchers
365//===----------------------------------------------------------------------===//
366
367/// Helper for MatchAddress. Add the specified node to the
368/// specified addressing mode without any further recursion.
369bool M68kDAGToDAGISel::matchAddressBase(SDValue N, M68kISelAddressMode &AM) {
370  // Is the base register already occupied?
371  if (AM.hasBase()) {
372    // If so, check to see if the scale index register is set.
373    if (!AM.hasIndexReg()) {
374      AM.IndexReg = N;
375      AM.Scale = 1;
376      return true;
377    }
378
379    // Otherwise, we cannot select it.
380    return false;
381  }
382
383  // Default, generate it as a register.
384  AM.BaseType = M68kISelAddressMode::Base::RegBase;
385  AM.BaseReg = N;
386  return true;
387}
388
389/// TODO Add TLS support
390bool M68kDAGToDAGISel::matchLoadInAddress(LoadSDNode *N,
391                                          M68kISelAddressMode &AM) {
392  return false;
393}
394
395bool M68kDAGToDAGISel::matchAddressRecursively(SDValue N,
396                                               M68kISelAddressMode &AM,
397                                               unsigned Depth) {
398  SDLoc DL(N);
399
400  // Limit recursion.
401  if (Depth > 5)
402    return matchAddressBase(N, AM);
403
404  // If this is already a %PC relative address, we can only merge immediates
405  // into it.  Instead of handling this in every case, we handle it here.
406  // PC relative addressing: %PC + 16-bit displacement!
407  if (AM.isPCRelative()) {
408    // FIXME JumpTable and ExternalSymbol address currently don't like
409    // displacements.  It isn't very important, but should be fixed for
410    // consistency.
411
412    if (ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(N))
413      if (foldOffsetIntoAddress(Cst->getSExtValue(), AM))
414        return true;
415    return false;
416  }
417
418  switch (N.getOpcode()) {
419  default:
420    break;
421
422  case ISD::Constant: {
423    uint64_t Val = cast<ConstantSDNode>(N)->getSExtValue();
424    if (foldOffsetIntoAddress(Val, AM))
425      return true;
426    break;
427  }
428
429  case M68kISD::Wrapper:
430  case M68kISD::WrapperPC:
431    if (matchWrapper(N, AM))
432      return true;
433    break;
434
435  case ISD::LOAD:
436    if (matchLoadInAddress(cast<LoadSDNode>(N), AM))
437      return true;
438    break;
439
440  case ISD::OR:
441    // We want to look through a transform in InstCombine and DAGCombiner that
442    // turns 'add' into 'or', so we can treat this 'or' exactly like an 'add'.
443    // Example: (or (and x, 1), (shl y, 3)) --> (add (and x, 1), (shl y, 3))
444    // An 'lea' can then be used to match the shift (multiply) and add:
445    // and $1, %esi
446    // lea (%rsi, %rdi, 8), %rax
447    if (CurDAG->haveNoCommonBitsSet(N.getOperand(0), N.getOperand(1)) &&
448        matchADD(N, AM, Depth))
449      return true;
450    break;
451
452  case ISD::ADD:
453    if (matchADD(N, AM, Depth))
454      return true;
455    break;
456
457  case ISD::FrameIndex:
458    if (AM.isDispAddrType() &&
459        AM.BaseType == M68kISelAddressMode::Base::RegBase &&
460        AM.BaseReg.getNode() == nullptr && doesDispFitFI(AM)) {
461      AM.BaseType = M68kISelAddressMode::Base::FrameIndexBase;
462      AM.BaseFrameIndex = cast<FrameIndexSDNode>(N)->getIndex();
463      return true;
464    }
465    break;
466  }
467
468  return matchAddressBase(N, AM);
469}
470
471/// Add the specified node to the specified addressing mode, returning true if
472/// it cannot be done. This just pattern matches for the addressing mode.
473bool M68kDAGToDAGISel::matchAddress(SDValue N, M68kISelAddressMode &AM) {
474  // TODO: Post-processing: Convert lea(,%reg,2) to lea(%reg,%reg), which has
475  // a smaller encoding and avoids a scaled-index.
476  // And make sure it is an indexed mode
477
478  // TODO: Post-processing: Convert foo to foo(%pc), even in non-PIC mode,
479  // because it has a smaller encoding.
480  // Make sure this must be done only if PC* modes are currently being matched
481  return matchAddressRecursively(N, AM, 0);
482}
483
484bool M68kDAGToDAGISel::matchADD(SDValue &N, M68kISelAddressMode &AM,
485                                unsigned Depth) {
486  // Add an artificial use to this node so that we can keep track of
487  // it if it gets CSE'd with a different node.
488  HandleSDNode Handle(N);
489
490  M68kISelAddressMode Backup = AM;
491  if (matchAddressRecursively(N.getOperand(0), AM, Depth + 1) &&
492      matchAddressRecursively(Handle.getValue().getOperand(1), AM, Depth + 1)) {
493    return true;
494  }
495  AM = Backup;
496
497  // Try again after commuting the operands.
498  if (matchAddressRecursively(Handle.getValue().getOperand(1), AM, Depth + 1) &&
499      matchAddressRecursively(Handle.getValue().getOperand(0), AM, Depth + 1)) {
500    return true;
501  }
502  AM = Backup;
503
504  // If we couldn't fold both operands into the address at the same time,
505  // see if we can just put each operand into a register and fold at least
506  // the add.
507  if (!AM.hasBase() && !AM.hasIndexReg()) {
508    N = Handle.getValue();
509    AM.BaseReg = N.getOperand(0);
510    AM.IndexReg = N.getOperand(1);
511    AM.Scale = 1;
512    return true;
513  }
514
515  N = Handle.getValue();
516  return false;
517}
518
519/// Try to match M68kISD::Wrapper and M68kISD::WrapperPC nodes into an
520/// addressing mode. These wrap things that will resolve down into a symbol
521/// reference. If no match is possible, this returns true, otherwise it returns
522/// false.
523bool M68kDAGToDAGISel::matchWrapper(SDValue N, M68kISelAddressMode &AM) {
524  // If the addressing mode already has a symbol as the displacement, we can
525  // never match another symbol.
526  if (AM.hasSymbolicDisplacement())
527    return false;
528
529  SDValue N0 = N.getOperand(0);
530
531  if (N.getOpcode() == M68kISD::WrapperPC) {
532
533    // If cannot match here just restore the old version
534    M68kISelAddressMode Backup = AM;
535
536    if (AM.hasBase()) {
537      return false;
538    }
539
540    if (auto *G = dyn_cast<GlobalAddressSDNode>(N0)) {
541      AM.GV = G->getGlobal();
542      AM.SymbolFlags = G->getTargetFlags();
543      if (!foldOffsetIntoAddress(G->getOffset(), AM)) {
544        AM = Backup;
545        return false;
546      }
547    } else if (auto *CP = dyn_cast<ConstantPoolSDNode>(N0)) {
548      AM.CP = CP->getConstVal();
549      AM.Alignment = CP->getAlign();
550      AM.SymbolFlags = CP->getTargetFlags();
551      if (!foldOffsetIntoAddress(CP->getOffset(), AM)) {
552        AM = Backup;
553        return false;
554      }
555    } else if (auto *S = dyn_cast<ExternalSymbolSDNode>(N0)) {
556      AM.ES = S->getSymbol();
557      AM.SymbolFlags = S->getTargetFlags();
558    } else if (auto *S = dyn_cast<MCSymbolSDNode>(N0)) {
559      AM.MCSym = S->getMCSymbol();
560    } else if (auto *J = dyn_cast<JumpTableSDNode>(N0)) {
561      AM.JT = J->getIndex();
562      AM.SymbolFlags = J->getTargetFlags();
563    } else if (auto *BA = dyn_cast<BlockAddressSDNode>(N0)) {
564      AM.BlockAddr = BA->getBlockAddress();
565      AM.SymbolFlags = BA->getTargetFlags();
566      if (!foldOffsetIntoAddress(BA->getOffset(), AM)) {
567        AM = Backup;
568        return false;
569      }
570    } else
571      llvm_unreachable("Unhandled symbol reference node.");
572
573    AM.setBaseReg(CurDAG->getRegister(M68k::PC, MVT::i32));
574    return true;
575  }
576
577  // This wrapper requires 32bit disp/imm field for Medium CM
578  if (!AM.isDisp32()) {
579    return false;
580  }
581
582  if (N.getOpcode() == M68kISD::Wrapper) {
583    if (auto *G = dyn_cast<GlobalAddressSDNode>(N0)) {
584      AM.GV = G->getGlobal();
585      AM.Disp += G->getOffset();
586      AM.SymbolFlags = G->getTargetFlags();
587    } else if (auto *CP = dyn_cast<ConstantPoolSDNode>(N0)) {
588      AM.CP = CP->getConstVal();
589      AM.Alignment = CP->getAlign();
590      AM.Disp += CP->getOffset();
591      AM.SymbolFlags = CP->getTargetFlags();
592    } else if (auto *S = dyn_cast<ExternalSymbolSDNode>(N0)) {
593      AM.ES = S->getSymbol();
594      AM.SymbolFlags = S->getTargetFlags();
595    } else if (auto *S = dyn_cast<MCSymbolSDNode>(N0)) {
596      AM.MCSym = S->getMCSymbol();
597    } else if (auto *J = dyn_cast<JumpTableSDNode>(N0)) {
598      AM.JT = J->getIndex();
599      AM.SymbolFlags = J->getTargetFlags();
600    } else if (auto *BA = dyn_cast<BlockAddressSDNode>(N0)) {
601      AM.BlockAddr = BA->getBlockAddress();
602      AM.Disp += BA->getOffset();
603      AM.SymbolFlags = BA->getTargetFlags();
604    } else
605      llvm_unreachable("Unhandled symbol reference node.");
606    return true;
607  }
608
609  return false;
610}
611
612//===----------------------------------------------------------------------===//
613// Selectors
614//===----------------------------------------------------------------------===//
615
616void M68kDAGToDAGISel::Select(SDNode *Node) {
617  unsigned Opcode = Node->getOpcode();
618  SDLoc DL(Node);
619
620  LLVM_DEBUG(dbgs() << "Selecting: "; Node->dump(CurDAG); dbgs() << '\n');
621
622  if (Node->isMachineOpcode()) {
623    LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << '\n');
624    Node->setNodeId(-1);
625    return; // Already selected.
626  }
627
628  switch (Opcode) {
629  default:
630    break;
631
632  case M68kISD::GLOBAL_BASE_REG:
633    ReplaceNode(Node, getGlobalBaseReg());
634    return;
635  }
636
637  SelectCode(Node);
638}
639
640bool M68kDAGToDAGISel::SelectARIPI(SDNode *Parent, SDValue N, SDValue &Base) {
641  LLVM_DEBUG(dbgs() << "Selecting AddrType::ARIPI: ");
642  LLVM_DEBUG(dbgs() << "NOT IMPLEMENTED\n");
643  return false;
644}
645
646bool M68kDAGToDAGISel::SelectARIPD(SDNode *Parent, SDValue N, SDValue &Base) {
647  LLVM_DEBUG(dbgs() << "Selecting AddrType::ARIPD: ");
648  LLVM_DEBUG(dbgs() << "NOT IMPLEMENTED\n");
649  return false;
650}
651
652bool M68kDAGToDAGISel::SelectARID(SDNode *Parent, SDValue N, SDValue &Disp,
653                                  SDValue &Base) {
654  LLVM_DEBUG(dbgs() << "Selecting AddrType::ARID: ");
655  M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARID);
656
657  if (!matchAddress(N, AM))
658    return false;
659
660  if (AM.isPCRelative()) {
661    LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");
662    return false;
663  }
664
665  // If this is a frame index, grab it
666  if (getFrameIndexAddress(AM, SDLoc(N), Disp, Base)) {
667    LLVM_DEBUG(dbgs() << "SUCCESS matched FI\n");
668    return true;
669  }
670
671  if (AM.hasIndexReg()) {
672    LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");
673    return false;
674  }
675
676  if (!AM.hasBaseReg()) {
677    LLVM_DEBUG(dbgs() << "REJECT: No Base reg\n");
678    return false;
679  }
680
681  if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {
682    assert(!AM.Disp && "Should not be any displacement");
683    LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");
684    return true;
685  }
686
687  // Give a chance to AddrType::ARI
688  if (AM.Disp == 0) {
689    LLVM_DEBUG(dbgs() << "REJECT: No displacement\n");
690    return false;
691  }
692
693  Base = AM.BaseReg;
694  Disp = getI16Imm(AM.Disp, SDLoc(N));
695
696  LLVM_DEBUG(dbgs() << "SUCCESS\n");
697  return true;
698}
699
700static bool isAddressBase(const SDValue &N) {
701  switch (N.getOpcode()) {
702  case ISD::ADD:
703  case ISD::ADDC:
704    return llvm::any_of(N.getNode()->ops(),
705                        [](const SDUse &U) { return isAddressBase(U.get()); });
706  case M68kISD::Wrapper:
707  case M68kISD::WrapperPC:
708  case M68kISD::GLOBAL_BASE_REG:
709    return true;
710  default:
711    return false;
712  }
713}
714
715bool M68kDAGToDAGISel::SelectARII(SDNode *Parent, SDValue N, SDValue &Disp,
716                                  SDValue &Base, SDValue &Index) {
717  M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARII);
718  LLVM_DEBUG(dbgs() << "Selecting AddrType::ARII: ");
719
720  if (!matchAddress(N, AM))
721    return false;
722
723  if (AM.isPCRelative()) {
724    LLVM_DEBUG(dbgs() << "REJECT: PC relative\n");
725    return false;
726  }
727
728  if (!AM.hasIndexReg()) {
729    LLVM_DEBUG(dbgs() << "REJECT: No Index\n");
730    return false;
731  }
732
733  if (!AM.hasBaseReg()) {
734    LLVM_DEBUG(dbgs() << "REJECT: No Base\n");
735    return false;
736  }
737
738  if (!isAddressBase(AM.BaseReg) && isAddressBase(AM.IndexReg)) {
739    Base = AM.IndexReg;
740    Index = AM.BaseReg;
741  } else {
742    Base = AM.BaseReg;
743    Index = AM.IndexReg;
744  }
745
746  if (AM.hasSymbolicDisplacement()) {
747    LLVM_DEBUG(dbgs() << "REJECT, Cannot match symbolic displacement\n");
748    return false;
749  }
750
751  // The idea here is that we want to use AddrType::ARII without displacement
752  // only if necessary like memory operations, otherwise this must be lowered
753  // into addition
754  if (AM.Disp == 0 && (!Parent || (Parent->getOpcode() != ISD::LOAD &&
755                                   Parent->getOpcode() != ISD::STORE))) {
756    LLVM_DEBUG(dbgs() << "REJECT: Displacement is Zero\n");
757    return false;
758  }
759
760  Disp = getI8Imm(AM.Disp, SDLoc(N));
761
762  LLVM_DEBUG(dbgs() << "SUCCESS\n");
763  return true;
764}
765
766bool M68kDAGToDAGISel::SelectAL(SDNode *Parent, SDValue N, SDValue &Sym) {
767  LLVM_DEBUG(dbgs() << "Selecting AddrType::AL: ");
768  M68kISelAddressMode AM(M68kISelAddressMode::AddrType::AL);
769
770  if (!matchAddress(N, AM)) {
771    LLVM_DEBUG(dbgs() << "REJECT: Match failed\n");
772    return false;
773  }
774
775  if (AM.isPCRelative()) {
776    LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");
777    return false;
778  }
779
780  if (AM.hasBase()) {
781    LLVM_DEBUG(dbgs() << "REJECT: Cannot match Base\n");
782    return false;
783  }
784
785  if (AM.hasIndexReg()) {
786    LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");
787    return false;
788  }
789
790  if (getSymbolicDisplacement(AM, SDLoc(N), Sym)) {
791    LLVM_DEBUG(dbgs() << "SUCCESS: Matched symbol\n");
792    return true;
793  }
794
795  if (AM.Disp) {
796    Sym = getI32Imm(AM.Disp, SDLoc(N));
797    LLVM_DEBUG(dbgs() << "SUCCESS\n");
798    return true;
799  }
800
801  LLVM_DEBUG(dbgs() << "REJECT: Not Symbol or Disp\n");
802  return false;
803  ;
804}
805
806bool M68kDAGToDAGISel::SelectPCD(SDNode *Parent, SDValue N, SDValue &Disp) {
807  LLVM_DEBUG(dbgs() << "Selecting AddrType::PCD: ");
808  M68kISelAddressMode AM(M68kISelAddressMode::AddrType::PCD);
809
810  if (!matchAddress(N, AM))
811    return false;
812
813  if (!AM.isPCRelative()) {
814    LLVM_DEBUG(dbgs() << "REJECT: Not PC relative\n");
815    return false;
816  }
817
818  if (AM.hasIndexReg()) {
819    LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");
820    return false;
821  }
822
823  if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {
824    LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");
825    return true;
826  }
827
828  Disp = getI16Imm(AM.Disp, SDLoc(N));
829
830  LLVM_DEBUG(dbgs() << "SUCCESS\n");
831  return true;
832}
833
834bool M68kDAGToDAGISel::SelectPCI(SDNode *Parent, SDValue N, SDValue &Disp,
835                                 SDValue &Index) {
836  LLVM_DEBUG(dbgs() << "Selecting AddrType::PCI: ");
837  M68kISelAddressMode AM(M68kISelAddressMode::AddrType::PCI);
838
839  if (!matchAddress(N, AM))
840    return false;
841
842  if (!AM.isPCRelative()) {
843    LLVM_DEBUG(dbgs() << "REJECT: Not PC relative\n");
844    return false;
845  }
846
847  if (!AM.hasIndexReg()) {
848    LLVM_DEBUG(dbgs() << "REJECT: No Index\n");
849    return false;
850  }
851
852  Index = AM.IndexReg;
853
854  if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {
855    assert(!AM.Disp && "Should not be any displacement");
856    LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");
857    return true;
858  }
859
860  Disp = getI8Imm(AM.Disp, SDLoc(N));
861
862  LLVM_DEBUG(dbgs() << "SUCCESS\n");
863  return true;
864}
865
866bool M68kDAGToDAGISel::SelectARI(SDNode *Parent, SDValue N, SDValue &Base) {
867  LLVM_DEBUG(dbgs() << "Selecting AddrType::ARI: ");
868  M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARI);
869
870  if (!matchAddress(N, AM)) {
871    LLVM_DEBUG(dbgs() << "REJECT: Match failed\n");
872    return false;
873  }
874
875  if (AM.isPCRelative()) {
876    LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");
877    return false;
878  }
879
880  // AddrType::ARI does not use these
881  if (AM.hasIndexReg() || AM.Disp != 0) {
882    LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index or Disp\n");
883    return false;
884  }
885
886  // Must be matched by AddrType::AL
887  if (AM.hasSymbolicDisplacement()) {
888    LLVM_DEBUG(dbgs() << "REJECT: Cannot match Symbolic Disp\n");
889    return false;
890  }
891
892  if (AM.hasBaseReg()) {
893    Base = AM.BaseReg;
894    LLVM_DEBUG(dbgs() << "SUCCESS\n");
895    return true;
896  }
897
898  return false;
899}
900