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