#define LLVM_CODEGEN_GLOBALISEL_REGBANKINFO_H
#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/GlobalISel/RegisterBank.h"
#include "llvm/CodeGen/MachineValueType.h" // For SimpleValueType.
/// different register banks.
struct ValueMapping {
/// How the value is broken down between the different register banks.
- SmallVector<PartialMapping, 2> BreakDown;
+ const PartialMapping *BreakDown;
+
+ /// Number of partial mapping to break down this value.
+ unsigned NumBreakDowns;
+
+ /// Iterators through the PartialMappings.
+ const PartialMapping *begin() const { return BreakDown; }
+ const PartialMapping *end() const { return BreakDown + NumBreakDowns; }
/// Verify that this mapping makes sense for a value of \p ExpectedBitWidth.
/// \note This method does not check anything when assertions are disabled.
/// This is a lightweight check for obvious wrong instance.
bool isValid() const { return getID() != InvalidMappingID; }
- /// Set the operand mapping for the \p OpIdx-th operand.
- /// The mapping will consist of only one element in the break down list.
- /// This element will map to \p RegBank and fully define a mask, whose
- /// bitwidth matches the size of \p MaskSize.
- void setOperandMapping(unsigned OpIdx, unsigned MaskSize,
- const RegisterBank &RegBank);
-
/// Verifiy that this mapping makes sense for \p MI.
/// \pre \p MI must be connected to a MachineFunction.
///
/// Total number of register banks.
unsigned NumRegBanks;
+ /// Keep dynamically allocated PartialMapping in a separate map.
+ /// This shouldn't be needed when everything gets TableGen'ed.
+ mutable DenseMap<unsigned, PartialMapping> MapOfPartialMappings;
+
/// Create a RegisterBankInfo that can accomodate up to \p NumRegBanks
/// RegisterBank instances.
///
/// any generic opcode that has not been lowered by target specific code.
InstructionMapping getInstrMappingImpl(const MachineInstr &MI) const;
+ /// Get the uniquely generated PartialMapping for the
+ /// given arguments.
+ const PartialMapping &getPartialMapping(unsigned StartIdx, unsigned Length,
+ const RegisterBank &RegBank) const;
+
/// Get the register bank for the \p OpIdx-th operand of \p MI form
/// the encoding constraints, if any.
///
OnlyAssign = false;
// Each part of a break down needs to end up in a different register.
// In other word, Reg assignement does not match.
- if (ValMapping.BreakDown.size() > 1)
+ if (ValMapping.NumBreakDowns > 1)
return false;
const RegisterBank *CurRegBank = RBI->getRegBank(Reg, *MRI, *TRI);
MachineOperand &MO, const RegisterBankInfo::ValueMapping &ValMapping,
RegBankSelect::RepairingPlacement &RepairPt,
const iterator_range<SmallVectorImpl<unsigned>::const_iterator> &NewVRegs) {
- if (ValMapping.BreakDown.size() != 1 && !TPC->isGlobalISelAbortEnabled())
+ if (ValMapping.NumBreakDowns != 1 && !TPC->isGlobalISelAbortEnabled())
return false;
- assert(ValMapping.BreakDown.size() == 1 && "Not yet implemented");
+ assert(ValMapping.NumBreakDowns == 1 && "Not yet implemented");
// An empty range of new register means no repairing.
assert(NewVRegs.begin() != NewVRegs.end() && "We should not have to repair");
const MachineOperand &MO,
const RegisterBankInfo::ValueMapping &ValMapping) const {
assert(MO.isReg() && "We should only repair register operand");
- assert(!ValMapping.BreakDown.empty() && "Nothing to map??");
+ assert(ValMapping.NumBreakDowns && "Nothing to map??");
- bool IsSameNumOfValues = ValMapping.BreakDown.size() == 1;
+ bool IsSameNumOfValues = ValMapping.NumBreakDowns == 1;
const RegisterBank *CurRegBank = RBI->getRegBank(MO.getReg(), *MRI, *TRI);
// If MO does not have a register bank, we should have just been
// able to set one unless we have to break the value down.
// For the PHI case, the split may not be actually required.
// In the copy case, a phi is already a copy on the incoming edge,
// therefore there is no need to split.
- if (ValMapping.BreakDown.size() == 1)
+ if (ValMapping.NumBreakDowns == 1)
// This is a already a copy, there is nothing to do.
RepairPt.switchTo(RepairingPlacement::RepairingKind::Reassign);
}
// We will split all the edges and repair there.
} else {
// This is a virtual register defined by a terminator.
- if (ValMapping.BreakDown.size() == 1) {
+ if (ValMapping.NumBreakDowns == 1) {
// There is nothing to repair, but we may actually lie on
// the repairing cost because of the PHIs already proceeded
// as already stated.
MachineOperand &MO = MI.getOperand(OpIdx);
const RegisterBankInfo::ValueMapping &ValMapping =
InstrMapping.getOperandMapping(OpIdx);
- unsigned BreakDownSize = ValMapping.BreakDown.size();
- (void)BreakDownSize;
unsigned Reg = MO.getReg();
switch (RepairPt.getKind()) {
case RepairingPlacement::Reassign:
- assert(BreakDownSize == 1 &&
+ assert(ValMapping.NumBreakDowns == 1 &&
"Reassignment should only be for simple mapping");
MRI->setRegBank(Reg, *ValMapping.BreakDown[0].RegBank);
break;
}
RegBank = CurRegBank;
RegSize = getSizeInBits(Reg, MRI, TRI);
- Mapping.setOperandMapping(OpIdx, RegSize, *CurRegBank);
+ Mapping.setOperandMapping(
+ OpIdx, ValueMapping{&getPartialMapping(0, RegSize, *CurRegBank), 1});
}
if (CompleteMapping)
continue;
// If a mapping already exists, do not touch it.
- if (!static_cast<const InstructionMapping *>(&Mapping)
- ->getOperandMapping(OpIdx)
- .BreakDown.empty())
+ if (static_cast<const InstructionMapping *>(&Mapping)
+ ->getOperandMapping(OpIdx)
+ .NumBreakDowns)
continue;
- Mapping.setOperandMapping(OpIdx, RegSize, *RegBank);
+ Mapping.setOperandMapping(
+ OpIdx, ValueMapping{&getPartialMapping(0, RegSize, *RegBank), 1});
}
return Mapping;
}
+const RegisterBankInfo::PartialMapping &
+RegisterBankInfo::getPartialMapping(unsigned StartIdx, unsigned Length,
+ const RegisterBank &RegBank) const {
+ hash_code Hash = hash_combine(StartIdx, Length, RegBank.getID());
+ const auto &It = MapOfPartialMappings.find(Hash);
+ if (It != MapOfPartialMappings.end())
+ return It->second;
+ PartialMapping &PartMapping = MapOfPartialMappings[Hash];
+ PartMapping = PartialMapping{StartIdx, Length, RegBank};
+ return PartMapping;
+}
+
RegisterBankInfo::InstructionMapping
RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
RegisterBankInfo::InstructionMapping Mapping = getInstrMappingImpl(MI);
DEBUG(dbgs() << " is not a register, nothing to be done\n");
continue;
}
- assert(
- OpdMapper.getInstrMapping().getOperandMapping(OpIdx).BreakDown.size() ==
- 1 &&
- "This mapping is too complex for this function");
+ assert(OpdMapper.getInstrMapping().getOperandMapping(OpIdx).NumBreakDowns ==
+ 1 &&
+ "This mapping is too complex for this function");
iterator_range<SmallVectorImpl<unsigned>::const_iterator> NewRegs =
OpdMapper.getVRegs(OpIdx);
if (NewRegs.begin() == NewRegs.end()) {
}
bool RegisterBankInfo::ValueMapping::verify(unsigned ExpectedBitWidth) const {
- assert(!BreakDown.empty() && "Value mapped nowhere?!");
+ assert(NumBreakDowns && "Value mapped nowhere?!");
unsigned OrigValueBitWidth = 0;
- for (const RegisterBankInfo::PartialMapping &PartMap : BreakDown) {
+ for (const RegisterBankInfo::PartialMapping &PartMap : *this) {
// Check that each register bank is big enough to hold the partial value:
// this check is done by PartialMapping::verify
assert(PartMap.verify() && "Partial mapping is invalid");
}
assert(OrigValueBitWidth == ExpectedBitWidth && "BitWidth does not match");
APInt ValueMask(OrigValueBitWidth, 0);
- for (const RegisterBankInfo::PartialMapping &PartMap : BreakDown) {
+ for (const RegisterBankInfo::PartialMapping &PartMap : *this) {
// Check that the union of the partial mappings covers the whole value,
// without overlaps.
// The high bit is exclusive in the APInt API, thus getHighBitIdx + 1.
}
void RegisterBankInfo::ValueMapping::print(raw_ostream &OS) const {
- OS << "#BreakDown: " << BreakDown.size() << " ";
+ OS << "#BreakDown: " << NumBreakDowns << " ";
bool IsFirst = true;
- for (const PartialMapping &PartMap : BreakDown) {
+ for (const PartialMapping &PartMap : *this) {
if (!IsFirst)
OS << ", ";
OS << '[' << PartMap << ']';
}
}
-void RegisterBankInfo::InstructionMapping::setOperandMapping(
- unsigned OpIdx, unsigned MaskSize, const RegisterBank &RegBank) {
- // Build the value mapping.
- assert(MaskSize <= RegBank.getSize() && "Register bank is too small");
-
- // Create the mapping object.
- getOperandMapping(OpIdx).BreakDown.push_back(
- PartialMapping(0, MaskSize, RegBank));
-}
-
bool RegisterBankInfo::InstructionMapping::verify(
const MachineInstr &MI) const {
// Check that all the register operands are properly mapped.
const RegisterBankInfo::ValueMapping &MOMapping = getOperandMapping(Idx);
(void)MOMapping;
if (!MO.isReg()) {
- assert(MOMapping.BreakDown.empty() &&
+ assert(!MOMapping.NumBreakDowns &&
"We should not care about non-reg mapping");
continue;
}
RegisterBankInfo::OperandsMapper::getVRegsMem(unsigned OpIdx) {
assert(OpIdx < getMI().getNumOperands() && "Out-of-bound access");
unsigned NumPartialVal =
- getInstrMapping().getOperandMapping(OpIdx).BreakDown.size();
+ getInstrMapping().getOperandMapping(OpIdx).NumBreakDowns;
int StartIdx = OpToNewVRegIdx[OpIdx];
if (StartIdx == OperandsMapper::DontKnowIdx) {
assert(OpIdx < getMI().getNumOperands() && "Out-of-bound access");
iterator_range<SmallVectorImpl<unsigned>::iterator> NewVRegsForOpIdx =
getVRegsMem(OpIdx);
- const SmallVectorImpl<PartialMapping> &PartMapList =
- getInstrMapping().getOperandMapping(OpIdx).BreakDown;
- SmallVectorImpl<PartialMapping>::const_iterator PartMap = PartMapList.begin();
+ const ValueMapping &ValMapping = getInstrMapping().getOperandMapping(OpIdx);
+ const PartialMapping *PartMap = ValMapping.begin();
for (unsigned &NewVReg : NewVRegsForOpIdx) {
- assert(PartMap != PartMapList.end() && "Out-of-bound access");
+ assert(PartMap != ValMapping.end() && "Out-of-bound access");
assert(NewVReg == 0 && "Register has already been created");
NewVReg = MRI.createGenericVirtualRegister(LLT::scalar(PartMap->Length));
MRI.setRegBank(NewVReg, *PartMap->RegBank);
unsigned PartialMapIdx,
unsigned NewVReg) {
assert(OpIdx < getMI().getNumOperands() && "Out-of-bound access");
- assert(getInstrMapping().getOperandMapping(OpIdx).BreakDown.size() >
+ assert(getInstrMapping().getOperandMapping(OpIdx).NumBreakDowns >
PartialMapIdx &&
"Out-of-bound access for partial mapping");
// Make sure the memory is initialized for that operand.
return make_range(NewVRegs.end(), NewVRegs.end());
unsigned PartMapSize =
- getInstrMapping().getOperandMapping(OpIdx).BreakDown.size();
+ getInstrMapping().getOperandMapping(OpIdx).NumBreakDowns;
SmallVectorImpl<unsigned>::const_iterator End =
getNewVRegsEnd(StartIdx, PartMapSize);
iterator_range<SmallVectorImpl<unsigned>::const_iterator> Res =
InstructionMapping GPRMapping(/*ID*/ 1, /*Cost*/ 1, /*NumOperands*/ 3);
InstructionMapping FPRMapping(/*ID*/ 2, /*Cost*/ 1, /*NumOperands*/ 3);
for (unsigned Idx = 0; Idx != 3; ++Idx) {
- GPRMapping.setOperandMapping(Idx, Size,
- getRegBank(AArch64::GPRRegBankID));
- FPRMapping.setOperandMapping(Idx, Size,
- getRegBank(AArch64::FPRRegBankID));
+ GPRMapping.setOperandMapping(
+ Idx, ValueMapping{&getPartialMapping(
+ 0, Size, getRegBank(AArch64::GPRRegBankID)),
+ 1});
+ FPRMapping.setOperandMapping(
+ Idx, ValueMapping{&getPartialMapping(
+ 0, Size, getRegBank(AArch64::FPRRegBankID)),
+ 1});
}
AltMappings.emplace_back(std::move(GPRMapping));
AltMappings.emplace_back(std::move(FPRMapping));
// Finally construct the computed mapping.
for (unsigned Idx = 0; Idx < MI.getNumOperands(); ++Idx)
if (MI.getOperand(Idx).isReg())
- Mapping.setOperandMapping(Idx, OpSizes[Idx], getRegBank(OpBanks[Idx]));
+ Mapping.setOperandMapping(
+ Idx, ValueMapping{&getPartialMapping(0, OpSizes[Idx],
+ getRegBank(OpBanks[Idx])),
+ 1});
return Mapping;
}