blob: 04b69c66bc0d1ae5ab71380828ff5c904648394a [file] [log] [blame]
//===- 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);
}