brintos

brintos / llvm-project-archived public Read only

0
0
Text · 31.4 KiB · 9c3d61e Raw
1061 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// 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 "M68kSelectionDAGInfo.h"19#include "M68kTargetMachine.h"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#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, Scale48struct M68kISelAddressMode {49  enum class AddrType {50    ARI,   // Address Register Indirect51    ARIPI, // Address Register Indirect with Postincrement52    ARIPD, // Address Register Indirect with Postdecrement53    ARID,  // Address Register Indirect with Displacement54    ARII,  // Address Register Indirect with Index55    PCD,   // Program Counter Indirect with Displacement56    PCI,   // Program Counter Indirect with Index57    AL,    // Absolute58  };59  AddrType AM;60 61  enum class Base { RegBase, FrameIndexBase };62  Base BaseType;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 displacement108  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 bit121    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    else158      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#endif170};171} // end anonymous namespace172 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 can187  /// 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, casted194  /// 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 the202  // 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  bool SelectInlineAsmMemoryOperand(const SDValue &Op,229                                    InlineAsm::ConstraintCode ConstraintID,230                                    std::vector<SDValue> &OutOps) override;231 232  // If Address Mode represents Frame Index store FI in Disp and233  // Displacement bit size in Base. These values are read symmetrically by234  // M68kRegisterInfo::eliminateFrameIndex method235  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 displacement248  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-specific306  /// 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} // namespace327 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, %d0344      //   sub.l	(4,%sp), %d0345      // vs.346      //   move.l	(4,%sp), %d0347      //   neg.l	%d0348      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>();359  return SelectionDAGISel::runOnMachineFunction(MF);360}361 362/// This pass converts a legalized DAG into a M68k-specific DAG,363/// ready for instruction scheduling.364FunctionPass *llvm::createM68kISelDag(M68kTargetMachine &TM) {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 field372  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// Matchers408//===----------------------------------------------------------------------===//409 410/// Helper for MatchAddress. Add the specified node to the411/// 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 support433bool 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 immediates448  // 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 like452    // displacements.  It isn't very important, but should be fixed for453    // 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:473  case M68kISD::WrapperPC: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 that485    // 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, %esi489    // lea (%rsi, %rdi, 8), %rax490    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 510  case ISD::TargetGlobalTLSAddress: {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 if522/// 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 has525  // a smaller encoding and avoids a scaled-index.526  // And make sure it is an indexed mode527 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 matched531  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 of537  // 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 least556  // 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 an570/// addressing mode. These wrap things that will resolve down into a symbol571/// reference. If no match is possible, this returns true, otherwise it returns572/// false.573bool M68kDAGToDAGISel::matchWrapper(SDValue N, M68kISelAddressMode &AM) {574  // If the addressing mode already has a symbol as the displacement, we can575  // 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 version584    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    } else621      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 CM628  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    } else655      llvm_unreachable("Unhandled symbol reference node.");656    return true;657  }658 659  return false;660}661 662//===----------------------------------------------------------------------===//663// Selectors664//===----------------------------------------------------------------------===//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 682  case ISD::GLOBAL_OFFSET_TABLE: {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 691  case M68kISD::GLOBAL_BASE_REG: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:718  case ISD::ATOMIC_STORE: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 it739  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::ARI764  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:782  case M68kISD::WrapperPC:783  case M68kISD::GLOBAL_BASE_REG: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:797  case ISD::ATOMIC_STORE:798  case ISD::ATOMIC_CMP_SWAP: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 displacement842  // only if necessary like memory operations, otherwise this must be lowered843  // into addition844  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 these970  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::AL976  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, which994  // might comprise of multiple SDValues (hence MachineOperands), a 32-bit995  // immediate value is prepended to the list of selected SDValues to indicate996  // 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 should1011    // 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 their1040    // 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}1061