774 lines
26 KiB
C++
774 lines
26 KiB
C++
//===- 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,
|
|
MachineInstr &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 (NewMI->getOpcode() == TargetOpcode::G_UNMERGE_VALUES)
|
|
combineAwayG_UNMERGE_VALUES(ArtCombiner, *NewMI, 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, MI, NewInstrObserver);
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return applyDefaultMapping(OpdMapper);
|
|
}
|