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" 42bdd1243dSDimitry 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: 177bdd1243dSDimitry Andric M68kDAGToDAGISel() = delete; 178bdd1243dSDimitry Andric 179bdd1243dSDimitry Andric explicit M68kDAGToDAGISel(M68kTargetMachine &TM) 180*0fca6ea1SDimitry Andric : SelectionDAGISel(TM), Subtarget(nullptr) {} 181fe6060f1SDimitry Andric 182fe6060f1SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 18381ad6265SDimitry Andric bool IsProfitableToFold(SDValue N, SDNode *U, SDNode *Root) const override; 184fe6060f1SDimitry Andric 185fe6060f1SDimitry Andric private: 186fe6060f1SDimitry Andric /// Keep a pointer to the M68kSubtarget around so that we can 187fe6060f1SDimitry Andric /// make the right decision when generating code for different targets. 188fe6060f1SDimitry Andric const M68kSubtarget *Subtarget; 189fe6060f1SDimitry Andric 190fe6060f1SDimitry Andric // Include the pieces autogenerated from the target description. 191fe6060f1SDimitry Andric #include "M68kGenDAGISel.inc" 192fe6060f1SDimitry Andric 193fe6060f1SDimitry Andric /// getTargetMachine - Return a reference to the TargetMachine, casted 194fe6060f1SDimitry Andric /// to the target-specific type. 195fe6060f1SDimitry Andric const M68kTargetMachine &getTargetMachine() { 196fe6060f1SDimitry Andric return static_cast<const M68kTargetMachine &>(TM); 197fe6060f1SDimitry Andric } 198fe6060f1SDimitry Andric 199fe6060f1SDimitry Andric void Select(SDNode *N) override; 200fe6060f1SDimitry Andric 201fe6060f1SDimitry Andric // Insert instructions to initialize the global base register in the 202fe6060f1SDimitry Andric // first MBB of the function. 203fe6060f1SDimitry Andric // HMM... do i need this? 204fe6060f1SDimitry Andric void initGlobalBaseReg(MachineFunction &MF); 205fe6060f1SDimitry Andric 206fe6060f1SDimitry Andric bool foldOffsetIntoAddress(uint64_t Offset, M68kISelAddressMode &AM); 207fe6060f1SDimitry Andric 208fe6060f1SDimitry Andric bool matchLoadInAddress(LoadSDNode *N, M68kISelAddressMode &AM); 209fe6060f1SDimitry Andric bool matchAddress(SDValue N, M68kISelAddressMode &AM); 210fe6060f1SDimitry Andric bool matchAddressBase(SDValue N, M68kISelAddressMode &AM); 211fe6060f1SDimitry Andric bool matchAddressRecursively(SDValue N, M68kISelAddressMode &AM, 212fe6060f1SDimitry Andric unsigned Depth); 213fe6060f1SDimitry Andric bool matchADD(SDValue &N, M68kISelAddressMode &AM, unsigned Depth); 214fe6060f1SDimitry Andric bool matchWrapper(SDValue N, M68kISelAddressMode &AM); 215fe6060f1SDimitry Andric 216fe6060f1SDimitry Andric std::pair<bool, SDNode *> selectNode(SDNode *Node); 217fe6060f1SDimitry Andric 218fe6060f1SDimitry Andric bool SelectARI(SDNode *Parent, SDValue N, SDValue &Base); 219fe6060f1SDimitry Andric bool SelectARIPI(SDNode *Parent, SDValue N, SDValue &Base); 220fe6060f1SDimitry Andric bool SelectARIPD(SDNode *Parent, SDValue N, SDValue &Base); 221fe6060f1SDimitry Andric bool SelectARID(SDNode *Parent, SDValue N, SDValue &Imm, SDValue &Base); 222fe6060f1SDimitry Andric bool SelectARII(SDNode *Parent, SDValue N, SDValue &Imm, SDValue &Base, 223fe6060f1SDimitry Andric SDValue &Index); 224fe6060f1SDimitry Andric bool SelectAL(SDNode *Parent, SDValue N, SDValue &Sym); 225fe6060f1SDimitry Andric bool SelectPCD(SDNode *Parent, SDValue N, SDValue &Imm); 226fe6060f1SDimitry Andric bool SelectPCI(SDNode *Parent, SDValue N, SDValue &Imm, SDValue &Index); 227fe6060f1SDimitry Andric 2285f757f3fSDimitry Andric bool SelectInlineAsmMemoryOperand(const SDValue &Op, 2295f757f3fSDimitry Andric InlineAsm::ConstraintCode ConstraintID, 23006c3fb27SDimitry Andric std::vector<SDValue> &OutOps) override; 23106c3fb27SDimitry Andric 232fe6060f1SDimitry Andric // If Address Mode represents Frame Index store FI in Disp and 233fe6060f1SDimitry Andric // Displacement bit size in Base. These values are read symmetrically by 234fe6060f1SDimitry Andric // M68kRegisterInfo::eliminateFrameIndex method 235fe6060f1SDimitry Andric inline bool getFrameIndexAddress(M68kISelAddressMode &AM, const SDLoc &DL, 236fe6060f1SDimitry Andric SDValue &Disp, SDValue &Base) { 237fe6060f1SDimitry Andric if (AM.BaseType == M68kISelAddressMode::Base::FrameIndexBase) { 238fe6060f1SDimitry Andric Disp = getI32Imm(AM.Disp, DL); 239fe6060f1SDimitry Andric Base = CurDAG->getTargetFrameIndex( 240fe6060f1SDimitry Andric AM.BaseFrameIndex, TLI->getPointerTy(CurDAG->getDataLayout())); 241fe6060f1SDimitry Andric return true; 242fe6060f1SDimitry Andric } 243fe6060f1SDimitry Andric 244fe6060f1SDimitry Andric return false; 245fe6060f1SDimitry Andric } 246fe6060f1SDimitry Andric 247fe6060f1SDimitry Andric // Gets a symbol plus optional displacement 248fe6060f1SDimitry Andric inline bool getSymbolicDisplacement(M68kISelAddressMode &AM, const SDLoc &DL, 249fe6060f1SDimitry Andric SDValue &Sym) { 250fe6060f1SDimitry Andric if (AM.GV) { 251fe6060f1SDimitry Andric Sym = CurDAG->getTargetGlobalAddress(AM.GV, SDLoc(), MVT::i32, AM.Disp, 252fe6060f1SDimitry Andric AM.SymbolFlags); 253fe6060f1SDimitry Andric return true; 254fe6060f1SDimitry Andric } 255fe6060f1SDimitry Andric 256fe6060f1SDimitry Andric if (AM.CP) { 257fe6060f1SDimitry Andric Sym = CurDAG->getTargetConstantPool(AM.CP, MVT::i32, AM.Alignment, 258fe6060f1SDimitry Andric AM.Disp, AM.SymbolFlags); 259fe6060f1SDimitry Andric return true; 260fe6060f1SDimitry Andric } 261fe6060f1SDimitry Andric 262fe6060f1SDimitry Andric if (AM.ES) { 263fe6060f1SDimitry Andric assert(!AM.Disp && "Non-zero displacement is ignored with ES."); 264fe6060f1SDimitry Andric Sym = CurDAG->getTargetExternalSymbol(AM.ES, MVT::i32, AM.SymbolFlags); 265fe6060f1SDimitry Andric return true; 266fe6060f1SDimitry Andric } 267fe6060f1SDimitry Andric 268fe6060f1SDimitry Andric if (AM.MCSym) { 269fe6060f1SDimitry Andric assert(!AM.Disp && "Non-zero displacement is ignored with MCSym."); 270fe6060f1SDimitry Andric assert(AM.SymbolFlags == 0 && "oo"); 271fe6060f1SDimitry Andric Sym = CurDAG->getMCSymbol(AM.MCSym, MVT::i32); 272fe6060f1SDimitry Andric return true; 273fe6060f1SDimitry Andric } 274fe6060f1SDimitry Andric 275fe6060f1SDimitry Andric if (AM.JT != -1) { 276fe6060f1SDimitry Andric assert(!AM.Disp && "Non-zero displacement is ignored with JT."); 277fe6060f1SDimitry Andric Sym = CurDAG->getTargetJumpTable(AM.JT, MVT::i32, AM.SymbolFlags); 278fe6060f1SDimitry Andric return true; 279fe6060f1SDimitry Andric } 280fe6060f1SDimitry Andric 281fe6060f1SDimitry Andric if (AM.BlockAddr) { 282fe6060f1SDimitry Andric Sym = CurDAG->getTargetBlockAddress(AM.BlockAddr, MVT::i32, AM.Disp, 283fe6060f1SDimitry Andric AM.SymbolFlags); 284fe6060f1SDimitry Andric return true; 285fe6060f1SDimitry Andric } 286fe6060f1SDimitry Andric 287fe6060f1SDimitry Andric return false; 288fe6060f1SDimitry Andric } 289fe6060f1SDimitry Andric 290fe6060f1SDimitry Andric /// Return a target constant with the specified value of type i8. 291fe6060f1SDimitry Andric inline SDValue getI8Imm(int64_t Imm, const SDLoc &DL) { 292fe6060f1SDimitry Andric return CurDAG->getTargetConstant(Imm, DL, MVT::i8); 293fe6060f1SDimitry Andric } 294fe6060f1SDimitry Andric 295fe6060f1SDimitry Andric /// Return a target constant with the specified value of type i8. 296fe6060f1SDimitry Andric inline SDValue getI16Imm(int64_t Imm, const SDLoc &DL) { 297fe6060f1SDimitry Andric return CurDAG->getTargetConstant(Imm, DL, MVT::i16); 298fe6060f1SDimitry Andric } 299fe6060f1SDimitry Andric 300fe6060f1SDimitry Andric /// Return a target constant with the specified value, of type i32. 301fe6060f1SDimitry Andric inline SDValue getI32Imm(int64_t Imm, const SDLoc &DL) { 302fe6060f1SDimitry Andric return CurDAG->getTargetConstant(Imm, DL, MVT::i32); 303fe6060f1SDimitry Andric } 304fe6060f1SDimitry Andric 305fe6060f1SDimitry Andric /// Return a reference to the TargetInstrInfo, casted to the target-specific 306fe6060f1SDimitry Andric /// type. 307fe6060f1SDimitry Andric const M68kInstrInfo *getInstrInfo() const { 308fe6060f1SDimitry Andric return Subtarget->getInstrInfo(); 309fe6060f1SDimitry Andric } 310fe6060f1SDimitry Andric 311fe6060f1SDimitry Andric /// Return an SDNode that returns the value of the global base register. 312fe6060f1SDimitry Andric /// Output instructions required to initialize the global base register, 313fe6060f1SDimitry Andric /// if necessary. 314fe6060f1SDimitry Andric SDNode *getGlobalBaseReg(); 315fe6060f1SDimitry Andric }; 316bdd1243dSDimitry Andric 317*0fca6ea1SDimitry Andric class M68kDAGToDAGISelLegacy : public SelectionDAGISelLegacy { 318*0fca6ea1SDimitry Andric public: 319*0fca6ea1SDimitry Andric static char ID; 320*0fca6ea1SDimitry Andric explicit M68kDAGToDAGISelLegacy(M68kTargetMachine &TM) 321*0fca6ea1SDimitry Andric : SelectionDAGISelLegacy(ID, std::make_unique<M68kDAGToDAGISel>(TM)) {} 322*0fca6ea1SDimitry Andric }; 323*0fca6ea1SDimitry Andric 324*0fca6ea1SDimitry Andric char M68kDAGToDAGISelLegacy::ID; 325bdd1243dSDimitry Andric 326fe6060f1SDimitry Andric } // namespace 327fe6060f1SDimitry Andric 328*0fca6ea1SDimitry Andric INITIALIZE_PASS(M68kDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false) 329bdd1243dSDimitry Andric 33081ad6265SDimitry Andric bool M68kDAGToDAGISel::IsProfitableToFold(SDValue N, SDNode *U, 33181ad6265SDimitry Andric SDNode *Root) const { 3325f757f3fSDimitry Andric if (OptLevel == CodeGenOptLevel::None) 33381ad6265SDimitry Andric return false; 33481ad6265SDimitry Andric 33581ad6265SDimitry Andric if (U == Root) { 33681ad6265SDimitry Andric switch (U->getOpcode()) { 33781ad6265SDimitry Andric default: 33881ad6265SDimitry Andric return true; 33981ad6265SDimitry Andric case M68kISD::SUB: 34081ad6265SDimitry Andric case ISD::SUB: 34181ad6265SDimitry Andric // Prefer NEG instruction when zero subtracts a value. 34281ad6265SDimitry Andric // e.g. 34381ad6265SDimitry Andric // move.l #0, %d0 34481ad6265SDimitry Andric // sub.l (4,%sp), %d0 34581ad6265SDimitry Andric // vs. 34681ad6265SDimitry Andric // move.l (4,%sp), %d0 34781ad6265SDimitry Andric // neg.l %d0 34881ad6265SDimitry Andric if (llvm::isNullConstant(U->getOperand(0))) 34981ad6265SDimitry Andric return false; 35081ad6265SDimitry Andric break; 35181ad6265SDimitry Andric } 35281ad6265SDimitry Andric } 35381ad6265SDimitry Andric 35481ad6265SDimitry Andric return true; 35581ad6265SDimitry Andric } 35681ad6265SDimitry Andric 357fe6060f1SDimitry Andric bool M68kDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { 35881ad6265SDimitry Andric Subtarget = &MF.getSubtarget<M68kSubtarget>(); 359fe6060f1SDimitry Andric return SelectionDAGISel::runOnMachineFunction(MF); 360fe6060f1SDimitry Andric } 361fe6060f1SDimitry Andric 362fe6060f1SDimitry Andric /// This pass converts a legalized DAG into a M68k-specific DAG, 363fe6060f1SDimitry Andric /// ready for instruction scheduling. 364fe6060f1SDimitry Andric FunctionPass *llvm::createM68kISelDag(M68kTargetMachine &TM) { 365*0fca6ea1SDimitry Andric return new M68kDAGToDAGISelLegacy(TM); 366fe6060f1SDimitry Andric } 367fe6060f1SDimitry Andric 368fe6060f1SDimitry Andric static bool doesDispFitFI(M68kISelAddressMode &AM) { 369fe6060f1SDimitry Andric if (!AM.isDispAddrType()) 370fe6060f1SDimitry Andric return false; 371fe6060f1SDimitry Andric // -1 to make sure that resolved FI will fit into Disp field 372fe6060f1SDimitry Andric return isIntN(AM.getDispSize() - 1, AM.Disp); 373fe6060f1SDimitry Andric } 374fe6060f1SDimitry Andric 375fe6060f1SDimitry Andric static bool doesDispFit(M68kISelAddressMode &AM, int64_t Val) { 376fe6060f1SDimitry Andric if (!AM.isDispAddrType()) 377fe6060f1SDimitry Andric return false; 378fe6060f1SDimitry Andric return isIntN(AM.getDispSize(), Val); 379fe6060f1SDimitry Andric } 380fe6060f1SDimitry Andric 381fe6060f1SDimitry Andric /// Return an SDNode that returns the value of the global base register. 382fe6060f1SDimitry Andric /// Output instructions required to initialize the global base register, 383fe6060f1SDimitry Andric /// if necessary. 384fe6060f1SDimitry Andric SDNode *M68kDAGToDAGISel::getGlobalBaseReg() { 385fe6060f1SDimitry Andric unsigned GlobalBaseReg = getInstrInfo()->getGlobalBaseReg(MF); 386fe6060f1SDimitry Andric auto &DL = MF->getDataLayout(); 387fe6060f1SDimitry Andric return CurDAG->getRegister(GlobalBaseReg, TLI->getPointerTy(DL)).getNode(); 388fe6060f1SDimitry Andric } 389fe6060f1SDimitry Andric 390fe6060f1SDimitry Andric bool M68kDAGToDAGISel::foldOffsetIntoAddress(uint64_t Offset, 391fe6060f1SDimitry Andric M68kISelAddressMode &AM) { 392fe6060f1SDimitry Andric // Cannot combine ExternalSymbol displacements with integer offsets. 393fe6060f1SDimitry Andric if (Offset != 0 && (AM.ES || AM.MCSym)) 394fe6060f1SDimitry Andric return false; 395fe6060f1SDimitry Andric 396fe6060f1SDimitry Andric int64_t Val = AM.Disp + Offset; 397fe6060f1SDimitry Andric 398fe6060f1SDimitry Andric if (doesDispFit(AM, Val)) { 399fe6060f1SDimitry Andric AM.Disp = Val; 400fe6060f1SDimitry Andric return true; 401fe6060f1SDimitry Andric } 402fe6060f1SDimitry Andric 403fe6060f1SDimitry Andric return false; 404fe6060f1SDimitry Andric } 405fe6060f1SDimitry Andric 406fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 407fe6060f1SDimitry Andric // Matchers 408fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 409fe6060f1SDimitry Andric 410fe6060f1SDimitry Andric /// Helper for MatchAddress. Add the specified node to the 411fe6060f1SDimitry Andric /// specified addressing mode without any further recursion. 412fe6060f1SDimitry Andric bool M68kDAGToDAGISel::matchAddressBase(SDValue N, M68kISelAddressMode &AM) { 413fe6060f1SDimitry Andric // Is the base register already occupied? 414fe6060f1SDimitry Andric if (AM.hasBase()) { 415fe6060f1SDimitry Andric // If so, check to see if the scale index register is set. 416fe6060f1SDimitry Andric if (!AM.hasIndexReg()) { 417fe6060f1SDimitry Andric AM.IndexReg = N; 418fe6060f1SDimitry Andric AM.Scale = 1; 419fe6060f1SDimitry Andric return true; 420fe6060f1SDimitry Andric } 421fe6060f1SDimitry Andric 422fe6060f1SDimitry Andric // Otherwise, we cannot select it. 423fe6060f1SDimitry Andric return false; 424fe6060f1SDimitry Andric } 425fe6060f1SDimitry Andric 426fe6060f1SDimitry Andric // Default, generate it as a register. 427fe6060f1SDimitry Andric AM.BaseType = M68kISelAddressMode::Base::RegBase; 428fe6060f1SDimitry Andric AM.BaseReg = N; 429fe6060f1SDimitry Andric return true; 430fe6060f1SDimitry Andric } 431fe6060f1SDimitry Andric 432fe6060f1SDimitry Andric /// TODO Add TLS support 433fe6060f1SDimitry Andric bool M68kDAGToDAGISel::matchLoadInAddress(LoadSDNode *N, 434fe6060f1SDimitry Andric M68kISelAddressMode &AM) { 435fe6060f1SDimitry Andric return false; 436fe6060f1SDimitry Andric } 437fe6060f1SDimitry Andric 438fe6060f1SDimitry Andric bool M68kDAGToDAGISel::matchAddressRecursively(SDValue N, 439fe6060f1SDimitry Andric M68kISelAddressMode &AM, 440fe6060f1SDimitry Andric unsigned Depth) { 441fe6060f1SDimitry Andric SDLoc DL(N); 442fe6060f1SDimitry Andric 443fe6060f1SDimitry Andric // Limit recursion. 444fe6060f1SDimitry Andric if (Depth > 5) 445fe6060f1SDimitry Andric return matchAddressBase(N, AM); 446fe6060f1SDimitry Andric 447fe6060f1SDimitry Andric // If this is already a %PC relative address, we can only merge immediates 448fe6060f1SDimitry Andric // into it. Instead of handling this in every case, we handle it here. 449fe6060f1SDimitry Andric // PC relative addressing: %PC + 16-bit displacement! 450fe6060f1SDimitry Andric if (AM.isPCRelative()) { 451fe6060f1SDimitry Andric // FIXME JumpTable and ExternalSymbol address currently don't like 452fe6060f1SDimitry Andric // displacements. It isn't very important, but should be fixed for 453fe6060f1SDimitry Andric // consistency. 454fe6060f1SDimitry Andric 455fe6060f1SDimitry Andric if (ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(N)) 456fe6060f1SDimitry Andric if (foldOffsetIntoAddress(Cst->getSExtValue(), AM)) 457fe6060f1SDimitry Andric return true; 458fe6060f1SDimitry Andric return false; 459fe6060f1SDimitry Andric } 460fe6060f1SDimitry Andric 461fe6060f1SDimitry Andric switch (N.getOpcode()) { 462fe6060f1SDimitry Andric default: 463fe6060f1SDimitry Andric break; 464fe6060f1SDimitry Andric 465fe6060f1SDimitry Andric case ISD::Constant: { 466fe6060f1SDimitry Andric uint64_t Val = cast<ConstantSDNode>(N)->getSExtValue(); 467fe6060f1SDimitry Andric if (foldOffsetIntoAddress(Val, AM)) 468fe6060f1SDimitry Andric return true; 469fe6060f1SDimitry Andric break; 470fe6060f1SDimitry Andric } 471fe6060f1SDimitry Andric 472fe6060f1SDimitry Andric case M68kISD::Wrapper: 473fe6060f1SDimitry Andric case M68kISD::WrapperPC: 474fe6060f1SDimitry Andric if (matchWrapper(N, AM)) 475fe6060f1SDimitry Andric return true; 476fe6060f1SDimitry Andric break; 477fe6060f1SDimitry Andric 478fe6060f1SDimitry Andric case ISD::LOAD: 479fe6060f1SDimitry Andric if (matchLoadInAddress(cast<LoadSDNode>(N), AM)) 480fe6060f1SDimitry Andric return true; 481fe6060f1SDimitry Andric break; 482fe6060f1SDimitry Andric 483fe6060f1SDimitry Andric case ISD::OR: 484fe6060f1SDimitry Andric // We want to look through a transform in InstCombine and DAGCombiner that 485fe6060f1SDimitry Andric // turns 'add' into 'or', so we can treat this 'or' exactly like an 'add'. 486fe6060f1SDimitry Andric // Example: (or (and x, 1), (shl y, 3)) --> (add (and x, 1), (shl y, 3)) 487fe6060f1SDimitry Andric // An 'lea' can then be used to match the shift (multiply) and add: 488fe6060f1SDimitry Andric // and $1, %esi 489fe6060f1SDimitry Andric // lea (%rsi, %rdi, 8), %rax 490fe6060f1SDimitry Andric if (CurDAG->haveNoCommonBitsSet(N.getOperand(0), N.getOperand(1)) && 491fe6060f1SDimitry Andric matchADD(N, AM, Depth)) 492fe6060f1SDimitry Andric return true; 493fe6060f1SDimitry Andric break; 494fe6060f1SDimitry Andric 495fe6060f1SDimitry Andric case ISD::ADD: 496fe6060f1SDimitry Andric if (matchADD(N, AM, Depth)) 497fe6060f1SDimitry Andric return true; 498fe6060f1SDimitry Andric break; 499fe6060f1SDimitry Andric 500fe6060f1SDimitry Andric case ISD::FrameIndex: 501fe6060f1SDimitry Andric if (AM.isDispAddrType() && 502fe6060f1SDimitry Andric AM.BaseType == M68kISelAddressMode::Base::RegBase && 503fe6060f1SDimitry Andric AM.BaseReg.getNode() == nullptr && doesDispFitFI(AM)) { 504fe6060f1SDimitry Andric AM.BaseType = M68kISelAddressMode::Base::FrameIndexBase; 505fe6060f1SDimitry Andric AM.BaseFrameIndex = cast<FrameIndexSDNode>(N)->getIndex(); 506fe6060f1SDimitry Andric return true; 507fe6060f1SDimitry Andric } 508fe6060f1SDimitry Andric break; 50906c3fb27SDimitry Andric 51006c3fb27SDimitry Andric case ISD::TargetGlobalTLSAddress: { 51106c3fb27SDimitry Andric GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(N); 51206c3fb27SDimitry Andric AM.GV = GA->getGlobal(); 51306c3fb27SDimitry Andric AM.SymbolFlags = GA->getTargetFlags(); 51406c3fb27SDimitry Andric return true; 51506c3fb27SDimitry Andric } 516fe6060f1SDimitry Andric } 517fe6060f1SDimitry Andric 518fe6060f1SDimitry Andric return matchAddressBase(N, AM); 519fe6060f1SDimitry Andric } 520fe6060f1SDimitry Andric 521fe6060f1SDimitry Andric /// Add the specified node to the specified addressing mode, returning true if 522fe6060f1SDimitry Andric /// it cannot be done. This just pattern matches for the addressing mode. 523fe6060f1SDimitry Andric bool M68kDAGToDAGISel::matchAddress(SDValue N, M68kISelAddressMode &AM) { 524fe6060f1SDimitry Andric // TODO: Post-processing: Convert lea(,%reg,2) to lea(%reg,%reg), which has 525fe6060f1SDimitry Andric // a smaller encoding and avoids a scaled-index. 526fe6060f1SDimitry Andric // And make sure it is an indexed mode 527fe6060f1SDimitry Andric 528fe6060f1SDimitry Andric // TODO: Post-processing: Convert foo to foo(%pc), even in non-PIC mode, 529fe6060f1SDimitry Andric // because it has a smaller encoding. 530fe6060f1SDimitry Andric // Make sure this must be done only if PC* modes are currently being matched 531fe6060f1SDimitry Andric return matchAddressRecursively(N, AM, 0); 532fe6060f1SDimitry Andric } 533fe6060f1SDimitry Andric 534fe6060f1SDimitry Andric bool M68kDAGToDAGISel::matchADD(SDValue &N, M68kISelAddressMode &AM, 535fe6060f1SDimitry Andric unsigned Depth) { 536fe6060f1SDimitry Andric // Add an artificial use to this node so that we can keep track of 537fe6060f1SDimitry Andric // it if it gets CSE'd with a different node. 538fe6060f1SDimitry Andric HandleSDNode Handle(N); 539fe6060f1SDimitry Andric 540fe6060f1SDimitry Andric M68kISelAddressMode Backup = AM; 541fe6060f1SDimitry Andric if (matchAddressRecursively(N.getOperand(0), AM, Depth + 1) && 542fe6060f1SDimitry Andric matchAddressRecursively(Handle.getValue().getOperand(1), AM, Depth + 1)) { 543fe6060f1SDimitry Andric return true; 544fe6060f1SDimitry Andric } 545fe6060f1SDimitry Andric AM = Backup; 546fe6060f1SDimitry Andric 547fe6060f1SDimitry Andric // Try again after commuting the operands. 548fe6060f1SDimitry Andric if (matchAddressRecursively(Handle.getValue().getOperand(1), AM, Depth + 1) && 549fe6060f1SDimitry Andric matchAddressRecursively(Handle.getValue().getOperand(0), AM, Depth + 1)) { 550fe6060f1SDimitry Andric return true; 551fe6060f1SDimitry Andric } 552fe6060f1SDimitry Andric AM = Backup; 553fe6060f1SDimitry Andric 554fe6060f1SDimitry Andric // If we couldn't fold both operands into the address at the same time, 555fe6060f1SDimitry Andric // see if we can just put each operand into a register and fold at least 556fe6060f1SDimitry Andric // the add. 557fe6060f1SDimitry Andric if (!AM.hasBase() && !AM.hasIndexReg()) { 558fe6060f1SDimitry Andric N = Handle.getValue(); 559fe6060f1SDimitry Andric AM.BaseReg = N.getOperand(0); 560fe6060f1SDimitry Andric AM.IndexReg = N.getOperand(1); 561fe6060f1SDimitry Andric AM.Scale = 1; 562fe6060f1SDimitry Andric return true; 563fe6060f1SDimitry Andric } 564fe6060f1SDimitry Andric 565fe6060f1SDimitry Andric N = Handle.getValue(); 566fe6060f1SDimitry Andric return false; 567fe6060f1SDimitry Andric } 568fe6060f1SDimitry Andric 569fe6060f1SDimitry Andric /// Try to match M68kISD::Wrapper and M68kISD::WrapperPC nodes into an 570fe6060f1SDimitry Andric /// addressing mode. These wrap things that will resolve down into a symbol 571fe6060f1SDimitry Andric /// reference. If no match is possible, this returns true, otherwise it returns 572fe6060f1SDimitry Andric /// false. 573fe6060f1SDimitry Andric bool M68kDAGToDAGISel::matchWrapper(SDValue N, M68kISelAddressMode &AM) { 574fe6060f1SDimitry Andric // If the addressing mode already has a symbol as the displacement, we can 575fe6060f1SDimitry Andric // never match another symbol. 576fe6060f1SDimitry Andric if (AM.hasSymbolicDisplacement()) 577fe6060f1SDimitry Andric return false; 578fe6060f1SDimitry Andric 579fe6060f1SDimitry Andric SDValue N0 = N.getOperand(0); 580fe6060f1SDimitry Andric 581fe6060f1SDimitry Andric if (N.getOpcode() == M68kISD::WrapperPC) { 582fe6060f1SDimitry Andric 583fe6060f1SDimitry Andric // If cannot match here just restore the old version 584fe6060f1SDimitry Andric M68kISelAddressMode Backup = AM; 585fe6060f1SDimitry Andric 586fe6060f1SDimitry Andric if (AM.hasBase()) { 587fe6060f1SDimitry Andric return false; 588fe6060f1SDimitry Andric } 589fe6060f1SDimitry Andric 590fe6060f1SDimitry Andric if (auto *G = dyn_cast<GlobalAddressSDNode>(N0)) { 591fe6060f1SDimitry Andric AM.GV = G->getGlobal(); 592fe6060f1SDimitry Andric AM.SymbolFlags = G->getTargetFlags(); 593fe6060f1SDimitry Andric if (!foldOffsetIntoAddress(G->getOffset(), AM)) { 594fe6060f1SDimitry Andric AM = Backup; 595fe6060f1SDimitry Andric return false; 596fe6060f1SDimitry Andric } 597fe6060f1SDimitry Andric } else if (auto *CP = dyn_cast<ConstantPoolSDNode>(N0)) { 598fe6060f1SDimitry Andric AM.CP = CP->getConstVal(); 599fe6060f1SDimitry Andric AM.Alignment = CP->getAlign(); 600fe6060f1SDimitry Andric AM.SymbolFlags = CP->getTargetFlags(); 601fe6060f1SDimitry Andric if (!foldOffsetIntoAddress(CP->getOffset(), AM)) { 602fe6060f1SDimitry Andric AM = Backup; 603fe6060f1SDimitry Andric return false; 604fe6060f1SDimitry Andric } 605fe6060f1SDimitry Andric } else if (auto *S = dyn_cast<ExternalSymbolSDNode>(N0)) { 606fe6060f1SDimitry Andric AM.ES = S->getSymbol(); 607fe6060f1SDimitry Andric AM.SymbolFlags = S->getTargetFlags(); 608fe6060f1SDimitry Andric } else if (auto *S = dyn_cast<MCSymbolSDNode>(N0)) { 609fe6060f1SDimitry Andric AM.MCSym = S->getMCSymbol(); 610fe6060f1SDimitry Andric } else if (auto *J = dyn_cast<JumpTableSDNode>(N0)) { 611fe6060f1SDimitry Andric AM.JT = J->getIndex(); 612fe6060f1SDimitry Andric AM.SymbolFlags = J->getTargetFlags(); 613fe6060f1SDimitry Andric } else if (auto *BA = dyn_cast<BlockAddressSDNode>(N0)) { 614fe6060f1SDimitry Andric AM.BlockAddr = BA->getBlockAddress(); 615fe6060f1SDimitry Andric AM.SymbolFlags = BA->getTargetFlags(); 616fe6060f1SDimitry Andric if (!foldOffsetIntoAddress(BA->getOffset(), AM)) { 617fe6060f1SDimitry Andric AM = Backup; 618fe6060f1SDimitry Andric return false; 619fe6060f1SDimitry Andric } 620fe6060f1SDimitry Andric } else 621fe6060f1SDimitry Andric llvm_unreachable("Unhandled symbol reference node."); 622fe6060f1SDimitry Andric 623fe6060f1SDimitry Andric AM.setBaseReg(CurDAG->getRegister(M68k::PC, MVT::i32)); 624fe6060f1SDimitry Andric return true; 625fe6060f1SDimitry Andric } 626fe6060f1SDimitry Andric 627fe6060f1SDimitry Andric // This wrapper requires 32bit disp/imm field for Medium CM 628fe6060f1SDimitry Andric if (!AM.isDisp32()) { 629fe6060f1SDimitry Andric return false; 630fe6060f1SDimitry Andric } 631fe6060f1SDimitry Andric 632fe6060f1SDimitry Andric if (N.getOpcode() == M68kISD::Wrapper) { 633fe6060f1SDimitry Andric if (auto *G = dyn_cast<GlobalAddressSDNode>(N0)) { 634fe6060f1SDimitry Andric AM.GV = G->getGlobal(); 635fe6060f1SDimitry Andric AM.Disp += G->getOffset(); 636fe6060f1SDimitry Andric AM.SymbolFlags = G->getTargetFlags(); 637fe6060f1SDimitry Andric } else if (auto *CP = dyn_cast<ConstantPoolSDNode>(N0)) { 638fe6060f1SDimitry Andric AM.CP = CP->getConstVal(); 639fe6060f1SDimitry Andric AM.Alignment = CP->getAlign(); 640fe6060f1SDimitry Andric AM.Disp += CP->getOffset(); 641fe6060f1SDimitry Andric AM.SymbolFlags = CP->getTargetFlags(); 642fe6060f1SDimitry Andric } else if (auto *S = dyn_cast<ExternalSymbolSDNode>(N0)) { 643fe6060f1SDimitry Andric AM.ES = S->getSymbol(); 644fe6060f1SDimitry Andric AM.SymbolFlags = S->getTargetFlags(); 645fe6060f1SDimitry Andric } else if (auto *S = dyn_cast<MCSymbolSDNode>(N0)) { 646fe6060f1SDimitry Andric AM.MCSym = S->getMCSymbol(); 647fe6060f1SDimitry Andric } else if (auto *J = dyn_cast<JumpTableSDNode>(N0)) { 648fe6060f1SDimitry Andric AM.JT = J->getIndex(); 649fe6060f1SDimitry Andric AM.SymbolFlags = J->getTargetFlags(); 650fe6060f1SDimitry Andric } else if (auto *BA = dyn_cast<BlockAddressSDNode>(N0)) { 651fe6060f1SDimitry Andric AM.BlockAddr = BA->getBlockAddress(); 652fe6060f1SDimitry Andric AM.Disp += BA->getOffset(); 653fe6060f1SDimitry Andric AM.SymbolFlags = BA->getTargetFlags(); 654fe6060f1SDimitry Andric } else 655fe6060f1SDimitry Andric llvm_unreachable("Unhandled symbol reference node."); 656fe6060f1SDimitry Andric return true; 657fe6060f1SDimitry Andric } 658fe6060f1SDimitry Andric 659fe6060f1SDimitry Andric return false; 660fe6060f1SDimitry Andric } 661fe6060f1SDimitry Andric 662fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 663fe6060f1SDimitry Andric // Selectors 664fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 665fe6060f1SDimitry Andric 666fe6060f1SDimitry Andric void M68kDAGToDAGISel::Select(SDNode *Node) { 667fe6060f1SDimitry Andric unsigned Opcode = Node->getOpcode(); 668fe6060f1SDimitry Andric SDLoc DL(Node); 669fe6060f1SDimitry Andric 670fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "Selecting: "; Node->dump(CurDAG); dbgs() << '\n'); 671fe6060f1SDimitry Andric 672fe6060f1SDimitry Andric if (Node->isMachineOpcode()) { 673fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << '\n'); 674fe6060f1SDimitry Andric Node->setNodeId(-1); 675fe6060f1SDimitry Andric return; // Already selected. 676fe6060f1SDimitry Andric } 677fe6060f1SDimitry Andric 678fe6060f1SDimitry Andric switch (Opcode) { 679fe6060f1SDimitry Andric default: 680fe6060f1SDimitry Andric break; 681fe6060f1SDimitry Andric 68206c3fb27SDimitry Andric case ISD::GLOBAL_OFFSET_TABLE: { 68306c3fb27SDimitry Andric SDValue GOT = CurDAG->getTargetExternalSymbol( 68406c3fb27SDimitry Andric "_GLOBAL_OFFSET_TABLE_", MVT::i32, M68kII::MO_GOTPCREL); 68506c3fb27SDimitry Andric MachineSDNode *Res = 68606c3fb27SDimitry Andric CurDAG->getMachineNode(M68k::LEA32q, DL, MVT::i32, GOT); 68706c3fb27SDimitry Andric ReplaceNode(Node, Res); 68806c3fb27SDimitry Andric return; 68906c3fb27SDimitry Andric } 69006c3fb27SDimitry Andric 691fe6060f1SDimitry Andric case M68kISD::GLOBAL_BASE_REG: 692fe6060f1SDimitry Andric ReplaceNode(Node, getGlobalBaseReg()); 693fe6060f1SDimitry Andric return; 694fe6060f1SDimitry Andric } 695fe6060f1SDimitry Andric 696fe6060f1SDimitry Andric SelectCode(Node); 697fe6060f1SDimitry Andric } 698fe6060f1SDimitry Andric 699fe6060f1SDimitry Andric bool M68kDAGToDAGISel::SelectARIPI(SDNode *Parent, SDValue N, SDValue &Base) { 700fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "Selecting AddrType::ARIPI: "); 701fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "NOT IMPLEMENTED\n"); 702fe6060f1SDimitry Andric return false; 703fe6060f1SDimitry Andric } 704fe6060f1SDimitry Andric 705fe6060f1SDimitry Andric bool M68kDAGToDAGISel::SelectARIPD(SDNode *Parent, SDValue N, SDValue &Base) { 706fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "Selecting AddrType::ARIPD: "); 707fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "NOT IMPLEMENTED\n"); 708fe6060f1SDimitry Andric return false; 709fe6060f1SDimitry Andric } 710fe6060f1SDimitry Andric 711fe6060f1SDimitry Andric bool M68kDAGToDAGISel::SelectARID(SDNode *Parent, SDValue N, SDValue &Disp, 712fe6060f1SDimitry Andric SDValue &Base) { 713fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "Selecting AddrType::ARID: "); 714fe6060f1SDimitry Andric M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARID); 715fe6060f1SDimitry Andric 716fe6060f1SDimitry Andric if (!matchAddress(N, AM)) 717fe6060f1SDimitry Andric return false; 718fe6060f1SDimitry Andric 719fe6060f1SDimitry Andric if (AM.isPCRelative()) { 720fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n"); 721fe6060f1SDimitry Andric return false; 722fe6060f1SDimitry Andric } 723fe6060f1SDimitry Andric 724fe6060f1SDimitry Andric // If this is a frame index, grab it 725fe6060f1SDimitry Andric if (getFrameIndexAddress(AM, SDLoc(N), Disp, Base)) { 726fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "SUCCESS matched FI\n"); 727fe6060f1SDimitry Andric return true; 728fe6060f1SDimitry Andric } 729fe6060f1SDimitry Andric 730fe6060f1SDimitry Andric if (AM.hasIndexReg()) { 731fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n"); 732fe6060f1SDimitry Andric return false; 733fe6060f1SDimitry Andric } 734fe6060f1SDimitry Andric 735fe6060f1SDimitry Andric if (!AM.hasBaseReg()) { 736fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "REJECT: No Base reg\n"); 737fe6060f1SDimitry Andric return false; 738fe6060f1SDimitry Andric } 739fe6060f1SDimitry Andric 74006c3fb27SDimitry Andric Base = AM.BaseReg; 74106c3fb27SDimitry Andric 742fe6060f1SDimitry Andric if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) { 743fe6060f1SDimitry Andric assert(!AM.Disp && "Should not be any displacement"); 744fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n"); 745fe6060f1SDimitry Andric return true; 746fe6060f1SDimitry Andric } 747fe6060f1SDimitry Andric 748fe6060f1SDimitry Andric // Give a chance to AddrType::ARI 749fe6060f1SDimitry Andric if (AM.Disp == 0) { 750fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "REJECT: No displacement\n"); 751fe6060f1SDimitry Andric return false; 752fe6060f1SDimitry Andric } 753fe6060f1SDimitry Andric 754fe6060f1SDimitry Andric Disp = getI16Imm(AM.Disp, SDLoc(N)); 755fe6060f1SDimitry Andric 756fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "SUCCESS\n"); 757fe6060f1SDimitry Andric return true; 758fe6060f1SDimitry Andric } 759fe6060f1SDimitry Andric 760fe6060f1SDimitry Andric static bool isAddressBase(const SDValue &N) { 761fe6060f1SDimitry Andric switch (N.getOpcode()) { 762fe6060f1SDimitry Andric case ISD::ADD: 763fe6060f1SDimitry Andric case ISD::ADDC: 764fe6060f1SDimitry Andric return llvm::any_of(N.getNode()->ops(), 765fe6060f1SDimitry Andric [](const SDUse &U) { return isAddressBase(U.get()); }); 766fe6060f1SDimitry Andric case M68kISD::Wrapper: 767fe6060f1SDimitry Andric case M68kISD::WrapperPC: 768fe6060f1SDimitry Andric case M68kISD::GLOBAL_BASE_REG: 769fe6060f1SDimitry Andric return true; 770fe6060f1SDimitry Andric default: 771fe6060f1SDimitry Andric return false; 772fe6060f1SDimitry Andric } 773fe6060f1SDimitry Andric } 774fe6060f1SDimitry Andric 775fe6060f1SDimitry Andric bool M68kDAGToDAGISel::SelectARII(SDNode *Parent, SDValue N, SDValue &Disp, 776fe6060f1SDimitry Andric SDValue &Base, SDValue &Index) { 777fe6060f1SDimitry Andric M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARII); 778fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "Selecting AddrType::ARII: "); 779fe6060f1SDimitry Andric 780fe6060f1SDimitry Andric if (!matchAddress(N, AM)) 781fe6060f1SDimitry Andric return false; 782fe6060f1SDimitry Andric 783fe6060f1SDimitry Andric if (AM.isPCRelative()) { 784fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "REJECT: PC relative\n"); 785fe6060f1SDimitry Andric return false; 786fe6060f1SDimitry Andric } 787fe6060f1SDimitry Andric 788fe6060f1SDimitry Andric if (!AM.hasIndexReg()) { 789fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "REJECT: No Index\n"); 790fe6060f1SDimitry Andric return false; 791fe6060f1SDimitry Andric } 792fe6060f1SDimitry Andric 793fe6060f1SDimitry Andric if (!AM.hasBaseReg()) { 794fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "REJECT: No Base\n"); 795fe6060f1SDimitry Andric return false; 796fe6060f1SDimitry Andric } 797fe6060f1SDimitry Andric 798fe6060f1SDimitry Andric if (!isAddressBase(AM.BaseReg) && isAddressBase(AM.IndexReg)) { 799fe6060f1SDimitry Andric Base = AM.IndexReg; 800fe6060f1SDimitry Andric Index = AM.BaseReg; 801fe6060f1SDimitry Andric } else { 802fe6060f1SDimitry Andric Base = AM.BaseReg; 803fe6060f1SDimitry Andric Index = AM.IndexReg; 804fe6060f1SDimitry Andric } 805fe6060f1SDimitry Andric 806fe6060f1SDimitry Andric if (AM.hasSymbolicDisplacement()) { 807fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "REJECT, Cannot match symbolic displacement\n"); 808fe6060f1SDimitry Andric return false; 809fe6060f1SDimitry Andric } 810fe6060f1SDimitry Andric 811fe6060f1SDimitry Andric // The idea here is that we want to use AddrType::ARII without displacement 812fe6060f1SDimitry Andric // only if necessary like memory operations, otherwise this must be lowered 813fe6060f1SDimitry Andric // into addition 814fe6060f1SDimitry Andric if (AM.Disp == 0 && (!Parent || (Parent->getOpcode() != ISD::LOAD && 815fe6060f1SDimitry Andric Parent->getOpcode() != ISD::STORE))) { 816fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "REJECT: Displacement is Zero\n"); 817fe6060f1SDimitry Andric return false; 818fe6060f1SDimitry Andric } 819fe6060f1SDimitry Andric 820fe6060f1SDimitry Andric Disp = getI8Imm(AM.Disp, SDLoc(N)); 821fe6060f1SDimitry Andric 822fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "SUCCESS\n"); 823fe6060f1SDimitry Andric return true; 824fe6060f1SDimitry Andric } 825fe6060f1SDimitry Andric 826fe6060f1SDimitry Andric bool M68kDAGToDAGISel::SelectAL(SDNode *Parent, SDValue N, SDValue &Sym) { 827fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "Selecting AddrType::AL: "); 828fe6060f1SDimitry Andric M68kISelAddressMode AM(M68kISelAddressMode::AddrType::AL); 829fe6060f1SDimitry Andric 830fe6060f1SDimitry Andric if (!matchAddress(N, AM)) { 831fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "REJECT: Match failed\n"); 832fe6060f1SDimitry Andric return false; 833fe6060f1SDimitry Andric } 834fe6060f1SDimitry Andric 835fe6060f1SDimitry Andric if (AM.isPCRelative()) { 836fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n"); 837fe6060f1SDimitry Andric return false; 838fe6060f1SDimitry Andric } 839fe6060f1SDimitry Andric 840fe6060f1SDimitry Andric if (AM.hasBase()) { 841fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "REJECT: Cannot match Base\n"); 842fe6060f1SDimitry Andric return false; 843fe6060f1SDimitry Andric } 844fe6060f1SDimitry Andric 845fe6060f1SDimitry Andric if (AM.hasIndexReg()) { 846fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n"); 847fe6060f1SDimitry Andric return false; 848fe6060f1SDimitry Andric } 849fe6060f1SDimitry Andric 850fe6060f1SDimitry Andric if (getSymbolicDisplacement(AM, SDLoc(N), Sym)) { 851fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "SUCCESS: Matched symbol\n"); 852fe6060f1SDimitry Andric return true; 853fe6060f1SDimitry Andric } 854fe6060f1SDimitry Andric 855fe6060f1SDimitry Andric if (AM.Disp) { 856fe6060f1SDimitry Andric Sym = getI32Imm(AM.Disp, SDLoc(N)); 857fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "SUCCESS\n"); 858fe6060f1SDimitry Andric return true; 859fe6060f1SDimitry Andric } 860fe6060f1SDimitry Andric 861fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "REJECT: Not Symbol or Disp\n"); 862fe6060f1SDimitry Andric return false; 863fe6060f1SDimitry Andric ; 864fe6060f1SDimitry Andric } 865fe6060f1SDimitry Andric 866fe6060f1SDimitry Andric bool M68kDAGToDAGISel::SelectPCD(SDNode *Parent, SDValue N, SDValue &Disp) { 867fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "Selecting AddrType::PCD: "); 868fe6060f1SDimitry Andric M68kISelAddressMode AM(M68kISelAddressMode::AddrType::PCD); 869fe6060f1SDimitry Andric 870fe6060f1SDimitry Andric if (!matchAddress(N, AM)) 871fe6060f1SDimitry Andric return false; 872fe6060f1SDimitry Andric 873fe6060f1SDimitry Andric if (!AM.isPCRelative()) { 874fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "REJECT: Not PC relative\n"); 875fe6060f1SDimitry Andric return false; 876fe6060f1SDimitry Andric } 877fe6060f1SDimitry Andric 878fe6060f1SDimitry Andric if (AM.hasIndexReg()) { 879fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n"); 880fe6060f1SDimitry Andric return false; 881fe6060f1SDimitry Andric } 882fe6060f1SDimitry Andric 883fe6060f1SDimitry Andric if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) { 884fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n"); 885fe6060f1SDimitry Andric return true; 886fe6060f1SDimitry Andric } 887fe6060f1SDimitry Andric 888fe6060f1SDimitry Andric Disp = getI16Imm(AM.Disp, SDLoc(N)); 889fe6060f1SDimitry Andric 890fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "SUCCESS\n"); 891fe6060f1SDimitry Andric return true; 892fe6060f1SDimitry Andric } 893fe6060f1SDimitry Andric 894fe6060f1SDimitry Andric bool M68kDAGToDAGISel::SelectPCI(SDNode *Parent, SDValue N, SDValue &Disp, 895fe6060f1SDimitry Andric SDValue &Index) { 896fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "Selecting AddrType::PCI: "); 897fe6060f1SDimitry Andric M68kISelAddressMode AM(M68kISelAddressMode::AddrType::PCI); 898fe6060f1SDimitry Andric 899fe6060f1SDimitry Andric if (!matchAddress(N, AM)) 900fe6060f1SDimitry Andric return false; 901fe6060f1SDimitry Andric 902fe6060f1SDimitry Andric if (!AM.isPCRelative()) { 903fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "REJECT: Not PC relative\n"); 904fe6060f1SDimitry Andric return false; 905fe6060f1SDimitry Andric } 906fe6060f1SDimitry Andric 907fe6060f1SDimitry Andric if (!AM.hasIndexReg()) { 908fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "REJECT: No Index\n"); 909fe6060f1SDimitry Andric return false; 910fe6060f1SDimitry Andric } 911fe6060f1SDimitry Andric 912fe6060f1SDimitry Andric Index = AM.IndexReg; 913fe6060f1SDimitry Andric 914fe6060f1SDimitry Andric if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) { 915fe6060f1SDimitry Andric assert(!AM.Disp && "Should not be any displacement"); 916fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n"); 917fe6060f1SDimitry Andric return true; 918fe6060f1SDimitry Andric } 919fe6060f1SDimitry Andric 920fe6060f1SDimitry Andric Disp = getI8Imm(AM.Disp, SDLoc(N)); 921fe6060f1SDimitry Andric 922fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "SUCCESS\n"); 923fe6060f1SDimitry Andric return true; 924fe6060f1SDimitry Andric } 925fe6060f1SDimitry Andric 926fe6060f1SDimitry Andric bool M68kDAGToDAGISel::SelectARI(SDNode *Parent, SDValue N, SDValue &Base) { 927fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "Selecting AddrType::ARI: "); 928fe6060f1SDimitry Andric M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARI); 929fe6060f1SDimitry Andric 930fe6060f1SDimitry Andric if (!matchAddress(N, AM)) { 931fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "REJECT: Match failed\n"); 932fe6060f1SDimitry Andric return false; 933fe6060f1SDimitry Andric } 934fe6060f1SDimitry Andric 935fe6060f1SDimitry Andric if (AM.isPCRelative()) { 936fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n"); 937fe6060f1SDimitry Andric return false; 938fe6060f1SDimitry Andric } 939fe6060f1SDimitry Andric 940fe6060f1SDimitry Andric // AddrType::ARI does not use these 941fe6060f1SDimitry Andric if (AM.hasIndexReg() || AM.Disp != 0) { 942fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index or Disp\n"); 943fe6060f1SDimitry Andric return false; 944fe6060f1SDimitry Andric } 945fe6060f1SDimitry Andric 946fe6060f1SDimitry Andric // Must be matched by AddrType::AL 947fe6060f1SDimitry Andric if (AM.hasSymbolicDisplacement()) { 948fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "REJECT: Cannot match Symbolic Disp\n"); 949fe6060f1SDimitry Andric return false; 950fe6060f1SDimitry Andric } 951fe6060f1SDimitry Andric 952fe6060f1SDimitry Andric if (AM.hasBaseReg()) { 953fe6060f1SDimitry Andric Base = AM.BaseReg; 954fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "SUCCESS\n"); 955fe6060f1SDimitry Andric return true; 956fe6060f1SDimitry Andric } 957fe6060f1SDimitry Andric 958fe6060f1SDimitry Andric return false; 959fe6060f1SDimitry Andric } 96006c3fb27SDimitry Andric 96106c3fb27SDimitry Andric bool M68kDAGToDAGISel::SelectInlineAsmMemoryOperand( 9625f757f3fSDimitry Andric const SDValue &Op, InlineAsm::ConstraintCode ConstraintID, 9635f757f3fSDimitry Andric std::vector<SDValue> &OutOps) { 96406c3fb27SDimitry Andric // In order to tell AsmPrinter the exact addressing mode we select here, which 96506c3fb27SDimitry Andric // might comprise of multiple SDValues (hence MachineOperands), a 32-bit 96606c3fb27SDimitry Andric // immediate value is prepended to the list of selected SDValues to indicate 96706c3fb27SDimitry Andric // the addressing mode kind. 96806c3fb27SDimitry Andric using AMK = M68k::MemAddrModeKind; 96906c3fb27SDimitry Andric auto addKind = [this](SDValue &Opnd, AMK Kind) -> bool { 97006c3fb27SDimitry Andric Opnd = CurDAG->getTargetConstant(unsigned(Kind), SDLoc(), MVT::i32); 97106c3fb27SDimitry Andric return true; 97206c3fb27SDimitry Andric }; 97306c3fb27SDimitry Andric 97406c3fb27SDimitry Andric switch (ConstraintID) { 97506c3fb27SDimitry Andric // Generic memory operand. 9765f757f3fSDimitry Andric case InlineAsm::ConstraintCode::m: { 97706c3fb27SDimitry Andric // Try every supported (memory) addressing modes. 97806c3fb27SDimitry Andric SDValue Operands[4]; 97906c3fb27SDimitry Andric 98006c3fb27SDimitry Andric // TODO: The ordering of the following SelectXXX is relatively...arbitrary, 98106c3fb27SDimitry Andric // right now we simply sort them by descending complexity. Maybe we should 98206c3fb27SDimitry Andric // adjust this by code model and/or relocation mode in the future. 98306c3fb27SDimitry Andric if (SelectARII(nullptr, Op, Operands[1], Operands[2], Operands[3]) && 98406c3fb27SDimitry Andric addKind(Operands[0], AMK::f)) { 98506c3fb27SDimitry Andric OutOps.insert(OutOps.end(), &Operands[0], Operands + 4); 98606c3fb27SDimitry Andric return false; 98706c3fb27SDimitry Andric } 98806c3fb27SDimitry Andric 98906c3fb27SDimitry Andric if ((SelectPCI(nullptr, Op, Operands[1], Operands[2]) && 99006c3fb27SDimitry Andric addKind(Operands[0], AMK::k)) || 99106c3fb27SDimitry Andric (SelectARID(nullptr, Op, Operands[1], Operands[2]) && 99206c3fb27SDimitry Andric addKind(Operands[0], AMK::p))) { 99306c3fb27SDimitry Andric OutOps.insert(OutOps.end(), &Operands[0], Operands + 3); 99406c3fb27SDimitry Andric return false; 99506c3fb27SDimitry Andric } 99606c3fb27SDimitry Andric 99706c3fb27SDimitry Andric if ((SelectPCD(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::q)) || 99806c3fb27SDimitry Andric (SelectARI(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::j)) || 99906c3fb27SDimitry Andric (SelectAL(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::b))) { 100006c3fb27SDimitry Andric OutOps.insert(OutOps.end(), {Operands[0], Operands[1]}); 100106c3fb27SDimitry Andric return false; 100206c3fb27SDimitry Andric } 100306c3fb27SDimitry Andric 100406c3fb27SDimitry Andric return true; 100506c3fb27SDimitry Andric } 100606c3fb27SDimitry Andric // 'Q': Address register indirect addressing. 10075f757f3fSDimitry Andric case InlineAsm::ConstraintCode::Q: { 100806c3fb27SDimitry Andric SDValue AMKind, Base; 100906c3fb27SDimitry Andric // 'j' addressing mode. 101006c3fb27SDimitry Andric // TODO: Add support for 'o' and 'e' after their 101106c3fb27SDimitry Andric // select functions are implemented. 101206c3fb27SDimitry Andric if (SelectARI(nullptr, Op, Base) && addKind(AMKind, AMK::j)) { 101306c3fb27SDimitry Andric OutOps.insert(OutOps.end(), {AMKind, Base}); 101406c3fb27SDimitry Andric return false; 101506c3fb27SDimitry Andric } 101606c3fb27SDimitry Andric return true; 101706c3fb27SDimitry Andric } 101806c3fb27SDimitry Andric // 'U': Address register indirect w/ constant offset addressing. 10195f757f3fSDimitry Andric case InlineAsm::ConstraintCode::Um: { 102006c3fb27SDimitry Andric SDValue AMKind, Base, Offset; 102106c3fb27SDimitry Andric // 'p' addressing mode. 102206c3fb27SDimitry Andric if (SelectARID(nullptr, Op, Offset, Base) && addKind(AMKind, AMK::p)) { 102306c3fb27SDimitry Andric OutOps.insert(OutOps.end(), {AMKind, Offset, Base}); 102406c3fb27SDimitry Andric return false; 102506c3fb27SDimitry Andric } 102606c3fb27SDimitry Andric return true; 102706c3fb27SDimitry Andric } 102806c3fb27SDimitry Andric default: 102906c3fb27SDimitry Andric return true; 103006c3fb27SDimitry Andric } 103106c3fb27SDimitry Andric } 1032