1061 lines · cpp
1//===-- M68kISelDAGToDAG.cpp - M68k Dag to Dag Inst Selector ----*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// This file defines an instruction selector for the M68K target.11///12//===----------------------------------------------------------------------===//13 14#include "M68k.h"15 16#include "M68kMachineFunction.h"17#include "M68kRegisterInfo.h"18#include "M68kSelectionDAGInfo.h"19#include "M68kTargetMachine.h"20#include "llvm/CodeGen/MachineConstantPool.h"21#include "llvm/CodeGen/MachineFrameInfo.h"22#include "llvm/CodeGen/MachineFunction.h"23#include "llvm/CodeGen/MachineInstrBuilder.h"24#include "llvm/CodeGen/MachineRegisterInfo.h"25#include "llvm/CodeGen/SelectionDAGISel.h"26#include "llvm/CodeGen/SelectionDAGNodes.h"27#include "llvm/IR/CFG.h"28#include "llvm/IR/GlobalValue.h"29#include "llvm/IR/Instructions.h"30#include "llvm/IR/Intrinsics.h"31#include "llvm/IR/Type.h"32#include "llvm/Support/Alignment.h"33#include "llvm/Support/Debug.h"34#include "llvm/Support/ErrorHandling.h"35#include "llvm/Support/MathExtras.h"36#include "llvm/Support/raw_ostream.h"37#include "llvm/Target/TargetMachine.h"38 39using namespace llvm;40 41#define DEBUG_TYPE "m68k-isel"42#define PASS_NAME "M68k DAG->DAG Pattern Instruction Selection"43 44namespace {45 46// For reference, the full order of operands for memory references is:47// (Operand), Displacement, Base, Index, Scale48struct M68kISelAddressMode {49 enum class AddrType {50 ARI, // Address Register Indirect51 ARIPI, // Address Register Indirect with Postincrement52 ARIPD, // Address Register Indirect with Postdecrement53 ARID, // Address Register Indirect with Displacement54 ARII, // Address Register Indirect with Index55 PCD, // Program Counter Indirect with Displacement56 PCI, // Program Counter Indirect with Index57 AL, // Absolute58 };59 AddrType AM;60 61 enum class Base { RegBase, FrameIndexBase };62 Base BaseType;63 64 int64_t Disp;65 66 // This is really a union, discriminated by BaseType!67 SDValue BaseReg;68 int BaseFrameIndex;69 70 SDValue IndexReg;71 unsigned Scale;72 73 const GlobalValue *GV;74 const Constant *CP;75 const BlockAddress *BlockAddr;76 const char *ES;77 MCSymbol *MCSym;78 int JT;79 Align Alignment; // CP alignment.80 81 unsigned char SymbolFlags; // M68kII::MO_*82 83 M68kISelAddressMode(AddrType AT)84 : AM(AT), BaseType(Base::RegBase), Disp(0), BaseFrameIndex(0), IndexReg(),85 Scale(1), GV(nullptr), CP(nullptr), BlockAddr(nullptr), ES(nullptr),86 MCSym(nullptr), JT(-1), Alignment(), SymbolFlags(M68kII::MO_NO_FLAG) {}87 88 bool hasSymbolicDisplacement() const {89 return GV != nullptr || CP != nullptr || ES != nullptr ||90 MCSym != nullptr || JT != -1 || BlockAddr != nullptr;91 }92 93 bool hasBase() const {94 return BaseType == Base::FrameIndexBase || BaseReg.getNode() != nullptr;95 }96 97 bool hasFrameIndex() const { return BaseType == Base::FrameIndexBase; }98 99 bool hasBaseReg() const {100 return BaseType == Base::RegBase && BaseReg.getNode() != nullptr;101 }102 103 bool hasIndexReg() const {104 return BaseType == Base::RegBase && IndexReg.getNode() != nullptr;105 }106 107 /// True if address mode type supports displacement108 bool isDispAddrType() const {109 return AM == AddrType::ARII || AM == AddrType::PCI ||110 AM == AddrType::ARID || AM == AddrType::PCD || AM == AddrType::AL;111 }112 113 unsigned getDispSize() const {114 switch (AM) {115 default:116 return 0;117 case AddrType::ARII:118 case AddrType::PCI:119 return 8;120 // These two in the next chip generations can hold upto 32 bit121 case AddrType::ARID:122 case AddrType::PCD:123 return 16;124 case AddrType::AL:125 return 32;126 }127 }128 129 bool hasDisp() const { return getDispSize() != 0; }130 bool isDisp8() const { return getDispSize() == 8; }131 bool isDisp16() const { return getDispSize() == 16; }132 bool isDisp32() const { return getDispSize() == 32; }133 134 /// Return true if this addressing mode is already PC-relative.135 bool isPCRelative() const {136 if (BaseType != Base::RegBase)137 return false;138 if (auto *RegNode = dyn_cast_or_null<RegisterSDNode>(BaseReg.getNode()))139 return RegNode->getReg() == M68k::PC;140 return false;141 }142 143 void setBaseReg(SDValue Reg) {144 BaseType = Base::RegBase;145 BaseReg = Reg;146 }147 148 void setIndexReg(SDValue Reg) { IndexReg = Reg; }149 150#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)151 void dump() {152 dbgs() << "M68kISelAddressMode " << this;153 dbgs() << "\nDisp: " << Disp;154 dbgs() << ", BaseReg: ";155 if (BaseReg.getNode())156 BaseReg.getNode()->dump();157 else158 dbgs() << "null";159 dbgs() << ", BaseFI: " << BaseFrameIndex;160 dbgs() << ", IndexReg: ";161 if (IndexReg.getNode()) {162 IndexReg.getNode()->dump();163 } else {164 dbgs() << "null";165 dbgs() << ", Scale: " << Scale;166 }167 dbgs() << '\n';168 }169#endif170};171} // end anonymous namespace172 173namespace {174 175class M68kDAGToDAGISel : public SelectionDAGISel {176public:177 M68kDAGToDAGISel() = delete;178 179 explicit M68kDAGToDAGISel(M68kTargetMachine &TM)180 : SelectionDAGISel(TM), Subtarget(nullptr) {}181 182 bool runOnMachineFunction(MachineFunction &MF) override;183 bool IsProfitableToFold(SDValue N, SDNode *U, SDNode *Root) const override;184 185private:186 /// Keep a pointer to the M68kSubtarget around so that we can187 /// make the right decision when generating code for different targets.188 const M68kSubtarget *Subtarget;189 190// Include the pieces autogenerated from the target description.191#include "M68kGenDAGISel.inc"192 193 /// getTargetMachine - Return a reference to the TargetMachine, casted194 /// to the target-specific type.195 const M68kTargetMachine &getTargetMachine() {196 return static_cast<const M68kTargetMachine &>(TM);197 }198 199 void Select(SDNode *N) override;200 201 // Insert instructions to initialize the global base register in the202 // first MBB of the function.203 // HMM... do i need this?204 void initGlobalBaseReg(MachineFunction &MF);205 206 bool foldOffsetIntoAddress(uint64_t Offset, M68kISelAddressMode &AM);207 208 bool matchLoadInAddress(LoadSDNode *N, M68kISelAddressMode &AM);209 bool matchAddress(SDValue N, M68kISelAddressMode &AM);210 bool matchAddressBase(SDValue N, M68kISelAddressMode &AM);211 bool matchAddressRecursively(SDValue N, M68kISelAddressMode &AM,212 unsigned Depth);213 bool matchADD(SDValue &N, M68kISelAddressMode &AM, unsigned Depth);214 bool matchWrapper(SDValue N, M68kISelAddressMode &AM);215 216 std::pair<bool, SDNode *> selectNode(SDNode *Node);217 218 bool SelectARI(SDNode *Parent, SDValue N, SDValue &Base);219 bool SelectARIPI(SDNode *Parent, SDValue N, SDValue &Base);220 bool SelectARIPD(SDNode *Parent, SDValue N, SDValue &Base);221 bool SelectARID(SDNode *Parent, SDValue N, SDValue &Imm, SDValue &Base);222 bool SelectARII(SDNode *Parent, SDValue N, SDValue &Imm, SDValue &Base,223 SDValue &Index);224 bool SelectAL(SDNode *Parent, SDValue N, SDValue &Sym);225 bool SelectPCD(SDNode *Parent, SDValue N, SDValue &Imm);226 bool SelectPCI(SDNode *Parent, SDValue N, SDValue &Imm, SDValue &Index);227 228 bool SelectInlineAsmMemoryOperand(const SDValue &Op,229 InlineAsm::ConstraintCode ConstraintID,230 std::vector<SDValue> &OutOps) override;231 232 // If Address Mode represents Frame Index store FI in Disp and233 // Displacement bit size in Base. These values are read symmetrically by234 // M68kRegisterInfo::eliminateFrameIndex method235 inline bool getFrameIndexAddress(M68kISelAddressMode &AM, const SDLoc &DL,236 SDValue &Disp, SDValue &Base) {237 if (AM.BaseType == M68kISelAddressMode::Base::FrameIndexBase) {238 Disp = getI32Imm(AM.Disp, DL);239 Base = CurDAG->getTargetFrameIndex(240 AM.BaseFrameIndex, TLI->getPointerTy(CurDAG->getDataLayout()));241 return true;242 }243 244 return false;245 }246 247 // Gets a symbol plus optional displacement248 inline bool getSymbolicDisplacement(M68kISelAddressMode &AM, const SDLoc &DL,249 SDValue &Sym) {250 if (AM.GV) {251 Sym = CurDAG->getTargetGlobalAddress(AM.GV, SDLoc(), MVT::i32, AM.Disp,252 AM.SymbolFlags);253 return true;254 }255 256 if (AM.CP) {257 Sym = CurDAG->getTargetConstantPool(AM.CP, MVT::i32, AM.Alignment,258 AM.Disp, AM.SymbolFlags);259 return true;260 }261 262 if (AM.ES) {263 assert(!AM.Disp && "Non-zero displacement is ignored with ES.");264 Sym = CurDAG->getTargetExternalSymbol(AM.ES, MVT::i32, AM.SymbolFlags);265 return true;266 }267 268 if (AM.MCSym) {269 assert(!AM.Disp && "Non-zero displacement is ignored with MCSym.");270 assert(AM.SymbolFlags == 0 && "oo");271 Sym = CurDAG->getMCSymbol(AM.MCSym, MVT::i32);272 return true;273 }274 275 if (AM.JT != -1) {276 assert(!AM.Disp && "Non-zero displacement is ignored with JT.");277 Sym = CurDAG->getTargetJumpTable(AM.JT, MVT::i32, AM.SymbolFlags);278 return true;279 }280 281 if (AM.BlockAddr) {282 Sym = CurDAG->getTargetBlockAddress(AM.BlockAddr, MVT::i32, AM.Disp,283 AM.SymbolFlags);284 return true;285 }286 287 return false;288 }289 290 /// Return a target constant with the specified value of type i8.291 inline SDValue getI8Imm(int64_t Imm, const SDLoc &DL) {292 return CurDAG->getSignedTargetConstant(Imm, DL, MVT::i8);293 }294 295 /// Return a target constant with the specified value of type i8.296 inline SDValue getI16Imm(int64_t Imm, const SDLoc &DL) {297 return CurDAG->getSignedTargetConstant(Imm, DL, MVT::i16);298 }299 300 /// Return a target constant with the specified value, of type i32.301 inline SDValue getI32Imm(int64_t Imm, const SDLoc &DL) {302 return CurDAG->getSignedTargetConstant(Imm, DL, MVT::i32);303 }304 305 /// Return a reference to the TargetInstrInfo, casted to the target-specific306 /// type.307 const M68kInstrInfo *getInstrInfo() const {308 return Subtarget->getInstrInfo();309 }310 311 /// Return an SDNode that returns the value of the global base register.312 /// Output instructions required to initialize the global base register,313 /// if necessary.314 SDNode *getGlobalBaseReg();315};316 317class M68kDAGToDAGISelLegacy : public SelectionDAGISelLegacy {318public:319 static char ID;320 explicit M68kDAGToDAGISelLegacy(M68kTargetMachine &TM)321 : SelectionDAGISelLegacy(ID, std::make_unique<M68kDAGToDAGISel>(TM)) {}322};323 324char M68kDAGToDAGISelLegacy::ID;325 326} // namespace327 328INITIALIZE_PASS(M68kDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)329 330bool M68kDAGToDAGISel::IsProfitableToFold(SDValue N, SDNode *U,331 SDNode *Root) const {332 if (OptLevel == CodeGenOptLevel::None)333 return false;334 335 if (U == Root) {336 switch (U->getOpcode()) {337 default:338 return true;339 case M68kISD::SUB:340 case ISD::SUB:341 // Prefer NEG instruction when zero subtracts a value.342 // e.g.343 // move.l #0, %d0344 // sub.l (4,%sp), %d0345 // vs.346 // move.l (4,%sp), %d0347 // neg.l %d0348 if (llvm::isNullConstant(U->getOperand(0)))349 return false;350 break;351 }352 }353 354 return true;355}356 357bool M68kDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {358 Subtarget = &MF.getSubtarget<M68kSubtarget>();359 return SelectionDAGISel::runOnMachineFunction(MF);360}361 362/// This pass converts a legalized DAG into a M68k-specific DAG,363/// ready for instruction scheduling.364FunctionPass *llvm::createM68kISelDag(M68kTargetMachine &TM) {365 return new M68kDAGToDAGISelLegacy(TM);366}367 368static bool doesDispFitFI(M68kISelAddressMode &AM) {369 if (!AM.isDispAddrType())370 return false;371 // -1 to make sure that resolved FI will fit into Disp field372 return isIntN(AM.getDispSize() - 1, AM.Disp);373}374 375static bool doesDispFit(M68kISelAddressMode &AM, int64_t Val) {376 if (!AM.isDispAddrType())377 return false;378 return isIntN(AM.getDispSize(), Val);379}380 381/// Return an SDNode that returns the value of the global base register.382/// Output instructions required to initialize the global base register,383/// if necessary.384SDNode *M68kDAGToDAGISel::getGlobalBaseReg() {385 unsigned GlobalBaseReg = getInstrInfo()->getGlobalBaseReg(MF);386 auto &DL = MF->getDataLayout();387 return CurDAG->getRegister(GlobalBaseReg, TLI->getPointerTy(DL)).getNode();388}389 390bool M68kDAGToDAGISel::foldOffsetIntoAddress(uint64_t Offset,391 M68kISelAddressMode &AM) {392 // Cannot combine ExternalSymbol displacements with integer offsets.393 if (Offset != 0 && (AM.ES || AM.MCSym))394 return false;395 396 int64_t Val = AM.Disp + Offset;397 398 if (doesDispFit(AM, Val)) {399 AM.Disp = Val;400 return true;401 }402 403 return false;404}405 406//===----------------------------------------------------------------------===//407// Matchers408//===----------------------------------------------------------------------===//409 410/// Helper for MatchAddress. Add the specified node to the411/// specified addressing mode without any further recursion.412bool M68kDAGToDAGISel::matchAddressBase(SDValue N, M68kISelAddressMode &AM) {413 // Is the base register already occupied?414 if (AM.hasBase()) {415 // If so, check to see if the scale index register is set.416 if (!AM.hasIndexReg()) {417 AM.IndexReg = N;418 AM.Scale = 1;419 return true;420 }421 422 // Otherwise, we cannot select it.423 return false;424 }425 426 // Default, generate it as a register.427 AM.BaseType = M68kISelAddressMode::Base::RegBase;428 AM.BaseReg = N;429 return true;430}431 432/// TODO Add TLS support433bool M68kDAGToDAGISel::matchLoadInAddress(LoadSDNode *N,434 M68kISelAddressMode &AM) {435 return false;436}437 438bool M68kDAGToDAGISel::matchAddressRecursively(SDValue N,439 M68kISelAddressMode &AM,440 unsigned Depth) {441 SDLoc DL(N);442 443 // Limit recursion.444 if (Depth > 5)445 return matchAddressBase(N, AM);446 447 // If this is already a %PC relative address, we can only merge immediates448 // into it. Instead of handling this in every case, we handle it here.449 // PC relative addressing: %PC + 16-bit displacement!450 if (AM.isPCRelative()) {451 // FIXME JumpTable and ExternalSymbol address currently don't like452 // displacements. It isn't very important, but should be fixed for453 // consistency.454 455 if (ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(N))456 if (foldOffsetIntoAddress(Cst->getSExtValue(), AM))457 return true;458 return false;459 }460 461 switch (N.getOpcode()) {462 default:463 break;464 465 case ISD::Constant: {466 uint64_t Val = cast<ConstantSDNode>(N)->getSExtValue();467 if (foldOffsetIntoAddress(Val, AM))468 return true;469 break;470 }471 472 case M68kISD::Wrapper:473 case M68kISD::WrapperPC:474 if (matchWrapper(N, AM))475 return true;476 break;477 478 case ISD::LOAD:479 if (matchLoadInAddress(cast<LoadSDNode>(N), AM))480 return true;481 break;482 483 case ISD::OR:484 // We want to look through a transform in InstCombine and DAGCombiner that485 // turns 'add' into 'or', so we can treat this 'or' exactly like an 'add'.486 // Example: (or (and x, 1), (shl y, 3)) --> (add (and x, 1), (shl y, 3))487 // An 'lea' can then be used to match the shift (multiply) and add:488 // and $1, %esi489 // lea (%rsi, %rdi, 8), %rax490 if (CurDAG->haveNoCommonBitsSet(N.getOperand(0), N.getOperand(1)) &&491 matchADD(N, AM, Depth))492 return true;493 break;494 495 case ISD::ADD:496 if (matchADD(N, AM, Depth))497 return true;498 break;499 500 case ISD::FrameIndex:501 if (AM.isDispAddrType() &&502 AM.BaseType == M68kISelAddressMode::Base::RegBase &&503 AM.BaseReg.getNode() == nullptr && doesDispFitFI(AM)) {504 AM.BaseType = M68kISelAddressMode::Base::FrameIndexBase;505 AM.BaseFrameIndex = cast<FrameIndexSDNode>(N)->getIndex();506 return true;507 }508 break;509 510 case ISD::TargetGlobalTLSAddress: {511 GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(N);512 AM.GV = GA->getGlobal();513 AM.SymbolFlags = GA->getTargetFlags();514 return true;515 }516 }517 518 return matchAddressBase(N, AM);519}520 521/// Add the specified node to the specified addressing mode, returning true if522/// it cannot be done. This just pattern matches for the addressing mode.523bool M68kDAGToDAGISel::matchAddress(SDValue N, M68kISelAddressMode &AM) {524 // TODO: Post-processing: Convert lea(,%reg,2) to lea(%reg,%reg), which has525 // a smaller encoding and avoids a scaled-index.526 // And make sure it is an indexed mode527 528 // TODO: Post-processing: Convert foo to foo(%pc), even in non-PIC mode,529 // because it has a smaller encoding.530 // Make sure this must be done only if PC* modes are currently being matched531 return matchAddressRecursively(N, AM, 0);532}533 534bool M68kDAGToDAGISel::matchADD(SDValue &N, M68kISelAddressMode &AM,535 unsigned Depth) {536 // Add an artificial use to this node so that we can keep track of537 // it if it gets CSE'd with a different node.538 HandleSDNode Handle(N);539 540 M68kISelAddressMode Backup = AM;541 if (matchAddressRecursively(N.getOperand(0), AM, Depth + 1) &&542 matchAddressRecursively(Handle.getValue().getOperand(1), AM, Depth + 1)) {543 return true;544 }545 AM = Backup;546 547 // Try again after commuting the operands.548 if (matchAddressRecursively(Handle.getValue().getOperand(1), AM, Depth + 1) &&549 matchAddressRecursively(Handle.getValue().getOperand(0), AM, Depth + 1)) {550 return true;551 }552 AM = Backup;553 554 // If we couldn't fold both operands into the address at the same time,555 // see if we can just put each operand into a register and fold at least556 // the add.557 if (!AM.hasBase() && !AM.hasIndexReg()) {558 N = Handle.getValue();559 AM.BaseReg = N.getOperand(0);560 AM.IndexReg = N.getOperand(1);561 AM.Scale = 1;562 return true;563 }564 565 N = Handle.getValue();566 return false;567}568 569/// Try to match M68kISD::Wrapper and M68kISD::WrapperPC nodes into an570/// addressing mode. These wrap things that will resolve down into a symbol571/// reference. If no match is possible, this returns true, otherwise it returns572/// false.573bool M68kDAGToDAGISel::matchWrapper(SDValue N, M68kISelAddressMode &AM) {574 // If the addressing mode already has a symbol as the displacement, we can575 // never match another symbol.576 if (AM.hasSymbolicDisplacement())577 return false;578 579 SDValue N0 = N.getOperand(0);580 581 if (N.getOpcode() == M68kISD::WrapperPC) {582 583 // If cannot match here just restore the old version584 M68kISelAddressMode Backup = AM;585 586 if (AM.hasBase()) {587 return false;588 }589 590 if (auto *G = dyn_cast<GlobalAddressSDNode>(N0)) {591 AM.GV = G->getGlobal();592 AM.SymbolFlags = G->getTargetFlags();593 if (!foldOffsetIntoAddress(G->getOffset(), AM)) {594 AM = Backup;595 return false;596 }597 } else if (auto *CP = dyn_cast<ConstantPoolSDNode>(N0)) {598 AM.CP = CP->getConstVal();599 AM.Alignment = CP->getAlign();600 AM.SymbolFlags = CP->getTargetFlags();601 if (!foldOffsetIntoAddress(CP->getOffset(), AM)) {602 AM = Backup;603 return false;604 }605 } else if (auto *S = dyn_cast<ExternalSymbolSDNode>(N0)) {606 AM.ES = S->getSymbol();607 AM.SymbolFlags = S->getTargetFlags();608 } else if (auto *S = dyn_cast<MCSymbolSDNode>(N0)) {609 AM.MCSym = S->getMCSymbol();610 } else if (auto *J = dyn_cast<JumpTableSDNode>(N0)) {611 AM.JT = J->getIndex();612 AM.SymbolFlags = J->getTargetFlags();613 } else if (auto *BA = dyn_cast<BlockAddressSDNode>(N0)) {614 AM.BlockAddr = BA->getBlockAddress();615 AM.SymbolFlags = BA->getTargetFlags();616 if (!foldOffsetIntoAddress(BA->getOffset(), AM)) {617 AM = Backup;618 return false;619 }620 } else621 llvm_unreachable("Unhandled symbol reference node.");622 623 AM.setBaseReg(CurDAG->getRegister(M68k::PC, MVT::i32));624 return true;625 }626 627 // This wrapper requires 32bit disp/imm field for Medium CM628 if (!AM.isDisp32()) {629 return false;630 }631 632 if (N.getOpcode() == M68kISD::Wrapper) {633 if (auto *G = dyn_cast<GlobalAddressSDNode>(N0)) {634 AM.GV = G->getGlobal();635 AM.Disp += G->getOffset();636 AM.SymbolFlags = G->getTargetFlags();637 } else if (auto *CP = dyn_cast<ConstantPoolSDNode>(N0)) {638 AM.CP = CP->getConstVal();639 AM.Alignment = CP->getAlign();640 AM.Disp += CP->getOffset();641 AM.SymbolFlags = CP->getTargetFlags();642 } else if (auto *S = dyn_cast<ExternalSymbolSDNode>(N0)) {643 AM.ES = S->getSymbol();644 AM.SymbolFlags = S->getTargetFlags();645 } else if (auto *S = dyn_cast<MCSymbolSDNode>(N0)) {646 AM.MCSym = S->getMCSymbol();647 } else if (auto *J = dyn_cast<JumpTableSDNode>(N0)) {648 AM.JT = J->getIndex();649 AM.SymbolFlags = J->getTargetFlags();650 } else if (auto *BA = dyn_cast<BlockAddressSDNode>(N0)) {651 AM.BlockAddr = BA->getBlockAddress();652 AM.Disp += BA->getOffset();653 AM.SymbolFlags = BA->getTargetFlags();654 } else655 llvm_unreachable("Unhandled symbol reference node.");656 return true;657 }658 659 return false;660}661 662//===----------------------------------------------------------------------===//663// Selectors664//===----------------------------------------------------------------------===//665 666void M68kDAGToDAGISel::Select(SDNode *Node) {667 unsigned Opcode = Node->getOpcode();668 SDLoc DL(Node);669 670 LLVM_DEBUG(dbgs() << "Selecting: "; Node->dump(CurDAG); dbgs() << '\n');671 672 if (Node->isMachineOpcode()) {673 LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << '\n');674 Node->setNodeId(-1);675 return; // Already selected.676 }677 678 switch (Opcode) {679 default:680 break;681 682 case ISD::GLOBAL_OFFSET_TABLE: {683 SDValue GOT = CurDAG->getTargetExternalSymbol(684 "_GLOBAL_OFFSET_TABLE_", MVT::i32, M68kII::MO_GOTPCREL);685 MachineSDNode *Res =686 CurDAG->getMachineNode(M68k::LEA32q, DL, MVT::i32, GOT);687 ReplaceNode(Node, Res);688 return;689 }690 691 case M68kISD::GLOBAL_BASE_REG:692 ReplaceNode(Node, getGlobalBaseReg());693 return;694 }695 696 SelectCode(Node);697}698 699bool M68kDAGToDAGISel::SelectARIPI(SDNode *Parent, SDValue N, SDValue &Base) {700 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARIPI: ");701 LLVM_DEBUG(dbgs() << "NOT IMPLEMENTED\n");702 return false;703}704 705bool M68kDAGToDAGISel::SelectARIPD(SDNode *Parent, SDValue N, SDValue &Base) {706 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARIPD: ");707 LLVM_DEBUG(dbgs() << "NOT IMPLEMENTED\n");708 return false;709}710 711[[maybe_unused]] static bool allowARIDWithDisp(SDNode *Parent) {712 if (!Parent)713 return false;714 switch (Parent->getOpcode()) {715 case ISD::LOAD:716 case ISD::STORE:717 case ISD::ATOMIC_LOAD:718 case ISD::ATOMIC_STORE:719 return true;720 default:721 return false;722 }723}724 725bool M68kDAGToDAGISel::SelectARID(SDNode *Parent, SDValue N, SDValue &Disp,726 SDValue &Base) {727 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARID: ");728 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARID);729 730 if (!matchAddress(N, AM))731 return false;732 733 if (AM.isPCRelative()) {734 LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");735 return false;736 }737 738 // If this is a frame index, grab it739 if (getFrameIndexAddress(AM, SDLoc(N), Disp, Base)) {740 LLVM_DEBUG(dbgs() << "SUCCESS matched FI\n");741 return true;742 }743 744 if (AM.hasIndexReg()) {745 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");746 return false;747 }748 749 if (!AM.hasBaseReg()) {750 LLVM_DEBUG(dbgs() << "REJECT: No Base reg\n");751 return false;752 }753 754 Base = AM.BaseReg;755 756 if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {757 assert((!AM.Disp || allowARIDWithDisp(Parent)) &&758 "Should not be any displacement");759 LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");760 return true;761 }762 763 // Give a chance to AddrType::ARI764 if (AM.Disp == 0) {765 LLVM_DEBUG(dbgs() << "REJECT: No displacement\n");766 return false;767 }768 769 Disp = getI16Imm(AM.Disp, SDLoc(N));770 771 LLVM_DEBUG(dbgs() << "SUCCESS\n");772 return true;773}774 775static bool isAddressBase(const SDValue &N) {776 switch (N.getOpcode()) {777 case ISD::ADD:778 case ISD::ADDC:779 return llvm::any_of(N.getNode()->ops(),780 [](const SDUse &U) { return isAddressBase(U.get()); });781 case M68kISD::Wrapper:782 case M68kISD::WrapperPC:783 case M68kISD::GLOBAL_BASE_REG:784 return true;785 default:786 return false;787 }788}789 790static bool AllowARIIWithZeroDisp(SDNode *Parent) {791 if (!Parent)792 return false;793 switch (Parent->getOpcode()) {794 case ISD::LOAD:795 case ISD::STORE:796 case ISD::ATOMIC_LOAD:797 case ISD::ATOMIC_STORE:798 case ISD::ATOMIC_CMP_SWAP:799 return true;800 default:801 return false;802 }803}804 805bool M68kDAGToDAGISel::SelectARII(SDNode *Parent, SDValue N, SDValue &Disp,806 SDValue &Base, SDValue &Index) {807 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARII);808 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARII: ");809 810 if (!matchAddress(N, AM))811 return false;812 813 if (AM.isPCRelative()) {814 LLVM_DEBUG(dbgs() << "REJECT: PC relative\n");815 return false;816 }817 818 if (!AM.hasIndexReg()) {819 LLVM_DEBUG(dbgs() << "REJECT: No Index\n");820 return false;821 }822 823 if (!AM.hasBaseReg()) {824 LLVM_DEBUG(dbgs() << "REJECT: No Base\n");825 return false;826 }827 828 if (!isAddressBase(AM.BaseReg) && isAddressBase(AM.IndexReg)) {829 Base = AM.IndexReg;830 Index = AM.BaseReg;831 } else {832 Base = AM.BaseReg;833 Index = AM.IndexReg;834 }835 836 if (AM.hasSymbolicDisplacement()) {837 LLVM_DEBUG(dbgs() << "REJECT, Cannot match symbolic displacement\n");838 return false;839 }840 841 // The idea here is that we want to use AddrType::ARII without displacement842 // only if necessary like memory operations, otherwise this must be lowered843 // into addition844 if (AM.Disp == 0 && !AllowARIIWithZeroDisp(Parent)) {845 LLVM_DEBUG(dbgs() << "REJECT: Displacement is Zero\n");846 return false;847 }848 849 Disp = getI8Imm(AM.Disp, SDLoc(N));850 851 LLVM_DEBUG(dbgs() << "SUCCESS\n");852 return true;853}854 855bool M68kDAGToDAGISel::SelectAL(SDNode *Parent, SDValue N, SDValue &Sym) {856 LLVM_DEBUG(dbgs() << "Selecting AddrType::AL: ");857 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::AL);858 859 if (!matchAddress(N, AM)) {860 LLVM_DEBUG(dbgs() << "REJECT: Match failed\n");861 return false;862 }863 864 if (AM.isPCRelative()) {865 LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");866 return false;867 }868 869 if (AM.hasBase()) {870 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Base\n");871 return false;872 }873 874 if (AM.hasIndexReg()) {875 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");876 return false;877 }878 879 if (getSymbolicDisplacement(AM, SDLoc(N), Sym)) {880 LLVM_DEBUG(dbgs() << "SUCCESS: Matched symbol\n");881 return true;882 }883 884 if (AM.Disp) {885 Sym = getI32Imm(AM.Disp, SDLoc(N));886 LLVM_DEBUG(dbgs() << "SUCCESS\n");887 return true;888 }889 890 LLVM_DEBUG(dbgs() << "REJECT: Not Symbol or Disp\n");891 return false;892 ;893}894 895bool M68kDAGToDAGISel::SelectPCD(SDNode *Parent, SDValue N, SDValue &Disp) {896 LLVM_DEBUG(dbgs() << "Selecting AddrType::PCD: ");897 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::PCD);898 899 if (!matchAddress(N, AM))900 return false;901 902 if (!AM.isPCRelative()) {903 LLVM_DEBUG(dbgs() << "REJECT: Not PC relative\n");904 return false;905 }906 907 if (AM.hasIndexReg()) {908 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");909 return false;910 }911 912 if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {913 LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");914 return true;915 }916 917 Disp = getI16Imm(AM.Disp, SDLoc(N));918 919 LLVM_DEBUG(dbgs() << "SUCCESS\n");920 return true;921}922 923bool M68kDAGToDAGISel::SelectPCI(SDNode *Parent, SDValue N, SDValue &Disp,924 SDValue &Index) {925 LLVM_DEBUG(dbgs() << "Selecting AddrType::PCI: ");926 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::PCI);927 928 if (!matchAddress(N, AM))929 return false;930 931 if (!AM.isPCRelative()) {932 LLVM_DEBUG(dbgs() << "REJECT: Not PC relative\n");933 return false;934 }935 936 if (!AM.hasIndexReg()) {937 LLVM_DEBUG(dbgs() << "REJECT: No Index\n");938 return false;939 }940 941 Index = AM.IndexReg;942 943 if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {944 assert(!AM.Disp && "Should not be any displacement");945 LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");946 return true;947 }948 949 Disp = getI8Imm(AM.Disp, SDLoc(N));950 951 LLVM_DEBUG(dbgs() << "SUCCESS\n");952 return true;953}954 955bool M68kDAGToDAGISel::SelectARI(SDNode *Parent, SDValue N, SDValue &Base) {956 LLVM_DEBUG(dbgs() << "Selecting AddrType::ARI: ");957 M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARI);958 959 if (!matchAddress(N, AM)) {960 LLVM_DEBUG(dbgs() << "REJECT: Match failed\n");961 return false;962 }963 964 if (AM.isPCRelative()) {965 LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");966 return false;967 }968 969 // AddrType::ARI does not use these970 if (AM.hasIndexReg() || AM.Disp != 0) {971 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index or Disp\n");972 return false;973 }974 975 // Must be matched by AddrType::AL976 if (AM.hasSymbolicDisplacement()) {977 LLVM_DEBUG(dbgs() << "REJECT: Cannot match Symbolic Disp\n");978 return false;979 }980 981 if (AM.hasBaseReg()) {982 Base = AM.BaseReg;983 LLVM_DEBUG(dbgs() << "SUCCESS\n");984 return true;985 }986 987 return false;988}989 990bool M68kDAGToDAGISel::SelectInlineAsmMemoryOperand(991 const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,992 std::vector<SDValue> &OutOps) {993 // In order to tell AsmPrinter the exact addressing mode we select here, which994 // might comprise of multiple SDValues (hence MachineOperands), a 32-bit995 // immediate value is prepended to the list of selected SDValues to indicate996 // the addressing mode kind.997 using AMK = M68k::MemAddrModeKind;998 auto addKind = [this](SDValue &Opnd, AMK Kind) -> bool {999 Opnd = CurDAG->getTargetConstant(unsigned(Kind), SDLoc(), MVT::i32);1000 return true;1001 };1002 1003 switch (ConstraintID) {1004 // Generic memory operand.1005 case InlineAsm::ConstraintCode::m: {1006 // Try every supported (memory) addressing modes.1007 SDValue Operands[4];1008 1009 // TODO: The ordering of the following SelectXXX is relatively...arbitrary,1010 // right now we simply sort them by descending complexity. Maybe we should1011 // adjust this by code model and/or relocation mode in the future.1012 if (SelectARII(nullptr, Op, Operands[1], Operands[2], Operands[3]) &&1013 addKind(Operands[0], AMK::f)) {1014 OutOps.insert(OutOps.end(), &Operands[0], Operands + 4);1015 return false;1016 }1017 1018 if ((SelectPCI(nullptr, Op, Operands[1], Operands[2]) &&1019 addKind(Operands[0], AMK::k)) ||1020 (SelectARID(nullptr, Op, Operands[1], Operands[2]) &&1021 addKind(Operands[0], AMK::p))) {1022 OutOps.insert(OutOps.end(), &Operands[0], Operands + 3);1023 return false;1024 }1025 1026 if ((SelectPCD(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::q)) ||1027 (SelectARI(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::j)) ||1028 (SelectAL(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::b))) {1029 OutOps.insert(OutOps.end(), {Operands[0], Operands[1]});1030 return false;1031 }1032 1033 return true;1034 }1035 // 'Q': Address register indirect addressing.1036 case InlineAsm::ConstraintCode::Q: {1037 SDValue AMKind, Base;1038 // 'j' addressing mode.1039 // TODO: Add support for 'o' and 'e' after their1040 // select functions are implemented.1041 if (SelectARI(nullptr, Op, Base) && addKind(AMKind, AMK::j)) {1042 OutOps.insert(OutOps.end(), {AMKind, Base});1043 return false;1044 }1045 return true;1046 }1047 // 'U': Address register indirect w/ constant offset addressing.1048 case InlineAsm::ConstraintCode::Um: {1049 SDValue AMKind, Base, Offset;1050 // 'p' addressing mode.1051 if (SelectARID(nullptr, Op, Offset, Base) && addKind(AMKind, AMK::p)) {1052 OutOps.insert(OutOps.end(), {AMKind, Offset, Base});1053 return false;1054 }1055 return true;1056 }1057 default:1058 return true;1059 }1060}1061