| //===- 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_GPR, |
| PMI_SPR, |
| PMI_DPR, |
| PMI_MSA, |
| PMI_Min = PMI_GPR, |
| }; |
| |
| RegisterBankInfo::PartialMapping PartMappings[]{ |
| {0, 32, GPRBRegBank}, |
| {0, 32, FPRBRegBank}, |
| {0, 64, FPRBRegBank}, |
| {0, 128, FPRBRegBank} |
| }; |
| |
| enum ValueMappingIdx { |
| InvalidIdx = 0, |
| GPRIdx = 1, |
| SPRIdx = 4, |
| DPRIdx = 7, |
| MSAIdx = 10 |
| }; |
| |
| RegisterBankInfo::ValueMapping ValueMappings[] = { |
| // invalid |
| {nullptr, 0}, |
| // up to 3 operands in GPRs |
| {&PartMappings[PMI_GPR - PMI_Min], 1}, |
| {&PartMappings[PMI_GPR - PMI_Min], 1}, |
| {&PartMappings[PMI_GPR - 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) |
| : MipsGenRegisterBankInfo() {} |
| |
| const RegisterBank & |
| MipsRegisterBankInfo::getRegBankFromRegClass(const TargetRegisterClass &RC, |
| LLT) const { |
| using namespace Mips; |
| |
| switch (RC.getID()) { |
| case Mips::GPR32RegClassID: |
| case Mips::CPU16Regs_and_GPRMM16ZeroRegClassID: |
| case Mips::GPRMM16MovePPairFirstRegClassID: |
| case Mips::CPU16Regs_and_GPRMM16MovePPairSecondRegClassID: |
| case Mips::GPRMM16MoveP_and_CPU16Regs_and_GPRMM16ZeroRegClassID: |
| case Mips::GPRMM16MovePPairFirst_and_GPRMM16MovePPairSecondRegClassID: |
| case Mips::SP32RegClassID: |
| case Mips::GP32RegClassID: |
| return getRegBank(Mips::GPRBRegBankID); |
| case Mips::FGRCCRegClassID: |
| case Mips::FGR32RegClassID: |
| case Mips::FGR64RegClassID: |
| case Mips::AFGR64RegClassID: |
| case Mips::MSA128BRegClassID: |
| case Mips::MSA128HRegClassID: |
| case Mips::MSA128WRegClassID: |
| case Mips::MSA128DRegClassID: |
| return getRegBank(Mips::FPRBRegBankID); |
| default: |
| llvm_unreachable("Register class not supported"); |
| } |
| } |
| |
| // Instructions where all register operands are floating point. |
| static bool isFloatingPointOpcode(unsigned Opc) { |
| switch (Opc) { |
| case TargetOpcode::G_FCONSTANT: |
| case TargetOpcode::G_FADD: |
| case TargetOpcode::G_FSUB: |
| case TargetOpcode::G_FMUL: |
| case TargetOpcode::G_FDIV: |
| case TargetOpcode::G_FABS: |
| case TargetOpcode::G_FSQRT: |
| case TargetOpcode::G_FCEIL: |
| case TargetOpcode::G_FFLOOR: |
| case TargetOpcode::G_FPEXT: |
| case TargetOpcode::G_FPTRUNC: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| // 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 isFloatingPointOpcode(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 isFloatingPointOpcode(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 = |
| static_cast<const MipsSubtarget &>(MI->getMF()->getSubtarget()); |
| if (MMO->getSize() == 4 && (!STI.systemSupportsUnalignedAccess() && |
| MMO->getAlign() < MMO->getSize())) |
| 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 && |
| !Register::isPhysicalRegister(NonCopyInstr->getOperand(0).getReg())) |
| 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 && |
| !Register::isPhysicalRegister(Ret->getOperand(0).getReg()) && |
| 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 && |
| !Register::isPhysicalRegister(Ret->getOperand(1).getReg())) |
| 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 (MI->getOpcode() == TargetOpcode::G_PHI) { |
| addDefUses(MI->getOperand(0).getReg(), MRI); |
| |
| for (unsigned i = 1; i < MI->getNumOperands(); i += 2) |
| addUseDef(MI->getOperand(i).getReg(), 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((Register::isPhysicalRegister(CopyInst->getOperand(Op).getReg())) && |
| "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(static_cast<const MipsSubtarget &>(MF.getSubtarget()).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::GPRIdx]; |
| |
| 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::GPRIdx]; |
| 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 = &Mips::ValueMappings[Mips::GPRIdx]; |
| break; |
| case G_ADD: |
| case G_SUB: |
| case G_MUL: |
| case G_SDIV: |
| case G_SREM: |
| case G_UDIV: |
| case G_UREM: |
| OperandsMapping = &Mips::ValueMappings[Mips::GPRIdx]; |
| if (Op0Size == 128) |
| OperandsMapping = getMSAMapping(MF); |
| break; |
| case G_STORE: |
| case G_LOAD: { |
| if (Op0Size == 128) { |
| OperandsMapping = getOperandsMapping( |
| {getMSAMapping(MF), &Mips::ValueMappings[Mips::GPRIdx]}); |
| break; |
| } |
| |
| if (!Op0Ty.isPointer()) |
| InstTy = TI.determineInstType(&MI); |
| |
| if (isFloatingPoint_32or64(InstTy, Op0Size) || |
| isAmbiguous_64(InstTy, Op0Size)) { |
| OperandsMapping = getOperandsMapping( |
| {getFprbMapping(Op0Size), &Mips::ValueMappings[Mips::GPRIdx]}); |
| } else { |
| assert((isInteger_32(InstTy, Op0Size) || |
| isAmbiguous_32(InstTy, Op0Size) || |
| isAmbiguousWithMergeOrUnmerge_64(InstTy, Op0Size)) && |
| "Unexpected Inst type"); |
| OperandsMapping = |
| getOperandsMapping({getGprbOrCustomMapping(Op0Size, MappingID), |
| &Mips::ValueMappings[Mips::GPRIdx]}); |
| } |
| |
| 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) || |
| 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, &Mips::ValueMappings[Mips::GPRIdx], Bank, Bank}); |
| break; |
| } else { |
| assert((isInteger_32(InstTy, Op0Size) || |
| isAmbiguous_32(InstTy, Op0Size) || |
| isAmbiguousWithMergeOrUnmerge_64(InstTy, Op0Size)) && |
| "Unexpected Inst type"); |
| const RegisterBankInfo::ValueMapping *Bank = |
| getGprbOrCustomMapping(Op0Size, MappingID); |
| OperandsMapping = getOperandsMapping( |
| {Bank, &Mips::ValueMappings[Mips::GPRIdx], Bank, Bank}); |
| } |
| break; |
| } |
| case G_IMPLICIT_DEF: { |
| if (!Op0Ty.isPointer()) |
| InstTy = TI.determineInstType(&MI); |
| |
| if (isFloatingPoint_32or64(InstTy, Op0Size)) |
| OperandsMapping = getFprbMapping(Op0Size); |
| else { |
| assert((isInteger_32(InstTy, Op0Size) || |
| 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({&Mips::ValueMappings[Mips::GPRIdx], |
| &Mips::ValueMappings[Mips::GPRIdx], |
| &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], |
| &Mips::ValueMappings[Mips::GPRIdx], |
| &Mips::ValueMappings[Mips::GPRIdx]}); |
| 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({&Mips::ValueMappings[Mips::GPRIdx], 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: { |
| assert((Op0Size == 32) && "Unsupported integer size"); |
| unsigned SizeFP = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits(); |
| OperandsMapping = getOperandsMapping( |
| {&Mips::ValueMappings[Mips::GPRIdx], getFprbMapping(SizeFP)}); |
| break; |
| } |
| case G_SITOFP: |
| assert((MRI.getType(MI.getOperand(1).getReg()).getSizeInBits() == 32) && |
| "Unsupported integer size"); |
| OperandsMapping = getOperandsMapping( |
| {getFprbMapping(Op0Size), &Mips::ValueMappings[Mips::GPRIdx]}); |
| break; |
| case G_CONSTANT: |
| case G_FRAME_INDEX: |
| case G_GLOBAL_VALUE: |
| case G_JUMP_TABLE: |
| case G_BRCOND: |
| OperandsMapping = |
| getOperandsMapping({&Mips::ValueMappings[Mips::GPRIdx], nullptr}); |
| break; |
| case G_BRJT: |
| OperandsMapping = |
| getOperandsMapping({&Mips::ValueMappings[Mips::GPRIdx], nullptr, |
| &Mips::ValueMappings[Mips::GPRIdx]}); |
| break; |
| case G_ICMP: |
| OperandsMapping = |
| getOperandsMapping({&Mips::ValueMappings[Mips::GPRIdx], nullptr, |
| &Mips::ValueMappings[Mips::GPRIdx], |
| &Mips::ValueMappings[Mips::GPRIdx]}); |
| 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; |
| |
| public: |
| InstManager(InstListTy &Insts) : InstList(Insts) {} |
| |
| 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( |
| const OperandsMapper &OpdMapper) const { |
| MachineInstr &MI = OpdMapper.getMI(); |
| InstListTy NewInstrs; |
| MachineFunction *MF = MI.getMF(); |
| MachineRegisterInfo &MRI = OpdMapper.getMRI(); |
| const LegalizerInfo &LegInfo = *MF->getSubtarget().getLegalizerInfo(); |
| |
| InstManager NewInstrObserver(NewInstrs); |
| MachineIRBuilder B(MI, NewInstrObserver); |
| LegalizerHelper Helper(*MF, NewInstrObserver, B); |
| LegalizationArtifactCombiner ArtCombiner(B, 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); |
| } |