| //===- MipsRegisterBankInfo.cpp ---------------------------------*- C++ -*-===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| /// \file | |
| /// This file implements the targeting of the RegisterBankInfo class for Mips. | |
| /// \todo This should be generated by TableGen. | |
| //===----------------------------------------------------------------------===// | |
| #include "MipsRegisterBankInfo.h" | |
| #include "MipsInstrInfo.h" | |
| #include "MipsTargetMachine.h" | |
| #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h" | |
| #include "llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h" | |
| #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h" | |
| #include "llvm/CodeGen/MachineRegisterInfo.h" | |
| #define GET_TARGET_REGBANK_IMPL | |
| #include "MipsGenRegisterBank.inc" | |
| namespace llvm { | |
| namespace Mips { | |
| enum PartialMappingIdx { | |
| PMI_GPR32, | |
| PMI_GPR64, | |
| PMI_SPR, | |
| PMI_DPR, | |
| PMI_MSA, | |
| PMI_Min = PMI_GPR32, | |
| }; | |
| const RegisterBankInfo::PartialMapping PartMappings[]{{0, 32, GPRBRegBank}, | |
| {0, 64, GPRBRegBank}, | |
| {0, 32, FPRBRegBank}, | |
| {0, 64, FPRBRegBank}, | |
| {0, 128, FPRBRegBank}}; | |
| enum ValueMappingIdx { | |
| InvalidIdx = 0, | |
| GPR32Idx = 1, | |
| GPR64Idx = 4, | |
| SPRIdx = 7, | |
| DPRIdx = 10, | |
| MSAIdx = 13 | |
| }; | |
| const RegisterBankInfo::ValueMapping ValueMappings[] = { | |
| // invalid | |
| {nullptr, 0}, | |
| // up to 3 operands in GPRs; 32 bit. | |
| {&PartMappings[PMI_GPR32 - PMI_Min], 1}, | |
| {&PartMappings[PMI_GPR32 - PMI_Min], 1}, | |
| {&PartMappings[PMI_GPR32 - PMI_Min], 1}, | |
| // up to 3 operands in GPRs; 64 bit. | |
| {&PartMappings[PMI_GPR64 - PMI_Min], 1}, | |
| {&PartMappings[PMI_GPR64 - PMI_Min], 1}, | |
| {&PartMappings[PMI_GPR64 - PMI_Min], 1}, | |
| // up to 3 operands in FPRs - single precission | |
| {&PartMappings[PMI_SPR - PMI_Min], 1}, | |
| {&PartMappings[PMI_SPR - PMI_Min], 1}, | |
| {&PartMappings[PMI_SPR - PMI_Min], 1}, | |
| // up to 3 operands in FPRs - double precission | |
| {&PartMappings[PMI_DPR - PMI_Min], 1}, | |
| {&PartMappings[PMI_DPR - PMI_Min], 1}, | |
| {&PartMappings[PMI_DPR - PMI_Min], 1}, | |
| // up to 3 operands in FPRs - MSA | |
| {&PartMappings[PMI_MSA - PMI_Min], 1}, | |
| {&PartMappings[PMI_MSA - PMI_Min], 1}, | |
| {&PartMappings[PMI_MSA - PMI_Min], 1}}; | |
| } // end namespace Mips | |
| } // end namespace llvm | |
| using namespace llvm; | |
| MipsRegisterBankInfo::MipsRegisterBankInfo(const TargetRegisterInfo &TRI) {} | |
| // Instructions where use operands are floating point registers. | |
| // Def operands are general purpose. | |
| static bool isFloatingPointOpcodeUse(unsigned Opc) { | |
| switch (Opc) { | |
| case TargetOpcode::G_FPTOSI: | |
| case TargetOpcode::G_FPTOUI: | |
| case TargetOpcode::G_FCMP: | |
| return true; | |
| default: | |
| return isPreISelGenericFloatingPointOpcode(Opc); | |
| } | |
| } | |
| // Instructions where def operands are floating point registers. | |
| // Use operands are general purpose. | |
| static bool isFloatingPointOpcodeDef(unsigned Opc) { | |
| switch (Opc) { | |
| case TargetOpcode::G_SITOFP: | |
| case TargetOpcode::G_UITOFP: | |
| return true; | |
| default: | |
| return isPreISelGenericFloatingPointOpcode(Opc); | |
| } | |
| } | |
| static bool isGprbTwoInstrUnalignedLoadOrStore(const MachineInstr *MI) { | |
| if (MI->getOpcode() == TargetOpcode::G_LOAD || | |
| MI->getOpcode() == TargetOpcode::G_STORE) { | |
| auto MMO = *MI->memoperands_begin(); | |
| const MipsSubtarget &STI = MI->getMF()->getSubtarget<MipsSubtarget>(); | |
| if (MMO->getSize() == 4 && (!STI.systemSupportsUnalignedAccess() && | |
| (!MMO->getSize().hasValue() || | |
| MMO->getAlign() < MMO->getSize().getValue()))) | |
| return true; | |
| } | |
| return false; | |
| } | |
| static bool isAmbiguous(unsigned Opc) { | |
| switch (Opc) { | |
| case TargetOpcode::G_LOAD: | |
| case TargetOpcode::G_STORE: | |
| case TargetOpcode::G_PHI: | |
| case TargetOpcode::G_SELECT: | |
| case TargetOpcode::G_IMPLICIT_DEF: | |
| case TargetOpcode::G_UNMERGE_VALUES: | |
| case TargetOpcode::G_MERGE_VALUES: | |
| return true; | |
| default: | |
| return false; | |
| } | |
| } | |
| void MipsRegisterBankInfo::AmbiguousRegDefUseContainer::addDefUses( | |
| Register Reg, const MachineRegisterInfo &MRI) { | |
| assert(!MRI.getType(Reg).isPointer() && | |
| "Pointers are gprb, they should not be considered as ambiguous.\n"); | |
| for (MachineInstr &UseMI : MRI.use_instructions(Reg)) { | |
| MachineInstr *NonCopyInstr = skipCopiesOutgoing(&UseMI); | |
| // Copy with many uses. | |
| if (NonCopyInstr->getOpcode() == TargetOpcode::COPY && | |
| !NonCopyInstr->getOperand(0).getReg().isPhysical()) | |
| addDefUses(NonCopyInstr->getOperand(0).getReg(), MRI); | |
| else | |
| DefUses.push_back(skipCopiesOutgoing(&UseMI)); | |
| } | |
| } | |
| void MipsRegisterBankInfo::AmbiguousRegDefUseContainer::addUseDef( | |
| Register Reg, const MachineRegisterInfo &MRI) { | |
| assert(!MRI.getType(Reg).isPointer() && | |
| "Pointers are gprb, they should not be considered as ambiguous.\n"); | |
| MachineInstr *DefMI = MRI.getVRegDef(Reg); | |
| UseDefs.push_back(skipCopiesIncoming(DefMI)); | |
| } | |
| MachineInstr * | |
| MipsRegisterBankInfo::AmbiguousRegDefUseContainer::skipCopiesOutgoing( | |
| MachineInstr *MI) const { | |
| const MachineFunction &MF = *MI->getParent()->getParent(); | |
| const MachineRegisterInfo &MRI = MF.getRegInfo(); | |
| MachineInstr *Ret = MI; | |
| while (Ret->getOpcode() == TargetOpcode::COPY && | |
| !Ret->getOperand(0).getReg().isPhysical() && | |
| MRI.hasOneUse(Ret->getOperand(0).getReg())) { | |
| Ret = &(*MRI.use_instr_begin(Ret->getOperand(0).getReg())); | |
| } | |
| return Ret; | |
| } | |
| MachineInstr * | |
| MipsRegisterBankInfo::AmbiguousRegDefUseContainer::skipCopiesIncoming( | |
| MachineInstr *MI) const { | |
| const MachineFunction &MF = *MI->getParent()->getParent(); | |
| const MachineRegisterInfo &MRI = MF.getRegInfo(); | |
| MachineInstr *Ret = MI; | |
| while (Ret->getOpcode() == TargetOpcode::COPY && | |
| !Ret->getOperand(1).getReg().isPhysical()) | |
| Ret = MRI.getVRegDef(Ret->getOperand(1).getReg()); | |
| return Ret; | |
| } | |
| MipsRegisterBankInfo::AmbiguousRegDefUseContainer::AmbiguousRegDefUseContainer( | |
| const MachineInstr *MI) { | |
| assert(isAmbiguous(MI->getOpcode()) && | |
| "Not implemented for non Ambiguous opcode.\n"); | |
| const MachineRegisterInfo &MRI = MI->getMF()->getRegInfo(); | |
| if (MI->getOpcode() == TargetOpcode::G_LOAD) | |
| addDefUses(MI->getOperand(0).getReg(), MRI); | |
| if (MI->getOpcode() == TargetOpcode::G_STORE) | |
| addUseDef(MI->getOperand(0).getReg(), MRI); | |
| if (auto *PHI = dyn_cast<GPhi>(MI)) { | |
| addDefUses(PHI->getReg(0), MRI); | |
| for (unsigned I = 1; I < PHI->getNumIncomingValues(); ++I) | |
| addUseDef(PHI->getIncomingValue(I), MRI); | |
| } | |
| if (MI->getOpcode() == TargetOpcode::G_SELECT) { | |
| addDefUses(MI->getOperand(0).getReg(), MRI); | |
| addUseDef(MI->getOperand(2).getReg(), MRI); | |
| addUseDef(MI->getOperand(3).getReg(), MRI); | |
| } | |
| if (MI->getOpcode() == TargetOpcode::G_IMPLICIT_DEF) | |
| addDefUses(MI->getOperand(0).getReg(), MRI); | |
| if (MI->getOpcode() == TargetOpcode::G_UNMERGE_VALUES) | |
| addUseDef(MI->getOperand(MI->getNumOperands() - 1).getReg(), MRI); | |
| if (MI->getOpcode() == TargetOpcode::G_MERGE_VALUES) | |
| addDefUses(MI->getOperand(0).getReg(), MRI); | |
| } | |
| bool MipsRegisterBankInfo::TypeInfoForMF::visit( | |
| const MachineInstr *MI, const MachineInstr *WaitingForTypeOfMI, | |
| InstType &AmbiguousTy) { | |
| assert(isAmbiguous(MI->getOpcode()) && "Visiting non-Ambiguous opcode.\n"); | |
| if (wasVisited(MI)) | |
| return true; // InstType has already been determined for MI. | |
| startVisit(MI); | |
| AmbiguousRegDefUseContainer DefUseContainer(MI); | |
| if (isGprbTwoInstrUnalignedLoadOrStore(MI)) { | |
| setTypes(MI, Integer); | |
| return true; | |
| } | |
| if (AmbiguousTy == InstType::Ambiguous && | |
| (MI->getOpcode() == TargetOpcode::G_MERGE_VALUES || | |
| MI->getOpcode() == TargetOpcode::G_UNMERGE_VALUES)) | |
| AmbiguousTy = InstType::AmbiguousWithMergeOrUnmerge; | |
| // Visit instructions where MI's DEF operands are USED. | |
| if (visitAdjacentInstrs(MI, DefUseContainer.getDefUses(), true, AmbiguousTy)) | |
| return true; | |
| // Visit instructions that DEFINE MI's USE operands. | |
| if (visitAdjacentInstrs(MI, DefUseContainer.getUseDefs(), false, AmbiguousTy)) | |
| return true; | |
| // All MI's adjacent instructions, are ambiguous. | |
| if (!WaitingForTypeOfMI) { | |
| // This is chain of ambiguous instructions. | |
| setTypes(MI, AmbiguousTy); | |
| return true; | |
| } | |
| // Excluding WaitingForTypeOfMI, MI is either connected to chains of ambiguous | |
| // instructions or has no other adjacent instructions. Anyway InstType could | |
| // not be determined. There could be unexplored path from some of | |
| // WaitingForTypeOfMI's adjacent instructions to an instruction with only one | |
| // mapping available. | |
| // We are done with this branch, add MI to WaitingForTypeOfMI's WaitingQueue, | |
| // this way when WaitingForTypeOfMI figures out its InstType same InstType | |
| // will be assigned to all instructions in this branch. | |
| addToWaitingQueue(WaitingForTypeOfMI, MI); | |
| return false; | |
| } | |
| bool MipsRegisterBankInfo::TypeInfoForMF::visitAdjacentInstrs( | |
| const MachineInstr *MI, SmallVectorImpl<MachineInstr *> &AdjacentInstrs, | |
| bool isDefUse, InstType &AmbiguousTy) { | |
| while (!AdjacentInstrs.empty()) { | |
| MachineInstr *AdjMI = AdjacentInstrs.pop_back_val(); | |
| if (isDefUse ? isFloatingPointOpcodeUse(AdjMI->getOpcode()) | |
| : isFloatingPointOpcodeDef(AdjMI->getOpcode())) { | |
| setTypes(MI, InstType::FloatingPoint); | |
| return true; | |
| } | |
| // Determine InstType from register bank of phys register that is | |
| // 'isDefUse ? def : use' of this copy. | |
| if (AdjMI->getOpcode() == TargetOpcode::COPY) { | |
| setTypesAccordingToPhysicalRegister(MI, AdjMI, isDefUse ? 0 : 1); | |
| return true; | |
| } | |
| // Defaults to integer instruction. Small registers in G_MERGE (uses) and | |
| // G_UNMERGE (defs) will always be gprb. | |
| if ((!isDefUse && AdjMI->getOpcode() == TargetOpcode::G_UNMERGE_VALUES) || | |
| (isDefUse && AdjMI->getOpcode() == TargetOpcode::G_MERGE_VALUES) || | |
| !isAmbiguous(AdjMI->getOpcode())) { | |
| setTypes(MI, InstType::Integer); | |
| return true; | |
| } | |
| // When AdjMI was visited first, MI has to continue to explore remaining | |
| // adjacent instructions and determine InstType without visiting AdjMI. | |
| if (!wasVisited(AdjMI) || | |
| getRecordedTypeForInstr(AdjMI) != InstType::NotDetermined) { | |
| if (visit(AdjMI, MI, AmbiguousTy)) { | |
| // InstType is successfully determined and is same as for AdjMI. | |
| setTypes(MI, getRecordedTypeForInstr(AdjMI)); | |
| return true; | |
| } | |
| } | |
| } | |
| return false; | |
| } | |
| void MipsRegisterBankInfo::TypeInfoForMF::setTypes(const MachineInstr *MI, | |
| InstType InstTy) { | |
| changeRecordedTypeForInstr(MI, InstTy); | |
| for (const MachineInstr *WaitingInstr : getWaitingQueueFor(MI)) { | |
| setTypes(WaitingInstr, InstTy); | |
| } | |
| } | |
| void MipsRegisterBankInfo::TypeInfoForMF::setTypesAccordingToPhysicalRegister( | |
| const MachineInstr *MI, const MachineInstr *CopyInst, unsigned Op) { | |
| assert((CopyInst->getOperand(Op).getReg().isPhysical()) && | |
| "Copies of non physical registers should not be considered here.\n"); | |
| const MachineFunction &MF = *CopyInst->getMF(); | |
| const MachineRegisterInfo &MRI = MF.getRegInfo(); | |
| const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo(); | |
| const RegisterBankInfo &RBI = | |
| *CopyInst->getMF()->getSubtarget().getRegBankInfo(); | |
| const RegisterBank *Bank = | |
| RBI.getRegBank(CopyInst->getOperand(Op).getReg(), MRI, TRI); | |
| if (Bank == &Mips::FPRBRegBank) | |
| setTypes(MI, InstType::FloatingPoint); | |
| else if (Bank == &Mips::GPRBRegBank) | |
| setTypes(MI, InstType::Integer); | |
| else | |
| llvm_unreachable("Unsupported register bank.\n"); | |
| } | |
| MipsRegisterBankInfo::InstType | |
| MipsRegisterBankInfo::TypeInfoForMF::determineInstType(const MachineInstr *MI) { | |
| InstType DefaultAmbiguousType = InstType::Ambiguous; | |
| visit(MI, nullptr, DefaultAmbiguousType); | |
| return getRecordedTypeForInstr(MI); | |
| } | |
| void MipsRegisterBankInfo::TypeInfoForMF::cleanupIfNewFunction( | |
| llvm::StringRef FunctionName) { | |
| if (MFName != FunctionName) { | |
| MFName = std::string(FunctionName); | |
| WaitingQueues.clear(); | |
| Types.clear(); | |
| } | |
| } | |
| static const MipsRegisterBankInfo::ValueMapping * | |
| getMSAMapping(const MachineFunction &MF) { | |
| assert(MF.getSubtarget<MipsSubtarget>().hasMSA() && | |
| "MSA mapping not available on target without MSA."); | |
| return &Mips::ValueMappings[Mips::MSAIdx]; | |
| } | |
| static const MipsRegisterBankInfo::ValueMapping *getFprbMapping(unsigned Size) { | |
| return Size == 32 ? &Mips::ValueMappings[Mips::SPRIdx] | |
| : &Mips::ValueMappings[Mips::DPRIdx]; | |
| } | |
| static const unsigned CustomMappingID = 1; | |
| // Only 64 bit mapping is available in fprb and will be marked as custom, i.e. | |
| // will be split into two 32 bit registers in gprb. | |
| static const MipsRegisterBankInfo::ValueMapping * | |
| getGprbOrCustomMapping(unsigned Size, unsigned &MappingID) { | |
| if (Size == 32) | |
| return &Mips::ValueMappings[Mips::GPR32Idx]; | |
| MappingID = CustomMappingID; | |
| return &Mips::ValueMappings[Mips::DPRIdx]; | |
| } | |
| const RegisterBankInfo::InstructionMapping & | |
| MipsRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { | |
| static TypeInfoForMF TI; | |
| // Reset TI internal data when MF changes. | |
| TI.cleanupIfNewFunction(MI.getMF()->getName()); | |
| unsigned Opc = MI.getOpcode(); | |
| const MachineFunction &MF = *MI.getParent()->getParent(); | |
| const MachineRegisterInfo &MRI = MF.getRegInfo(); | |
| if (MI.getOpcode() != TargetOpcode::G_PHI) { | |
| const RegisterBankInfo::InstructionMapping &Mapping = | |
| getInstrMappingImpl(MI); | |
| if (Mapping.isValid()) | |
| return Mapping; | |
| } | |
| using namespace TargetOpcode; | |
| unsigned NumOperands = MI.getNumOperands(); | |
| const ValueMapping *OperandsMapping = &Mips::ValueMappings[Mips::GPR32Idx]; | |
| unsigned GPRSize = getMaximumSize(Mips::GPRBRegBankID); | |
| assert((GPRSize == 32 || GPRSize == 64) && "Unexpected GPR size"); | |
| const ValueMapping *GPRValueMapping = | |
| GPRSize == 32 ? &Mips::ValueMappings[Mips::GPR32Idx] | |
| : &Mips::ValueMappings[Mips::GPR64Idx]; | |
| unsigned MappingID = DefaultMappingID; | |
| // Check if LLT sizes match sizes of available register banks. | |
| for (const MachineOperand &Op : MI.operands()) { | |
| if (Op.isReg()) { | |
| LLT RegTy = MRI.getType(Op.getReg()); | |
| if (RegTy.isScalar() && | |
| (RegTy.getSizeInBits() != 32 && RegTy.getSizeInBits() != 64)) | |
| return getInvalidInstructionMapping(); | |
| if (RegTy.isVector() && RegTy.getSizeInBits() != 128) | |
| return getInvalidInstructionMapping(); | |
| } | |
| } | |
| const LLT Op0Ty = MRI.getType(MI.getOperand(0).getReg()); | |
| unsigned Op0Size = Op0Ty.getSizeInBits(); | |
| InstType InstTy = InstType::Integer; | |
| switch (Opc) { | |
| case G_TRUNC: | |
| case G_UMULH: | |
| case G_ZEXTLOAD: | |
| case G_SEXTLOAD: | |
| case G_PTR_ADD: | |
| case G_INTTOPTR: | |
| case G_PTRTOINT: | |
| case G_AND: | |
| case G_OR: | |
| case G_XOR: | |
| case G_SHL: | |
| case G_ASHR: | |
| case G_LSHR: | |
| case G_BRINDIRECT: | |
| case G_VASTART: | |
| case G_BSWAP: | |
| case G_CTLZ: | |
| OperandsMapping = GPRValueMapping; | |
| break; | |
| case G_ADD: | |
| case G_SUB: | |
| case G_MUL: | |
| case G_SDIV: | |
| case G_SREM: | |
| case G_UDIV: | |
| case G_UREM: | |
| OperandsMapping = GPRValueMapping; | |
| if (Op0Size == 128) | |
| OperandsMapping = getMSAMapping(MF); | |
| break; | |
| case G_STORE: | |
| case G_LOAD: { | |
| if (Op0Size == 128) { | |
| OperandsMapping = | |
| getOperandsMapping({getMSAMapping(MF), GPRValueMapping}); | |
| break; | |
| } | |
| if (!Op0Ty.isPointer()) | |
| InstTy = TI.determineInstType(&MI); | |
| if (isFloatingPoint_32or64(InstTy, Op0Size) || | |
| isAmbiguous_64(InstTy, Op0Size)) { | |
| OperandsMapping = | |
| getOperandsMapping({getFprbMapping(Op0Size), GPRValueMapping}); | |
| } else if (InstTy == InstType::Integer) { | |
| OperandsMapping = getOperandsMapping({GPRValueMapping, GPRValueMapping}); | |
| } else { | |
| assert((isAmbiguous_32(InstTy, Op0Size) || | |
| isAmbiguousWithMergeOrUnmerge_64(InstTy, Op0Size)) && | |
| "Unexpected Inst type"); | |
| OperandsMapping = getOperandsMapping( | |
| {getGprbOrCustomMapping(Op0Size, MappingID), GPRValueMapping}); | |
| } | |
| break; | |
| } | |
| case G_PHI: { | |
| if (!Op0Ty.isPointer()) | |
| InstTy = TI.determineInstType(&MI); | |
| // PHI is copylike and should have one regbank in mapping for def register. | |
| if (isAmbiguousWithMergeOrUnmerge_64(InstTy, Op0Size)) { | |
| OperandsMapping = | |
| getOperandsMapping({&Mips::ValueMappings[Mips::DPRIdx]}); | |
| TI.clearTypeInfoData(&MI); | |
| return getInstructionMapping(CustomMappingID, /*Cost=*/1, OperandsMapping, | |
| /*NumOperands=*/1); | |
| } | |
| assert((isInteger_32(InstTy, Op0Size) || isInteger_64(InstTy, Op0Size) || | |
| isFloatingPoint_32or64(InstTy, Op0Size) || | |
| isAmbiguous_32or64(InstTy, Op0Size)) && | |
| "Unexpected Inst type"); | |
| // Use default handling for PHI, i.e. set reg bank of def operand to match | |
| // register banks of use operands. | |
| return getInstrMappingImpl(MI); | |
| } | |
| case G_SELECT: { | |
| if (!Op0Ty.isPointer()) | |
| InstTy = TI.determineInstType(&MI); | |
| if (isFloatingPoint_32or64(InstTy, Op0Size) || | |
| isAmbiguous_64(InstTy, Op0Size)) { | |
| const RegisterBankInfo::ValueMapping *Bank = getFprbMapping(Op0Size); | |
| OperandsMapping = getOperandsMapping({Bank, GPRValueMapping, Bank, Bank}); | |
| break; | |
| } else if (InstTy == InstType::Integer) { | |
| OperandsMapping = getOperandsMapping( | |
| {GPRValueMapping, GPRValueMapping, GPRValueMapping, GPRValueMapping}); | |
| } else { | |
| assert((isAmbiguous_32(InstTy, Op0Size) || | |
| isAmbiguousWithMergeOrUnmerge_64(InstTy, Op0Size)) && | |
| "Unexpected Inst type"); | |
| const RegisterBankInfo::ValueMapping *Bank = | |
| getGprbOrCustomMapping(Op0Size, MappingID); | |
| OperandsMapping = getOperandsMapping({Bank, GPRValueMapping, Bank, Bank}); | |
| } | |
| break; | |
| } | |
| case G_IMPLICIT_DEF: { | |
| if (!Op0Ty.isPointer()) | |
| InstTy = TI.determineInstType(&MI); | |
| if (isFloatingPoint_32or64(InstTy, Op0Size)) | |
| OperandsMapping = getFprbMapping(Op0Size); | |
| else if (InstTy == InstType::Integer) { | |
| OperandsMapping = GPRValueMapping; | |
| } else { | |
| assert(isAmbiguousWithMergeOrUnmerge_64(InstTy, Op0Size) && | |
| "Unexpected Inst type"); | |
| OperandsMapping = getGprbOrCustomMapping(Op0Size, MappingID); | |
| } | |
| } break; | |
| case G_UNMERGE_VALUES: { | |
| assert(MI.getNumOperands() == 3 && "Unsupported G_UNMERGE_VALUES"); | |
| unsigned Op3Size = MRI.getType(MI.getOperand(2).getReg()).getSizeInBits(); | |
| InstTy = TI.determineInstType(&MI); | |
| assert((isAmbiguousWithMergeOrUnmerge_64(InstTy, Op3Size) || | |
| isFloatingPoint_64(InstTy, Op3Size)) && | |
| "Unexpected Inst type"); | |
| OperandsMapping = getOperandsMapping( | |
| {GPRValueMapping, GPRValueMapping, &Mips::ValueMappings[Mips::DPRIdx]}); | |
| if (isAmbiguousWithMergeOrUnmerge_64(InstTy, Op3Size)) | |
| MappingID = CustomMappingID; | |
| break; | |
| } | |
| case G_MERGE_VALUES: { | |
| InstTy = TI.determineInstType(&MI); | |
| assert((isAmbiguousWithMergeOrUnmerge_64(InstTy, Op0Size) || | |
| isFloatingPoint_64(InstTy, Op0Size)) && | |
| "Unexpected Inst type"); | |
| OperandsMapping = getOperandsMapping( | |
| {&Mips::ValueMappings[Mips::DPRIdx], GPRValueMapping, GPRValueMapping}); | |
| if (isAmbiguousWithMergeOrUnmerge_64(InstTy, Op0Size)) | |
| MappingID = CustomMappingID; | |
| break; | |
| } | |
| case G_FADD: | |
| case G_FSUB: | |
| case G_FMUL: | |
| case G_FDIV: | |
| case G_FABS: | |
| case G_FSQRT: | |
| OperandsMapping = getFprbMapping(Op0Size); | |
| if (Op0Size == 128) | |
| OperandsMapping = getMSAMapping(MF); | |
| break; | |
| case G_FCONSTANT: | |
| OperandsMapping = getOperandsMapping({getFprbMapping(Op0Size), nullptr}); | |
| break; | |
| case G_FCMP: { | |
| unsigned Op2Size = MRI.getType(MI.getOperand(2).getReg()).getSizeInBits(); | |
| OperandsMapping = | |
| getOperandsMapping({GPRValueMapping, nullptr, getFprbMapping(Op2Size), | |
| getFprbMapping(Op2Size)}); | |
| break; | |
| } | |
| case G_FPEXT: | |
| OperandsMapping = getOperandsMapping({&Mips::ValueMappings[Mips::DPRIdx], | |
| &Mips::ValueMappings[Mips::SPRIdx]}); | |
| break; | |
| case G_FPTRUNC: | |
| OperandsMapping = getOperandsMapping({&Mips::ValueMappings[Mips::SPRIdx], | |
| &Mips::ValueMappings[Mips::DPRIdx]}); | |
| break; | |
| case G_FPTOSI: { | |
| unsigned SizeFP = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits(); | |
| OperandsMapping = | |
| getOperandsMapping({GPRValueMapping, getFprbMapping(SizeFP)}); | |
| break; | |
| } | |
| case G_SITOFP: | |
| OperandsMapping = | |
| getOperandsMapping({getFprbMapping(Op0Size), GPRValueMapping}); | |
| break; | |
| case G_CONSTANT: | |
| case G_FRAME_INDEX: | |
| case G_GLOBAL_VALUE: | |
| case G_JUMP_TABLE: | |
| case G_BRCOND: | |
| OperandsMapping = getOperandsMapping({GPRValueMapping, nullptr}); | |
| break; | |
| case G_BRJT: | |
| OperandsMapping = | |
| getOperandsMapping({GPRValueMapping, nullptr, GPRValueMapping}); | |
| break; | |
| case G_ICMP: | |
| OperandsMapping = getOperandsMapping( | |
| {GPRValueMapping, nullptr, GPRValueMapping, GPRValueMapping}); | |
| break; | |
| default: | |
| return getInvalidInstructionMapping(); | |
| } | |
| if (MappingID == CustomMappingID) | |
| TI.clearTypeInfoData(&MI); | |
| return getInstructionMapping(MappingID, /*Cost=*/1, OperandsMapping, | |
| NumOperands); | |
| } | |
| using InstListTy = GISelWorkList<4>; | |
| namespace { | |
| class InstManager : public GISelChangeObserver { | |
| InstListTy &InstList; | |
| MachineIRBuilder &B; | |
| public: | |
| InstManager(MachineIRBuilder &B, InstListTy &Insts) : InstList(Insts), B(B) { | |
| assert(!B.isObservingChanges()); | |
| B.setChangeObserver(*this); | |
| } | |
| ~InstManager() override { B.stopObservingChanges(); } | |
| void createdInstr(MachineInstr &MI) override { InstList.insert(&MI); } | |
| void erasingInstr(MachineInstr &MI) override {} | |
| void changingInstr(MachineInstr &MI) override {} | |
| void changedInstr(MachineInstr &MI) override {} | |
| }; | |
| } // end anonymous namespace | |
| void MipsRegisterBankInfo::setRegBank(MachineInstr &MI, | |
| MachineRegisterInfo &MRI) const { | |
| Register Dest = MI.getOperand(0).getReg(); | |
| switch (MI.getOpcode()) { | |
| case TargetOpcode::G_STORE: | |
| // No def operands, skip this instruction. | |
| break; | |
| case TargetOpcode::G_CONSTANT: | |
| case TargetOpcode::G_LOAD: | |
| case TargetOpcode::G_SELECT: | |
| case TargetOpcode::G_PHI: | |
| case TargetOpcode::G_IMPLICIT_DEF: { | |
| assert(MRI.getType(Dest) == LLT::scalar(32) && "Unexpected operand type."); | |
| MRI.setRegBank(Dest, getRegBank(Mips::GPRBRegBankID)); | |
| break; | |
| } | |
| case TargetOpcode::G_PTR_ADD: { | |
| assert(MRI.getType(Dest).isPointer() && "Unexpected operand type."); | |
| MRI.setRegBank(Dest, getRegBank(Mips::GPRBRegBankID)); | |
| break; | |
| } | |
| default: | |
| llvm_unreachable("Unexpected opcode."); | |
| } | |
| } | |
| static void | |
| combineAwayG_UNMERGE_VALUES(LegalizationArtifactCombiner &ArtCombiner, | |
| GUnmerge &MI, GISelChangeObserver &Observer) { | |
| SmallVector<Register, 4> UpdatedDefs; | |
| SmallVector<MachineInstr *, 2> DeadInstrs; | |
| ArtCombiner.tryCombineUnmergeValues(MI, DeadInstrs, | |
| UpdatedDefs, Observer); | |
| for (MachineInstr *DeadMI : DeadInstrs) | |
| DeadMI->eraseFromParent(); | |
| } | |
| void MipsRegisterBankInfo::applyMappingImpl( | |
| MachineIRBuilder &Builder, const OperandsMapper &OpdMapper) const { | |
| MachineInstr &MI = OpdMapper.getMI(); | |
| Builder.setInstrAndDebugLoc(MI); | |
| InstListTy NewInstrs; | |
| MachineFunction *MF = MI.getMF(); | |
| MachineRegisterInfo &MRI = OpdMapper.getMRI(); | |
| const LegalizerInfo &LegInfo = *MF->getSubtarget().getLegalizerInfo(); | |
| InstManager NewInstrObserver(Builder, NewInstrs); | |
| LegalizerHelper Helper(*MF, NewInstrObserver, Builder); | |
| LegalizationArtifactCombiner ArtCombiner(Builder, MF->getRegInfo(), LegInfo); | |
| switch (MI.getOpcode()) { | |
| case TargetOpcode::G_LOAD: | |
| case TargetOpcode::G_STORE: | |
| case TargetOpcode::G_PHI: | |
| case TargetOpcode::G_SELECT: | |
| case TargetOpcode::G_IMPLICIT_DEF: { | |
| Helper.narrowScalar(MI, 0, LLT::scalar(32)); | |
| // Handle new instructions. | |
| while (!NewInstrs.empty()) { | |
| MachineInstr *NewMI = NewInstrs.pop_back_val(); | |
| // This is new G_UNMERGE that was created during narrowScalar and will | |
| // not be considered for regbank selection. RegBankSelect for mips | |
| // visits/makes corresponding G_MERGE first. Combine them here. | |
| if (auto *Unmerge = dyn_cast<GUnmerge>(NewMI)) | |
| combineAwayG_UNMERGE_VALUES(ArtCombiner, *Unmerge, NewInstrObserver); | |
| // This G_MERGE will be combined away when its corresponding G_UNMERGE | |
| // gets regBankSelected. | |
| else if (NewMI->getOpcode() == TargetOpcode::G_MERGE_VALUES) | |
| continue; | |
| else | |
| // Manually set register banks for def operands to 32 bit gprb. | |
| setRegBank(*NewMI, MRI); | |
| } | |
| return; | |
| } | |
| case TargetOpcode::G_UNMERGE_VALUES: | |
| combineAwayG_UNMERGE_VALUES(ArtCombiner, cast<GUnmerge>(MI), | |
| NewInstrObserver); | |
| return; | |
| default: | |
| break; | |
| } | |
| return applyDefaultMapping(OpdMapper); | |
| } |