Path: blob/main/contrib/llvm-project/llvm/lib/Target/M68k/M68kISelDAGToDAG.cpp
35267 views
//===-- M68kISelDAGToDAG.cpp - M68k Dag to Dag Inst Selector ----*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7///8/// \file9/// This file defines an instruction selector for the M68K target.10///11//===----------------------------------------------------------------------===//1213#include "M68k.h"1415#include "M68kMachineFunction.h"16#include "M68kRegisterInfo.h"17#include "M68kTargetMachine.h"1819#include "llvm/CodeGen/MachineConstantPool.h"20#include "llvm/CodeGen/MachineFrameInfo.h"21#include "llvm/CodeGen/MachineFunction.h"22#include "llvm/CodeGen/MachineInstrBuilder.h"23#include "llvm/CodeGen/MachineRegisterInfo.h"24#include "llvm/CodeGen/SelectionDAGISel.h"25#include "llvm/CodeGen/SelectionDAGNodes.h"26#include "llvm/IR/CFG.h"27#include "llvm/IR/GlobalValue.h"28#include "llvm/IR/Instructions.h"29#include "llvm/IR/Intrinsics.h"30#include "llvm/IR/Type.h"31#include "llvm/Support/Alignment.h"32#include "llvm/Support/Debug.h"33#include "llvm/Support/ErrorHandling.h"34#include "llvm/Support/MathExtras.h"35#include "llvm/Support/raw_ostream.h"36#include "llvm/Target/TargetMachine.h"3738using namespace llvm;3940#define DEBUG_TYPE "m68k-isel"41#define PASS_NAME "M68k DAG->DAG Pattern Instruction Selection"4243namespace {4445// For reference, the full order of operands for memory references is:46// (Operand), Displacement, Base, Index, Scale47struct M68kISelAddressMode {48enum class AddrType {49ARI, // Address Register Indirect50ARIPI, // Address Register Indirect with Postincrement51ARIPD, // Address Register Indirect with Postdecrement52ARID, // Address Register Indirect with Displacement53ARII, // Address Register Indirect with Index54PCD, // Program Counter Indirect with Displacement55PCI, // Program Counter Indirect with Index56AL, // Absolute57};58AddrType AM;5960enum class Base { RegBase, FrameIndexBase };61Base BaseType;6263int64_t Disp;6465// This is really a union, discriminated by BaseType!66SDValue BaseReg;67int BaseFrameIndex;6869SDValue IndexReg;70unsigned Scale;7172const GlobalValue *GV;73const Constant *CP;74const BlockAddress *BlockAddr;75const char *ES;76MCSymbol *MCSym;77int JT;78Align Alignment; // CP alignment.7980unsigned char SymbolFlags; // M68kII::MO_*8182M68kISelAddressMode(AddrType AT)83: AM(AT), BaseType(Base::RegBase), Disp(0), BaseFrameIndex(0), IndexReg(),84Scale(1), GV(nullptr), CP(nullptr), BlockAddr(nullptr), ES(nullptr),85MCSym(nullptr), JT(-1), Alignment(), SymbolFlags(M68kII::MO_NO_FLAG) {}8687bool hasSymbolicDisplacement() const {88return GV != nullptr || CP != nullptr || ES != nullptr ||89MCSym != nullptr || JT != -1 || BlockAddr != nullptr;90}9192bool hasBase() const {93return BaseType == Base::FrameIndexBase || BaseReg.getNode() != nullptr;94}9596bool hasFrameIndex() const { return BaseType == Base::FrameIndexBase; }9798bool hasBaseReg() const {99return BaseType == Base::RegBase && BaseReg.getNode() != nullptr;100}101102bool hasIndexReg() const {103return BaseType == Base::RegBase && IndexReg.getNode() != nullptr;104}105106/// True if address mode type supports displacement107bool isDispAddrType() const {108return AM == AddrType::ARII || AM == AddrType::PCI ||109AM == AddrType::ARID || AM == AddrType::PCD || AM == AddrType::AL;110}111112unsigned getDispSize() const {113switch (AM) {114default:115return 0;116case AddrType::ARII:117case AddrType::PCI:118return 8;119// These two in the next chip generations can hold upto 32 bit120case AddrType::ARID:121case AddrType::PCD:122return 16;123case AddrType::AL:124return 32;125}126}127128bool hasDisp() const { return getDispSize() != 0; }129bool isDisp8() const { return getDispSize() == 8; }130bool isDisp16() const { return getDispSize() == 16; }131bool isDisp32() const { return getDispSize() == 32; }132133/// Return true if this addressing mode is already PC-relative.134bool isPCRelative() const {135if (BaseType != Base::RegBase)136return false;137if (auto *RegNode = dyn_cast_or_null<RegisterSDNode>(BaseReg.getNode()))138return RegNode->getReg() == M68k::PC;139return false;140}141142void setBaseReg(SDValue Reg) {143BaseType = Base::RegBase;144BaseReg = Reg;145}146147void setIndexReg(SDValue Reg) { IndexReg = Reg; }148149#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)150void dump() {151dbgs() << "M68kISelAddressMode " << this;152dbgs() << "\nDisp: " << Disp;153dbgs() << ", BaseReg: ";154if (BaseReg.getNode())155BaseReg.getNode()->dump();156else157dbgs() << "null";158dbgs() << ", BaseFI: " << BaseFrameIndex;159dbgs() << ", IndexReg: ";160if (IndexReg.getNode()) {161IndexReg.getNode()->dump();162} else {163dbgs() << "null";164dbgs() << ", Scale: " << Scale;165}166dbgs() << '\n';167}168#endif169};170} // end anonymous namespace171172namespace {173174class M68kDAGToDAGISel : public SelectionDAGISel {175public:176M68kDAGToDAGISel() = delete;177178explicit M68kDAGToDAGISel(M68kTargetMachine &TM)179: SelectionDAGISel(TM), Subtarget(nullptr) {}180181bool runOnMachineFunction(MachineFunction &MF) override;182bool IsProfitableToFold(SDValue N, SDNode *U, SDNode *Root) const override;183184private:185/// Keep a pointer to the M68kSubtarget around so that we can186/// make the right decision when generating code for different targets.187const M68kSubtarget *Subtarget;188189// Include the pieces autogenerated from the target description.190#include "M68kGenDAGISel.inc"191192/// getTargetMachine - Return a reference to the TargetMachine, casted193/// to the target-specific type.194const M68kTargetMachine &getTargetMachine() {195return static_cast<const M68kTargetMachine &>(TM);196}197198void Select(SDNode *N) override;199200// Insert instructions to initialize the global base register in the201// first MBB of the function.202// HMM... do i need this?203void initGlobalBaseReg(MachineFunction &MF);204205bool foldOffsetIntoAddress(uint64_t Offset, M68kISelAddressMode &AM);206207bool matchLoadInAddress(LoadSDNode *N, M68kISelAddressMode &AM);208bool matchAddress(SDValue N, M68kISelAddressMode &AM);209bool matchAddressBase(SDValue N, M68kISelAddressMode &AM);210bool matchAddressRecursively(SDValue N, M68kISelAddressMode &AM,211unsigned Depth);212bool matchADD(SDValue &N, M68kISelAddressMode &AM, unsigned Depth);213bool matchWrapper(SDValue N, M68kISelAddressMode &AM);214215std::pair<bool, SDNode *> selectNode(SDNode *Node);216217bool SelectARI(SDNode *Parent, SDValue N, SDValue &Base);218bool SelectARIPI(SDNode *Parent, SDValue N, SDValue &Base);219bool SelectARIPD(SDNode *Parent, SDValue N, SDValue &Base);220bool SelectARID(SDNode *Parent, SDValue N, SDValue &Imm, SDValue &Base);221bool SelectARII(SDNode *Parent, SDValue N, SDValue &Imm, SDValue &Base,222SDValue &Index);223bool SelectAL(SDNode *Parent, SDValue N, SDValue &Sym);224bool SelectPCD(SDNode *Parent, SDValue N, SDValue &Imm);225bool SelectPCI(SDNode *Parent, SDValue N, SDValue &Imm, SDValue &Index);226227bool SelectInlineAsmMemoryOperand(const SDValue &Op,228InlineAsm::ConstraintCode ConstraintID,229std::vector<SDValue> &OutOps) override;230231// If Address Mode represents Frame Index store FI in Disp and232// Displacement bit size in Base. These values are read symmetrically by233// M68kRegisterInfo::eliminateFrameIndex method234inline bool getFrameIndexAddress(M68kISelAddressMode &AM, const SDLoc &DL,235SDValue &Disp, SDValue &Base) {236if (AM.BaseType == M68kISelAddressMode::Base::FrameIndexBase) {237Disp = getI32Imm(AM.Disp, DL);238Base = CurDAG->getTargetFrameIndex(239AM.BaseFrameIndex, TLI->getPointerTy(CurDAG->getDataLayout()));240return true;241}242243return false;244}245246// Gets a symbol plus optional displacement247inline bool getSymbolicDisplacement(M68kISelAddressMode &AM, const SDLoc &DL,248SDValue &Sym) {249if (AM.GV) {250Sym = CurDAG->getTargetGlobalAddress(AM.GV, SDLoc(), MVT::i32, AM.Disp,251AM.SymbolFlags);252return true;253}254255if (AM.CP) {256Sym = CurDAG->getTargetConstantPool(AM.CP, MVT::i32, AM.Alignment,257AM.Disp, AM.SymbolFlags);258return true;259}260261if (AM.ES) {262assert(!AM.Disp && "Non-zero displacement is ignored with ES.");263Sym = CurDAG->getTargetExternalSymbol(AM.ES, MVT::i32, AM.SymbolFlags);264return true;265}266267if (AM.MCSym) {268assert(!AM.Disp && "Non-zero displacement is ignored with MCSym.");269assert(AM.SymbolFlags == 0 && "oo");270Sym = CurDAG->getMCSymbol(AM.MCSym, MVT::i32);271return true;272}273274if (AM.JT != -1) {275assert(!AM.Disp && "Non-zero displacement is ignored with JT.");276Sym = CurDAG->getTargetJumpTable(AM.JT, MVT::i32, AM.SymbolFlags);277return true;278}279280if (AM.BlockAddr) {281Sym = CurDAG->getTargetBlockAddress(AM.BlockAddr, MVT::i32, AM.Disp,282AM.SymbolFlags);283return true;284}285286return false;287}288289/// Return a target constant with the specified value of type i8.290inline SDValue getI8Imm(int64_t Imm, const SDLoc &DL) {291return CurDAG->getTargetConstant(Imm, DL, MVT::i8);292}293294/// Return a target constant with the specified value of type i8.295inline SDValue getI16Imm(int64_t Imm, const SDLoc &DL) {296return CurDAG->getTargetConstant(Imm, DL, MVT::i16);297}298299/// Return a target constant with the specified value, of type i32.300inline SDValue getI32Imm(int64_t Imm, const SDLoc &DL) {301return CurDAG->getTargetConstant(Imm, DL, MVT::i32);302}303304/// Return a reference to the TargetInstrInfo, casted to the target-specific305/// type.306const M68kInstrInfo *getInstrInfo() const {307return Subtarget->getInstrInfo();308}309310/// Return an SDNode that returns the value of the global base register.311/// Output instructions required to initialize the global base register,312/// if necessary.313SDNode *getGlobalBaseReg();314};315316class M68kDAGToDAGISelLegacy : public SelectionDAGISelLegacy {317public:318static char ID;319explicit M68kDAGToDAGISelLegacy(M68kTargetMachine &TM)320: SelectionDAGISelLegacy(ID, std::make_unique<M68kDAGToDAGISel>(TM)) {}321};322323char M68kDAGToDAGISelLegacy::ID;324325} // namespace326327INITIALIZE_PASS(M68kDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)328329bool M68kDAGToDAGISel::IsProfitableToFold(SDValue N, SDNode *U,330SDNode *Root) const {331if (OptLevel == CodeGenOptLevel::None)332return false;333334if (U == Root) {335switch (U->getOpcode()) {336default:337return true;338case M68kISD::SUB:339case ISD::SUB:340// Prefer NEG instruction when zero subtracts a value.341// e.g.342// move.l #0, %d0343// sub.l (4,%sp), %d0344// vs.345// move.l (4,%sp), %d0346// neg.l %d0347if (llvm::isNullConstant(U->getOperand(0)))348return false;349break;350}351}352353return true;354}355356bool M68kDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {357Subtarget = &MF.getSubtarget<M68kSubtarget>();358return SelectionDAGISel::runOnMachineFunction(MF);359}360361/// This pass converts a legalized DAG into a M68k-specific DAG,362/// ready for instruction scheduling.363FunctionPass *llvm::createM68kISelDag(M68kTargetMachine &TM) {364return new M68kDAGToDAGISelLegacy(TM);365}366367static bool doesDispFitFI(M68kISelAddressMode &AM) {368if (!AM.isDispAddrType())369return false;370// -1 to make sure that resolved FI will fit into Disp field371return isIntN(AM.getDispSize() - 1, AM.Disp);372}373374static bool doesDispFit(M68kISelAddressMode &AM, int64_t Val) {375if (!AM.isDispAddrType())376return false;377return isIntN(AM.getDispSize(), Val);378}379380/// Return an SDNode that returns the value of the global base register.381/// Output instructions required to initialize the global base register,382/// if necessary.383SDNode *M68kDAGToDAGISel::getGlobalBaseReg() {384unsigned GlobalBaseReg = getInstrInfo()->getGlobalBaseReg(MF);385auto &DL = MF->getDataLayout();386return CurDAG->getRegister(GlobalBaseReg, TLI->getPointerTy(DL)).getNode();387}388389bool M68kDAGToDAGISel::foldOffsetIntoAddress(uint64_t Offset,390M68kISelAddressMode &AM) {391// Cannot combine ExternalSymbol displacements with integer offsets.392if (Offset != 0 && (AM.ES || AM.MCSym))393return false;394395int64_t Val = AM.Disp + Offset;396397if (doesDispFit(AM, Val)) {398AM.Disp = Val;399return true;400}401402return false;403}404405//===----------------------------------------------------------------------===//406// Matchers407//===----------------------------------------------------------------------===//408409/// Helper for MatchAddress. Add the specified node to the410/// specified addressing mode without any further recursion.411bool M68kDAGToDAGISel::matchAddressBase(SDValue N, M68kISelAddressMode &AM) {412// Is the base register already occupied?413if (AM.hasBase()) {414// If so, check to see if the scale index register is set.415if (!AM.hasIndexReg()) {416AM.IndexReg = N;417AM.Scale = 1;418return true;419}420421// Otherwise, we cannot select it.422return false;423}424425// Default, generate it as a register.426AM.BaseType = M68kISelAddressMode::Base::RegBase;427AM.BaseReg = N;428return true;429}430431/// TODO Add TLS support432bool M68kDAGToDAGISel::matchLoadInAddress(LoadSDNode *N,433M68kISelAddressMode &AM) {434return false;435}436437bool M68kDAGToDAGISel::matchAddressRecursively(SDValue N,438M68kISelAddressMode &AM,439unsigned Depth) {440SDLoc DL(N);441442// Limit recursion.443if (Depth > 5)444return matchAddressBase(N, AM);445446// If this is already a %PC relative address, we can only merge immediates447// into it. Instead of handling this in every case, we handle it here.448// PC relative addressing: %PC + 16-bit displacement!449if (AM.isPCRelative()) {450// FIXME JumpTable and ExternalSymbol address currently don't like451// displacements. It isn't very important, but should be fixed for452// consistency.453454if (ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(N))455if (foldOffsetIntoAddress(Cst->getSExtValue(), AM))456return true;457return false;458}459460switch (N.getOpcode()) {461default:462break;463464case ISD::Constant: {465uint64_t Val = cast<ConstantSDNode>(N)->getSExtValue();466if (foldOffsetIntoAddress(Val, AM))467return true;468break;469}470471case M68kISD::Wrapper:472case M68kISD::WrapperPC:473if (matchWrapper(N, AM))474return true;475break;476477case ISD::LOAD:478if (matchLoadInAddress(cast<LoadSDNode>(N), AM))479return true;480break;481482case ISD::OR:483// We want to look through a transform in InstCombine and DAGCombiner that484// turns 'add' into 'or', so we can treat this 'or' exactly like an 'add'.485// Example: (or (and x, 1), (shl y, 3)) --> (add (and x, 1), (shl y, 3))486// An 'lea' can then be used to match the shift (multiply) and add:487// and $1, %esi488// lea (%rsi, %rdi, 8), %rax489if (CurDAG->haveNoCommonBitsSet(N.getOperand(0), N.getOperand(1)) &&490matchADD(N, AM, Depth))491return true;492break;493494case ISD::ADD:495if (matchADD(N, AM, Depth))496return true;497break;498499case ISD::FrameIndex:500if (AM.isDispAddrType() &&501AM.BaseType == M68kISelAddressMode::Base::RegBase &&502AM.BaseReg.getNode() == nullptr && doesDispFitFI(AM)) {503AM.BaseType = M68kISelAddressMode::Base::FrameIndexBase;504AM.BaseFrameIndex = cast<FrameIndexSDNode>(N)->getIndex();505return true;506}507break;508509case ISD::TargetGlobalTLSAddress: {510GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(N);511AM.GV = GA->getGlobal();512AM.SymbolFlags = GA->getTargetFlags();513return true;514}515}516517return matchAddressBase(N, AM);518}519520/// Add the specified node to the specified addressing mode, returning true if521/// it cannot be done. This just pattern matches for the addressing mode.522bool M68kDAGToDAGISel::matchAddress(SDValue N, M68kISelAddressMode &AM) {523// TODO: Post-processing: Convert lea(,%reg,2) to lea(%reg,%reg), which has524// a smaller encoding and avoids a scaled-index.525// And make sure it is an indexed mode526527// TODO: Post-processing: Convert foo to foo(%pc), even in non-PIC mode,528// because it has a smaller encoding.529// Make sure this must be done only if PC* modes are currently being matched530return matchAddressRecursively(N, AM, 0);531}532533bool M68kDAGToDAGISel::matchADD(SDValue &N, M68kISelAddressMode &AM,534unsigned Depth) {535// Add an artificial use to this node so that we can keep track of536// it if it gets CSE'd with a different node.537HandleSDNode Handle(N);538539M68kISelAddressMode Backup = AM;540if (matchAddressRecursively(N.getOperand(0), AM, Depth + 1) &&541matchAddressRecursively(Handle.getValue().getOperand(1), AM, Depth + 1)) {542return true;543}544AM = Backup;545546// Try again after commuting the operands.547if (matchAddressRecursively(Handle.getValue().getOperand(1), AM, Depth + 1) &&548matchAddressRecursively(Handle.getValue().getOperand(0), AM, Depth + 1)) {549return true;550}551AM = Backup;552553// If we couldn't fold both operands into the address at the same time,554// see if we can just put each operand into a register and fold at least555// the add.556if (!AM.hasBase() && !AM.hasIndexReg()) {557N = Handle.getValue();558AM.BaseReg = N.getOperand(0);559AM.IndexReg = N.getOperand(1);560AM.Scale = 1;561return true;562}563564N = Handle.getValue();565return false;566}567568/// Try to match M68kISD::Wrapper and M68kISD::WrapperPC nodes into an569/// addressing mode. These wrap things that will resolve down into a symbol570/// reference. If no match is possible, this returns true, otherwise it returns571/// false.572bool M68kDAGToDAGISel::matchWrapper(SDValue N, M68kISelAddressMode &AM) {573// If the addressing mode already has a symbol as the displacement, we can574// never match another symbol.575if (AM.hasSymbolicDisplacement())576return false;577578SDValue N0 = N.getOperand(0);579580if (N.getOpcode() == M68kISD::WrapperPC) {581582// If cannot match here just restore the old version583M68kISelAddressMode Backup = AM;584585if (AM.hasBase()) {586return false;587}588589if (auto *G = dyn_cast<GlobalAddressSDNode>(N0)) {590AM.GV = G->getGlobal();591AM.SymbolFlags = G->getTargetFlags();592if (!foldOffsetIntoAddress(G->getOffset(), AM)) {593AM = Backup;594return false;595}596} else if (auto *CP = dyn_cast<ConstantPoolSDNode>(N0)) {597AM.CP = CP->getConstVal();598AM.Alignment = CP->getAlign();599AM.SymbolFlags = CP->getTargetFlags();600if (!foldOffsetIntoAddress(CP->getOffset(), AM)) {601AM = Backup;602return false;603}604} else if (auto *S = dyn_cast<ExternalSymbolSDNode>(N0)) {605AM.ES = S->getSymbol();606AM.SymbolFlags = S->getTargetFlags();607} else if (auto *S = dyn_cast<MCSymbolSDNode>(N0)) {608AM.MCSym = S->getMCSymbol();609} else if (auto *J = dyn_cast<JumpTableSDNode>(N0)) {610AM.JT = J->getIndex();611AM.SymbolFlags = J->getTargetFlags();612} else if (auto *BA = dyn_cast<BlockAddressSDNode>(N0)) {613AM.BlockAddr = BA->getBlockAddress();614AM.SymbolFlags = BA->getTargetFlags();615if (!foldOffsetIntoAddress(BA->getOffset(), AM)) {616AM = Backup;617return false;618}619} else620llvm_unreachable("Unhandled symbol reference node.");621622AM.setBaseReg(CurDAG->getRegister(M68k::PC, MVT::i32));623return true;624}625626// This wrapper requires 32bit disp/imm field for Medium CM627if (!AM.isDisp32()) {628return false;629}630631if (N.getOpcode() == M68kISD::Wrapper) {632if (auto *G = dyn_cast<GlobalAddressSDNode>(N0)) {633AM.GV = G->getGlobal();634AM.Disp += G->getOffset();635AM.SymbolFlags = G->getTargetFlags();636} else if (auto *CP = dyn_cast<ConstantPoolSDNode>(N0)) {637AM.CP = CP->getConstVal();638AM.Alignment = CP->getAlign();639AM.Disp += CP->getOffset();640AM.SymbolFlags = CP->getTargetFlags();641} else if (auto *S = dyn_cast<ExternalSymbolSDNode>(N0)) {642AM.ES = S->getSymbol();643AM.SymbolFlags = S->getTargetFlags();644} else if (auto *S = dyn_cast<MCSymbolSDNode>(N0)) {645AM.MCSym = S->getMCSymbol();646} else if (auto *J = dyn_cast<JumpTableSDNode>(N0)) {647AM.JT = J->getIndex();648AM.SymbolFlags = J->getTargetFlags();649} else if (auto *BA = dyn_cast<BlockAddressSDNode>(N0)) {650AM.BlockAddr = BA->getBlockAddress();651AM.Disp += BA->getOffset();652AM.SymbolFlags = BA->getTargetFlags();653} else654llvm_unreachable("Unhandled symbol reference node.");655return true;656}657658return false;659}660661//===----------------------------------------------------------------------===//662// Selectors663//===----------------------------------------------------------------------===//664665void M68kDAGToDAGISel::Select(SDNode *Node) {666unsigned Opcode = Node->getOpcode();667SDLoc DL(Node);668669LLVM_DEBUG(dbgs() << "Selecting: "; Node->dump(CurDAG); dbgs() << '\n');670671if (Node->isMachineOpcode()) {672LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << '\n');673Node->setNodeId(-1);674return; // Already selected.675}676677switch (Opcode) {678default:679break;680681case ISD::GLOBAL_OFFSET_TABLE: {682SDValue GOT = CurDAG->getTargetExternalSymbol(683"_GLOBAL_OFFSET_TABLE_", MVT::i32, M68kII::MO_GOTPCREL);684MachineSDNode *Res =685CurDAG->getMachineNode(M68k::LEA32q, DL, MVT::i32, GOT);686ReplaceNode(Node, Res);687return;688}689690case M68kISD::GLOBAL_BASE_REG:691ReplaceNode(Node, getGlobalBaseReg());692return;693}694695SelectCode(Node);696}697698bool M68kDAGToDAGISel::SelectARIPI(SDNode *Parent, SDValue N, SDValue &Base) {699LLVM_DEBUG(dbgs() << "Selecting AddrType::ARIPI: ");700LLVM_DEBUG(dbgs() << "NOT IMPLEMENTED\n");701return false;702}703704bool M68kDAGToDAGISel::SelectARIPD(SDNode *Parent, SDValue N, SDValue &Base) {705LLVM_DEBUG(dbgs() << "Selecting AddrType::ARIPD: ");706LLVM_DEBUG(dbgs() << "NOT IMPLEMENTED\n");707return false;708}709710bool M68kDAGToDAGISel::SelectARID(SDNode *Parent, SDValue N, SDValue &Disp,711SDValue &Base) {712LLVM_DEBUG(dbgs() << "Selecting AddrType::ARID: ");713M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARID);714715if (!matchAddress(N, AM))716return false;717718if (AM.isPCRelative()) {719LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");720return false;721}722723// If this is a frame index, grab it724if (getFrameIndexAddress(AM, SDLoc(N), Disp, Base)) {725LLVM_DEBUG(dbgs() << "SUCCESS matched FI\n");726return true;727}728729if (AM.hasIndexReg()) {730LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");731return false;732}733734if (!AM.hasBaseReg()) {735LLVM_DEBUG(dbgs() << "REJECT: No Base reg\n");736return false;737}738739Base = AM.BaseReg;740741if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {742assert(!AM.Disp && "Should not be any displacement");743LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");744return true;745}746747// Give a chance to AddrType::ARI748if (AM.Disp == 0) {749LLVM_DEBUG(dbgs() << "REJECT: No displacement\n");750return false;751}752753Disp = getI16Imm(AM.Disp, SDLoc(N));754755LLVM_DEBUG(dbgs() << "SUCCESS\n");756return true;757}758759static bool isAddressBase(const SDValue &N) {760switch (N.getOpcode()) {761case ISD::ADD:762case ISD::ADDC:763return llvm::any_of(N.getNode()->ops(),764[](const SDUse &U) { return isAddressBase(U.get()); });765case M68kISD::Wrapper:766case M68kISD::WrapperPC:767case M68kISD::GLOBAL_BASE_REG:768return true;769default:770return false;771}772}773774bool M68kDAGToDAGISel::SelectARII(SDNode *Parent, SDValue N, SDValue &Disp,775SDValue &Base, SDValue &Index) {776M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARII);777LLVM_DEBUG(dbgs() << "Selecting AddrType::ARII: ");778779if (!matchAddress(N, AM))780return false;781782if (AM.isPCRelative()) {783LLVM_DEBUG(dbgs() << "REJECT: PC relative\n");784return false;785}786787if (!AM.hasIndexReg()) {788LLVM_DEBUG(dbgs() << "REJECT: No Index\n");789return false;790}791792if (!AM.hasBaseReg()) {793LLVM_DEBUG(dbgs() << "REJECT: No Base\n");794return false;795}796797if (!isAddressBase(AM.BaseReg) && isAddressBase(AM.IndexReg)) {798Base = AM.IndexReg;799Index = AM.BaseReg;800} else {801Base = AM.BaseReg;802Index = AM.IndexReg;803}804805if (AM.hasSymbolicDisplacement()) {806LLVM_DEBUG(dbgs() << "REJECT, Cannot match symbolic displacement\n");807return false;808}809810// The idea here is that we want to use AddrType::ARII without displacement811// only if necessary like memory operations, otherwise this must be lowered812// into addition813if (AM.Disp == 0 && (!Parent || (Parent->getOpcode() != ISD::LOAD &&814Parent->getOpcode() != ISD::STORE))) {815LLVM_DEBUG(dbgs() << "REJECT: Displacement is Zero\n");816return false;817}818819Disp = getI8Imm(AM.Disp, SDLoc(N));820821LLVM_DEBUG(dbgs() << "SUCCESS\n");822return true;823}824825bool M68kDAGToDAGISel::SelectAL(SDNode *Parent, SDValue N, SDValue &Sym) {826LLVM_DEBUG(dbgs() << "Selecting AddrType::AL: ");827M68kISelAddressMode AM(M68kISelAddressMode::AddrType::AL);828829if (!matchAddress(N, AM)) {830LLVM_DEBUG(dbgs() << "REJECT: Match failed\n");831return false;832}833834if (AM.isPCRelative()) {835LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");836return false;837}838839if (AM.hasBase()) {840LLVM_DEBUG(dbgs() << "REJECT: Cannot match Base\n");841return false;842}843844if (AM.hasIndexReg()) {845LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");846return false;847}848849if (getSymbolicDisplacement(AM, SDLoc(N), Sym)) {850LLVM_DEBUG(dbgs() << "SUCCESS: Matched symbol\n");851return true;852}853854if (AM.Disp) {855Sym = getI32Imm(AM.Disp, SDLoc(N));856LLVM_DEBUG(dbgs() << "SUCCESS\n");857return true;858}859860LLVM_DEBUG(dbgs() << "REJECT: Not Symbol or Disp\n");861return false;862;863}864865bool M68kDAGToDAGISel::SelectPCD(SDNode *Parent, SDValue N, SDValue &Disp) {866LLVM_DEBUG(dbgs() << "Selecting AddrType::PCD: ");867M68kISelAddressMode AM(M68kISelAddressMode::AddrType::PCD);868869if (!matchAddress(N, AM))870return false;871872if (!AM.isPCRelative()) {873LLVM_DEBUG(dbgs() << "REJECT: Not PC relative\n");874return false;875}876877if (AM.hasIndexReg()) {878LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index\n");879return false;880}881882if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {883LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");884return true;885}886887Disp = getI16Imm(AM.Disp, SDLoc(N));888889LLVM_DEBUG(dbgs() << "SUCCESS\n");890return true;891}892893bool M68kDAGToDAGISel::SelectPCI(SDNode *Parent, SDValue N, SDValue &Disp,894SDValue &Index) {895LLVM_DEBUG(dbgs() << "Selecting AddrType::PCI: ");896M68kISelAddressMode AM(M68kISelAddressMode::AddrType::PCI);897898if (!matchAddress(N, AM))899return false;900901if (!AM.isPCRelative()) {902LLVM_DEBUG(dbgs() << "REJECT: Not PC relative\n");903return false;904}905906if (!AM.hasIndexReg()) {907LLVM_DEBUG(dbgs() << "REJECT: No Index\n");908return false;909}910911Index = AM.IndexReg;912913if (getSymbolicDisplacement(AM, SDLoc(N), Disp)) {914assert(!AM.Disp && "Should not be any displacement");915LLVM_DEBUG(dbgs() << "SUCCESS, matched Symbol\n");916return true;917}918919Disp = getI8Imm(AM.Disp, SDLoc(N));920921LLVM_DEBUG(dbgs() << "SUCCESS\n");922return true;923}924925bool M68kDAGToDAGISel::SelectARI(SDNode *Parent, SDValue N, SDValue &Base) {926LLVM_DEBUG(dbgs() << "Selecting AddrType::ARI: ");927M68kISelAddressMode AM(M68kISelAddressMode::AddrType::ARI);928929if (!matchAddress(N, AM)) {930LLVM_DEBUG(dbgs() << "REJECT: Match failed\n");931return false;932}933934if (AM.isPCRelative()) {935LLVM_DEBUG(dbgs() << "REJECT: Cannot match PC relative address\n");936return false;937}938939// AddrType::ARI does not use these940if (AM.hasIndexReg() || AM.Disp != 0) {941LLVM_DEBUG(dbgs() << "REJECT: Cannot match Index or Disp\n");942return false;943}944945// Must be matched by AddrType::AL946if (AM.hasSymbolicDisplacement()) {947LLVM_DEBUG(dbgs() << "REJECT: Cannot match Symbolic Disp\n");948return false;949}950951if (AM.hasBaseReg()) {952Base = AM.BaseReg;953LLVM_DEBUG(dbgs() << "SUCCESS\n");954return true;955}956957return false;958}959960bool M68kDAGToDAGISel::SelectInlineAsmMemoryOperand(961const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,962std::vector<SDValue> &OutOps) {963// In order to tell AsmPrinter the exact addressing mode we select here, which964// might comprise of multiple SDValues (hence MachineOperands), a 32-bit965// immediate value is prepended to the list of selected SDValues to indicate966// the addressing mode kind.967using AMK = M68k::MemAddrModeKind;968auto addKind = [this](SDValue &Opnd, AMK Kind) -> bool {969Opnd = CurDAG->getTargetConstant(unsigned(Kind), SDLoc(), MVT::i32);970return true;971};972973switch (ConstraintID) {974// Generic memory operand.975case InlineAsm::ConstraintCode::m: {976// Try every supported (memory) addressing modes.977SDValue Operands[4];978979// TODO: The ordering of the following SelectXXX is relatively...arbitrary,980// right now we simply sort them by descending complexity. Maybe we should981// adjust this by code model and/or relocation mode in the future.982if (SelectARII(nullptr, Op, Operands[1], Operands[2], Operands[3]) &&983addKind(Operands[0], AMK::f)) {984OutOps.insert(OutOps.end(), &Operands[0], Operands + 4);985return false;986}987988if ((SelectPCI(nullptr, Op, Operands[1], Operands[2]) &&989addKind(Operands[0], AMK::k)) ||990(SelectARID(nullptr, Op, Operands[1], Operands[2]) &&991addKind(Operands[0], AMK::p))) {992OutOps.insert(OutOps.end(), &Operands[0], Operands + 3);993return false;994}995996if ((SelectPCD(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::q)) ||997(SelectARI(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::j)) ||998(SelectAL(nullptr, Op, Operands[1]) && addKind(Operands[0], AMK::b))) {999OutOps.insert(OutOps.end(), {Operands[0], Operands[1]});1000return false;1001}10021003return true;1004}1005// 'Q': Address register indirect addressing.1006case InlineAsm::ConstraintCode::Q: {1007SDValue AMKind, Base;1008// 'j' addressing mode.1009// TODO: Add support for 'o' and 'e' after their1010// select functions are implemented.1011if (SelectARI(nullptr, Op, Base) && addKind(AMKind, AMK::j)) {1012OutOps.insert(OutOps.end(), {AMKind, Base});1013return false;1014}1015return true;1016}1017// 'U': Address register indirect w/ constant offset addressing.1018case InlineAsm::ConstraintCode::Um: {1019SDValue AMKind, Base, Offset;1020// 'p' addressing mode.1021if (SelectARID(nullptr, Op, Offset, Base) && addKind(AMKind, AMK::p)) {1022OutOps.insert(OutOps.end(), {AMKind, Offset, Base});1023return false;1024}1025return true;1026}1027default:1028return true;1029}1030}103110321033