llvm-project/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
Ivan Kosarev 21c1ba16ed
[TableGen] Complete the support for artificial registers (#183371)
Artificial registers were added in
eb0c510ecde667cd911682cc1e855f73f341d134
as a means of giving super-registers heavier weights than that
of their subregisters, even when they only contain a single
physical subregister.

Artifical registers thus do exist in code and participate in
register unit weight calculations, but are not supposed to be
available for register allocation.

This patch completes the support for artificial registers to:

- Ignore artificial registers when joining register unit uber
  sets. Artificial registers may be members of classes that
  together include registers and their sub-registers, making it
  impossible to compute normalised weights for uber sets they
  belong to.

  We have a use case downstream relying on this being supported,
  which allows to avoid introducing a large number of additional
  register classes.

- Not generate purely artificial register class intersections.
  It is critical not to have such classes, as the common LLVM
  codegen infrastructure will try to use them to constrain
  classes of virtual registers instead of producing COPYs
  whenever both the source and target register classes contain
  the same artificial registers.

- Not generate sub-classes where classes with the same
  non-artificial members already exist. This is mostly for
  convenience. For example, the HI16-capable subset of AMDGPU's
  AV_32 is VGPR_32, except VGPR_32 also contains the artificial
  staging registers. If the staging registers are not ignored,
  we'll end up having an additional generated register class,
  AV_32_with_hi16_in_VGPR_16, -- harmless, but also useless.

Eliminates a few inferred AMDGPU register classes:
    - VS_32_with_hi16
    - VS_32_Lo256_with_hi16
    - VS_32_Lo128_with_hi16
    - VRegOrLds_32_and_VS_32_Lo256
    - VRegOrLds_32_and_VS_32_Lo128
    - SRegOrLds_32_and_VRegOrLds_32

Causes no register class changes for other targets.
2026-03-04 13:33:26 +00:00

2833 lines
104 KiB
C++

//===- CodeGenRegisters.cpp - Register and RegisterClass Info -------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file defines structures to encapsulate information gleaned from the
// target register and register class definitions.
//
//===----------------------------------------------------------------------===//
#include "CodeGenRegisters.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/IntEqClasses.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TGTimer.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <iterator>
#include <map>
#include <queue>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
using namespace llvm;
#define DEBUG_TYPE "regalloc-emitter"
//===----------------------------------------------------------------------===//
// CodeGenSubRegIndex
//===----------------------------------------------------------------------===//
CodeGenSubRegIndex::CodeGenSubRegIndex(const Record *R, unsigned Enum,
const CodeGenHwModes &CGH)
: TheDef(R), Name(R->getName().str()), EnumValue(Enum),
AllSuperRegsCovered(true), Artificial(true) {
if (R->getValue("Namespace"))
Namespace = R->getValueAsString("Namespace").str();
if (const Record *RV = R->getValueAsOptionalDef("SubRegRanges"))
Range = SubRegRangeByHwMode(RV, CGH);
if (!Range.hasDefault())
Range.insertSubRegRangeForMode(DefaultMode, SubRegRange(R));
}
CodeGenSubRegIndex::CodeGenSubRegIndex(StringRef N, StringRef Nspace,
unsigned Enum)
: TheDef(nullptr), Name(N.str()), Namespace(Nspace.str()),
Range(SubRegRange(-1, -1)), EnumValue(Enum), AllSuperRegsCovered(true),
Artificial(true) {}
std::string CodeGenSubRegIndex::getQualifiedName() const {
std::string N = getNamespace();
if (!N.empty())
N += "::";
N += getName();
return N;
}
void CodeGenSubRegIndex::updateComponents(CodeGenRegBank &RegBank) {
if (!TheDef)
return;
std::vector<const Record *> Comps =
TheDef->getValueAsListOfDefs("ComposedOf");
if (!Comps.empty()) {
if (Comps.size() != 2)
PrintFatalError(TheDef->getLoc(),
"ComposedOf must have exactly two entries");
CodeGenSubRegIndex *A = RegBank.getSubRegIdx(Comps[0]);
CodeGenSubRegIndex *B = RegBank.getSubRegIdx(Comps[1]);
CodeGenSubRegIndex *X = A->addComposite(B, this, RegBank.getHwModes());
if (X)
PrintFatalError(TheDef->getLoc(), "Ambiguous ComposedOf entries");
}
std::vector<const Record *> Parts =
TheDef->getValueAsListOfDefs("CoveringSubRegIndices");
if (!Parts.empty()) {
if (Parts.size() < 2)
PrintFatalError(TheDef->getLoc(),
"CoveringSubRegIndices must have two or more entries");
SmallVector<CodeGenSubRegIndex *, 8> IdxParts;
for (const Record *Part : Parts)
IdxParts.push_back(RegBank.getSubRegIdx(Part));
setConcatenationOf(IdxParts);
}
}
LaneBitmask CodeGenSubRegIndex::computeLaneMask() const {
// Already computed?
if (LaneMask.any())
return LaneMask;
// Recursion guard, shouldn't be required.
LaneMask = LaneBitmask::getAll();
// The lane mask is simply the union of all sub-indices.
LaneBitmask M;
for (const auto &C : Composed)
M |= C.second->computeLaneMask();
assert(M.any() && "Missing lane mask, sub-register cycle?");
LaneMask = M;
return LaneMask;
}
void CodeGenSubRegIndex::setConcatenationOf(
ArrayRef<CodeGenSubRegIndex *> Parts) {
if (ConcatenationOf.empty()) {
ConcatenationOf.assign(Parts.begin(), Parts.end());
return;
}
assert(llvm::equal(Parts, ConcatenationOf) && "parts consistent");
}
void CodeGenSubRegIndex::computeConcatTransitiveClosure() {
for (SmallVectorImpl<CodeGenSubRegIndex *>::iterator I =
ConcatenationOf.begin();
I != ConcatenationOf.end();
/*empty*/) {
CodeGenSubRegIndex *SubIdx = *I;
SubIdx->computeConcatTransitiveClosure();
#ifndef NDEBUG
for (CodeGenSubRegIndex *SRI : SubIdx->ConcatenationOf)
assert(SRI->ConcatenationOf.empty() && "No transitive closure?");
#endif
if (SubIdx->ConcatenationOf.empty()) {
++I;
} else {
I = ConcatenationOf.erase(I);
I = ConcatenationOf.insert(I, SubIdx->ConcatenationOf.begin(),
SubIdx->ConcatenationOf.end());
I += SubIdx->ConcatenationOf.size();
}
}
}
//===----------------------------------------------------------------------===//
// CodeGenRegister
//===----------------------------------------------------------------------===//
CodeGenRegister::CodeGenRegister(const Record *R, unsigned Enum)
: TheDef(R), EnumValue(Enum),
CostPerUse(R->getValueAsListOfInts("CostPerUse")),
CoveredBySubRegs(R->getValueAsBit("CoveredBySubRegs")),
Constant(R->getValueAsBit("isConstant")), SubRegsComplete(false),
SuperRegsComplete(false), TopoSig(~0u) {
Artificial = R->getValueAsBit("isArtificial");
}
void CodeGenRegister::buildObjectGraph(CodeGenRegBank &RegBank) {
std::vector<const Record *> SRIs =
TheDef->getValueAsListOfDefs("SubRegIndices");
std::vector<const Record *> SRs = TheDef->getValueAsListOfDefs("SubRegs");
for (const auto &[SRI, SR] : zip_equal(SRIs, SRs)) {
ExplicitSubRegIndices.push_back(RegBank.getSubRegIdx(SRI));
ExplicitSubRegs.push_back(RegBank.getReg(SR));
}
// Also compute leading super-registers. Each register has a list of
// covered-by-subregs super-registers where it appears as the first explicit
// sub-register.
//
// This is used by computeSecondarySubRegs() to find candidates.
if (CoveredBySubRegs && !ExplicitSubRegs.empty())
ExplicitSubRegs.front()->LeadingSuperRegs.push_back(this);
// Add ad hoc alias links. This is a symmetric relationship between two
// registers, so build a symmetric graph by adding links in both ends.
for (const Record *Alias : TheDef->getValueAsListOfDefs("Aliases")) {
CodeGenRegister *Reg = RegBank.getReg(Alias);
ExplicitAliases.push_back(Reg);
Reg->ExplicitAliases.push_back(this);
}
}
// Inherit register units from subregisters.
// Return true if the RegUnits changed.
bool CodeGenRegister::inheritRegUnits(CodeGenRegBank &RegBank) {
bool changed = false;
for (const auto &[_, SR] : SubRegs) {
// Merge the subregister's units into this register's RegUnits.
changed |= (RegUnits |= SR->RegUnits);
}
return changed;
}
const CodeGenRegister::SubRegMap &
CodeGenRegister::computeSubRegs(CodeGenRegBank &RegBank) {
// Only compute this map once.
if (SubRegsComplete)
return SubRegs;
SubRegsComplete = true;
HasDisjunctSubRegs = ExplicitSubRegs.size() > 1;
// First insert the explicit subregs and make sure they are fully indexed.
for (auto [SR, Idx] : zip_equal(ExplicitSubRegs, ExplicitSubRegIndices)) {
if (!SR->Artificial)
Idx->Artificial = false;
if (!SubRegs.try_emplace(Idx, SR).second)
PrintFatalError(TheDef->getLoc(), "SubRegIndex " + Idx->getName() +
" appears twice in Register " +
getName());
// Map explicit sub-registers first, so the names take precedence.
// The inherited sub-registers are mapped below.
SubReg2Idx.try_emplace(SR, Idx);
}
// Keep track of inherited subregs and how they can be reached.
SmallPtrSet<CodeGenRegister *, 8> Orphans;
// Clone inherited subregs and place duplicate entries in Orphans.
// Here the order is important - earlier subregs take precedence.
for (CodeGenRegister *ESR : ExplicitSubRegs) {
const SubRegMap &Map = ESR->computeSubRegs(RegBank);
HasDisjunctSubRegs |= ESR->HasDisjunctSubRegs;
for (const auto &SR : Map) {
if (!SubRegs.insert(SR).second)
Orphans.insert(SR.second);
}
}
// Expand any composed subreg indices.
// If dsub_2 has ComposedOf = [qsub_1, dsub_0], and this register has a
// qsub_1 subreg, add a dsub_2 subreg. Keep growing Indices and process
// expanded subreg indices recursively.
SmallVector<CodeGenSubRegIndex *, 8> Indices = ExplicitSubRegIndices;
for (unsigned i = 0; i != Indices.size(); ++i) {
CodeGenSubRegIndex *Idx = Indices[i];
const CodeGenSubRegIndex::CompMap &Comps = Idx->getComposites();
CodeGenRegister *SR = SubRegs[Idx];
const SubRegMap &Map = SR->computeSubRegs(RegBank);
// Look at the possible compositions of Idx.
// They may not all be supported by SR.
for (auto [Key, Val] : Comps) {
SubRegMap::const_iterator SRI = Map.find(Key);
if (SRI == Map.end())
continue; // Idx + I->first doesn't exist in SR.
// Add `Val` as a name for the subreg SRI->second, assuming it is
// orphaned, and the name isn't already used for something else.
if (SubRegs.count(Val) || !Orphans.erase(SRI->second))
continue;
// We found a new name for the orphaned sub-register.
SubRegs.try_emplace(Val, SRI->second);
Indices.push_back(Val);
}
}
// Now Orphans contains the inherited subregisters without a direct index.
// Create inferred indexes for all missing entries.
// Work backwards in the Indices vector in order to compose subregs bottom-up.
// Consider this subreg sequence:
//
// qsub_1 -> dsub_0 -> ssub_0
//
// The qsub_1 -> dsub_0 composition becomes dsub_2, so the ssub_0 register
// can be reached in two different ways:
//
// qsub_1 -> ssub_0
// dsub_2 -> ssub_0
//
// We pick the latter composition because another register may have [dsub_0,
// dsub_1, dsub_2] subregs without necessarily having a qsub_1 subreg. The
// dsub_2 -> ssub_0 composition can be shared.
while (!Indices.empty() && !Orphans.empty()) {
CodeGenSubRegIndex *Idx = Indices.pop_back_val();
CodeGenRegister *SR = SubRegs[Idx];
const SubRegMap &Map = SR->computeSubRegs(RegBank);
for (const auto &[SRI, SubReg] : Map)
if (Orphans.erase(SubReg))
SubRegs[RegBank.getCompositeSubRegIndex(Idx, SRI)] = SubReg;
}
// Compute the inverse SubReg -> Idx map.
for (auto &[SRI, SubReg] : SubRegs) {
if (SubReg == this) {
ArrayRef<SMLoc> Loc;
if (TheDef)
Loc = TheDef->getLoc();
PrintFatalError(Loc, "Register " + getName() +
" has itself as a sub-register");
}
// Compute AllSuperRegsCovered.
if (!CoveredBySubRegs)
SRI->AllSuperRegsCovered = false;
// Ensure that every sub-register has a unique name.
DenseMap<const CodeGenRegister *, CodeGenSubRegIndex *>::iterator Ins =
SubReg2Idx.try_emplace(SubReg, SRI).first;
if (Ins->second == SRI)
continue;
// Trouble: Two different names for SubReg.second.
ArrayRef<SMLoc> Loc;
if (TheDef)
Loc = TheDef->getLoc();
PrintFatalError(Loc, "Sub-register can't have two names: " +
SubReg->getName() + " available as " +
SRI->getName() + " and " + Ins->second->getName());
}
// Derive possible names for sub-register concatenations from any explicit
// sub-registers. By doing this before computeSecondarySubRegs(), we ensure
// that getConcatSubRegIndex() won't invent any concatenated indices that the
// user already specified.
for (auto [Idx, SR] : enumerate(ExplicitSubRegs)) {
if (!SR->CoveredBySubRegs || SR->Artificial)
continue;
// SR is composed of multiple sub-regs. Find their names in this register.
bool AnyArtificial = false;
SmallVector<CodeGenSubRegIndex *, 8> Parts;
for (unsigned j = 0, e = SR->ExplicitSubRegs.size(); j != e; ++j) {
CodeGenSubRegIndex &I = *SR->ExplicitSubRegIndices[j];
if (I.Artificial) {
AnyArtificial = true;
break;
}
Parts.push_back(getSubRegIndex(SR->ExplicitSubRegs[j]));
}
if (AnyArtificial)
continue;
// Offer this as an existing spelling for the concatenation of Parts.
ExplicitSubRegIndices[Idx]->setConcatenationOf(Parts);
}
// Initialize RegUnitList. Because getSubRegs is called recursively, this
// processes the register hierarchy in postorder.
if (ExplicitSubRegs.empty()) {
// Create one register unit per leaf register. These units correspond to the
// maximal cliques in the register overlap graph which is optimal.
RegUnits.set(RegBank.newRegUnit(this));
} else {
// Inherit all sub-register units. It is good enough to look at the explicit
// sub-registers, the other registers won't contribute any more units.
for (const CodeGenRegister *SR : ExplicitSubRegs)
RegUnits |= SR->RegUnits;
}
// When there is ad hoc aliasing, we simply create one unit per edge in the
// undirected ad hoc aliasing graph. Technically, we could do better by
// identifying maximal cliques in the ad hoc graph, but cliques larger than 2
// are extremely rare anyway (I've never seen one), so we don't bother with
// the added complexity.
for (CodeGenRegister *AR : ExplicitAliases) {
// Only visit each edge once.
if (AR->SubRegsComplete)
continue;
// Create a RegUnit representing this alias edge, and add it to both
// registers.
unsigned Unit = RegBank.newRegUnit(this, AR);
RegUnits.set(Unit);
AR->RegUnits.set(Unit);
}
// We have now computed the native register units. More may be adopted later
// for balancing purposes.
NativeRegUnits = RegUnits;
return SubRegs;
}
// In a register that is covered by its sub-registers, try to find redundant
// sub-registers. For example:
//
// QQ0 = {Q0, Q1}
// Q0 = {D0, D1}
// Q1 = {D2, D3}
//
// We can infer that D1_D2 is also a sub-register, even if it wasn't named in
// the register definition.
//
// The explicitly specified registers form a tree. This function discovers
// sub-register relationships that would force a DAG.
//
void CodeGenRegister::computeSecondarySubRegs(CodeGenRegBank &RegBank) {
SmallVector<SubRegMap::value_type, 8> NewSubRegs;
std::queue<std::pair<CodeGenSubRegIndex *, CodeGenRegister *>> SubRegQueue;
for (auto [SRI, SubReg] : SubRegs)
SubRegQueue.emplace(SRI, SubReg);
// Look at the leading super-registers of each sub-register. Those are the
// candidates for new sub-registers, assuming they are fully contained in
// this register.
while (!SubRegQueue.empty()) {
auto [SubRegIdx, SubReg] = SubRegQueue.front();
SubRegQueue.pop();
const CodeGenRegister::SuperRegList &Leads = SubReg->LeadingSuperRegs;
for (const CodeGenRegister *Cand : Leads) {
// Already got this sub-register?
if (Cand == this || getSubRegIndex(Cand))
continue;
// Check if each component of Cand is already a sub-register.
assert(!Cand->ExplicitSubRegs.empty() &&
"Super-register has no sub-registers");
if (Cand->ExplicitSubRegs.size() == 1)
continue;
SmallVector<CodeGenSubRegIndex *, 8> Parts;
// We know that the first component is (SubRegIdx,SubReg). However we
// may still need to split it into smaller subregister parts.
assert(Cand->ExplicitSubRegs[0] == SubReg && "LeadingSuperRegs correct");
assert(getSubRegIndex(SubReg) == SubRegIdx && "LeadingSuperRegs correct");
for (CodeGenRegister *SubReg : Cand->ExplicitSubRegs) {
if (CodeGenSubRegIndex *SubRegIdx = getSubRegIndex(SubReg)) {
if (SubRegIdx->ConcatenationOf.empty())
Parts.push_back(SubRegIdx);
else
append_range(Parts, SubRegIdx->ConcatenationOf);
} else {
// Sub-register doesn't exist.
Parts.clear();
break;
}
}
// There is nothing to do if some Cand sub-register is not part of this
// register.
if (Parts.empty())
continue;
// Each part of Cand is a sub-register of this. Make the full Cand also
// a sub-register with a concatenated sub-register index.
CodeGenSubRegIndex *Concat =
RegBank.getConcatSubRegIndex(Parts, RegBank.getHwModes());
std::pair<CodeGenSubRegIndex *, CodeGenRegister *> NewSubReg = {
Concat, const_cast<CodeGenRegister *>(Cand)};
if (!SubRegs.insert(NewSubReg).second)
continue;
// We inserted a new subregister.
NewSubRegs.push_back(NewSubReg);
SubRegQueue.push(NewSubReg);
SubReg2Idx.try_emplace(Cand, Concat);
}
}
// Create sub-register index composition maps for the synthesized indices.
for (auto [NewIdx, NewSubReg] : NewSubRegs) {
for (auto [SRI, SubReg] : NewSubReg->SubRegs) {
CodeGenSubRegIndex *SubIdx = getSubRegIndex(SubReg);
if (!SubIdx)
PrintFatalError(TheDef->getLoc(), "No SubRegIndex for " +
SubReg->getName() + " in " +
getName());
NewIdx->addComposite(SRI, SubIdx, RegBank.getHwModes());
}
}
}
void CodeGenRegister::computeSuperRegs(CodeGenRegBank &RegBank) {
// Only visit each register once.
if (SuperRegsComplete)
return;
SuperRegsComplete = true;
// Make sure all sub-registers have been visited first, so the super-reg
// lists will be topologically ordered.
for (auto SubReg : SubRegs)
SubReg.second->computeSuperRegs(RegBank);
// Now add this as a super-register on all sub-registers.
// Also compute the TopoSigId in post-order.
TopoSigId Id;
for (auto SubReg : SubRegs) {
// Topological signature computed from SubIdx, TopoId(SubReg).
// Loops and idempotent indices have TopoSig = ~0u.
Id.push_back(SubReg.first->EnumValue);
Id.push_back(SubReg.second->TopoSig);
// Don't add duplicate entries.
if (!SubReg.second->SuperRegs.empty() &&
SubReg.second->SuperRegs.back() == this)
continue;
SubReg.second->SuperRegs.push_back(this);
}
TopoSig = RegBank.getTopoSig(Id);
}
void CodeGenRegister::addSubRegsPreOrder(
SetVector<const CodeGenRegister *> &OSet, CodeGenRegBank &RegBank) const {
assert(SubRegsComplete && "Must precompute sub-registers");
for (CodeGenRegister *SR : ExplicitSubRegs) {
if (OSet.insert(SR))
SR->addSubRegsPreOrder(OSet, RegBank);
}
// Add any secondary sub-registers that weren't part of the explicit tree.
OSet.insert_range(llvm::make_second_range(SubRegs));
}
// Get the sum of this register's unit weights.
unsigned CodeGenRegister::getWeight(const CodeGenRegBank &RegBank) const {
unsigned Weight = 0;
for (unsigned RegUnit : RegUnits)
Weight += RegBank.getRegUnit(RegUnit).Weight;
return Weight;
}
//===----------------------------------------------------------------------===//
// RegisterTuples
//===----------------------------------------------------------------------===//
// A RegisterTuples def is used to generate pseudo-registers from lists of
// sub-registers. We provide a SetTheory expander class that returns the new
// registers.
namespace {
struct TupleExpander : SetTheory::Expander {
// Reference to SynthDefs in the containing CodeGenRegBank, to keep track of
// the synthesized definitions for their lifetime.
std::vector<std::unique_ptr<Record>> &SynthDefs;
// Track all synthesized tuple names in order to detect duplicate definitions.
llvm::StringSet<> TupleNames;
TupleExpander(std::vector<std::unique_ptr<Record>> &SynthDefs)
: SynthDefs(SynthDefs) {}
void expand(SetTheory &ST, const Record *Def,
SetTheory::RecSet &Elts) override {
std::vector<const Record *> Indices =
Def->getValueAsListOfDefs("SubRegIndices");
unsigned Dim = Indices.size();
const ListInit *SubRegs = Def->getValueAsListInit("SubRegs");
// Evaluate the sub-register lists to be zipped.
unsigned Length = ~0u;
SmallVector<SetTheory::RecSet, 4> Lists(Dim);
for (unsigned i = 0; i != Dim; ++i) {
ST.evaluate(SubRegs->getElement(i), Lists[i], Def->getLoc());
Length = std::min(Length, unsigned(Lists[i].size()));
}
if (Length == 0)
return;
// Precompute some types.
const Record *RegisterCl = Def->getRecords().getClass("Register");
const RecTy *RegisterRecTy = RecordRecTy::get(RegisterCl);
std::vector<StringRef> RegNames =
Def->getValueAsListOfStrings("RegAsmNames");
// Zip them up.
RecordKeeper &RK = Def->getRecords();
for (unsigned n = 0; n != Length; ++n) {
std::string Name;
const Record *Proto = Lists[0][n];
std::vector<Init *> Tuple;
for (unsigned i = 0; i != Dim; ++i) {
const Record *Reg = Lists[i][n];
if (i)
Name += '_';
Name += Reg->getName();
Tuple.push_back(Reg->getDefInit());
}
// Take the cost list of the first register in the tuple.
const ListInit *CostList = Proto->getValueAsListInit("CostPerUse");
SmallVector<const Init *, 2> CostPerUse(CostList->getElements());
const StringInit *AsmName = StringInit::get(RK, "");
if (!RegNames.empty()) {
if (RegNames.size() <= n)
PrintFatalError(Def->getLoc(),
"Register tuple definition missing name for '" +
Name + "'.");
AsmName = StringInit::get(RK, RegNames[n]);
}
// Create a new Record representing the synthesized register. This record
// is only for consumption by CodeGenRegister, it is not added to the
// RecordKeeper.
SynthDefs.emplace_back(
std::make_unique<Record>(Name, Def->getLoc(), Def->getRecords()));
Record *NewReg = SynthDefs.back().get();
Elts.insert(NewReg);
// Detect duplicates among synthesized registers.
const auto Res = TupleNames.insert(NewReg->getName());
if (!Res.second)
PrintFatalError(Def->getLoc(),
"Register tuple redefines register '" + Name + "'.");
// Copy Proto super-classes.
for (const auto &[Super, Loc] : Proto->getDirectSuperClasses())
NewReg->addDirectSuperClass(Super, Loc);
// Copy Proto fields.
for (RecordVal RV : Proto->getValues()) {
// Skip existing fields, like NAME.
if (NewReg->getValue(RV.getNameInit()))
continue;
StringRef Field = RV.getName();
// Replace the sub-register list with Tuple.
if (Field == "SubRegs")
RV.setValue(ListInit::get(Tuple, RegisterRecTy));
if (Field == "AsmName")
RV.setValue(AsmName);
// CostPerUse is aggregated from all Tuple members.
if (Field == "CostPerUse")
RV.setValue(ListInit::get(CostPerUse, CostList->getElementType()));
// Composite registers are always covered by sub-registers.
if (Field == "CoveredBySubRegs")
RV.setValue(BitInit::get(RK, true));
// Copy fields from the RegisterTuples def.
if (Field == "SubRegIndices") {
NewReg->addValue(*Def->getValue(Field));
continue;
}
// Some fields get their default uninitialized value.
if (Field == "DwarfNumbers" || Field == "DwarfAlias" ||
Field == "Aliases") {
if (const RecordVal *DefRV = RegisterCl->getValue(Field))
NewReg->addValue(*DefRV);
continue;
}
// Everything else is copied from Proto.
NewReg->addValue(RV);
}
}
}
};
} // end anonymous namespace
//===----------------------------------------------------------------------===//
// CodeGenRegisterClass
//===----------------------------------------------------------------------===//
static void sortAndUniqueRegisters(CodeGenRegister::Vec &M) {
llvm::sort(M, deref<std::less<>>());
M.erase(llvm::unique(M, deref<std::equal_to<>>()), M.end());
}
CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank,
const Record *R)
: TheDef(R), Name(R->getName().str()),
RegsWithSuperRegsTopoSigs(RegBank.getNumTopoSigs()), EnumValue(-1),
TSFlags(0) {
GeneratePressureSet = R->getValueAsBit("GeneratePressureSet");
for (const Record *Type : R->getValueAsListOfDefs("RegTypes"))
VTs.push_back(getValueTypeByHwMode(Type, RegBank.getHwModes()));
// Allocation order 0 is the full set. AltOrders provides others.
const SetTheory::RecVec *Elements = RegBank.getSets().expand(R);
const ListInit *AltOrders = R->getValueAsListInit("AltOrders");
Orders.resize(1 + AltOrders->size());
// Default allocation order always contains all registers.
MemberBV.resize(RegBank.getRegisters().size());
Artificial = true;
for (const Record *Element : *Elements) {
Orders[0].push_back(Element);
const CodeGenRegister *Reg = RegBank.getReg(Element);
Members.push_back(Reg);
MemberBV.set(CodeGenRegBank::getRegIndex(Reg));
Artificial &= Reg->Artificial;
if (!Reg->getSuperRegs().empty())
RegsWithSuperRegsTopoSigs.set(Reg->getTopoSig());
}
sortAndUniqueRegisters(Members);
// Alternative allocation orders may be subsets.
SetTheory::RecSet Order;
for (auto [Idx, AltOrderElem] : enumerate(AltOrders->getElements())) {
RegBank.getSets().evaluate(AltOrderElem, Order, R->getLoc());
Orders[1 + Idx].append(Order.begin(), Order.end());
// Verify that all altorder members are regclass members.
while (!Order.empty()) {
CodeGenRegister *Reg = RegBank.getReg(Order.back());
Order.pop_back();
if (!contains(Reg))
PrintFatalError(R->getLoc(), " AltOrder register " + Reg->getName() +
" is not a class member");
}
}
Namespace = R->getValueAsString("Namespace");
if (const Record *RV = R->getValueAsOptionalDef("RegInfos"))
RSI = RegSizeInfoByHwMode(RV, RegBank.getHwModes());
unsigned Size = R->getValueAsInt("Size");
if (!RSI.hasDefault() && Size == 0 && !VTs[0].isSimple())
PrintFatalError(R->getLoc(), "Impossible to determine register size");
if (!RSI.hasDefault()) {
RegSizeInfo RI;
RI.RegSize = RI.SpillSize =
Size ? Size : VTs[0].getSimple().getSizeInBits();
RI.SpillAlignment = R->getValueAsInt("Alignment");
RSI.insertRegSizeForMode(DefaultMode, RI);
}
int CopyCostParsed = R->getValueAsInt("CopyCost");
Allocatable = R->getValueAsBit("isAllocatable");
AltOrderSelect = R->getValueAsString("AltOrderSelect");
int AllocationPriority = R->getValueAsInt("AllocationPriority");
if (!isUInt<5>(AllocationPriority))
PrintFatalError(R->getLoc(), "AllocationPriority out of range [0,31]");
this->AllocationPriority = AllocationPriority;
GlobalPriority = R->getValueAsBit("GlobalPriority");
const BitsInit *TSF = R->getValueAsBitsInit("TSFlags");
TSFlags = uint8_t(*TSF->convertInitializerToInt());
// Saturate negative costs to the maximum
if (CopyCostParsed < 0)
CopyCost = std::numeric_limits<uint8_t>::max();
else if (!isUInt<8>(CopyCostParsed))
PrintFatalError(R->getLoc(), "'CopyCost' must be an 8-bit value");
CopyCost = CopyCostParsed;
}
// Create an inferred register class that was missing from the .td files.
// Most properties will be inherited from the closest super-class after the
// class structure has been computed.
CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank,
StringRef Name, Key Props)
: Members(*Props.Members), TheDef(nullptr), Name(Name.str()),
RegsWithSuperRegsTopoSigs(RegBank.getNumTopoSigs()), EnumValue(-1),
RSI(Props.RSI), CopyCost(0), Allocatable(true), AllocationPriority(0),
GlobalPriority(false), TSFlags(0) {
MemberBV.resize(RegBank.getRegisters().size());
Artificial = true;
GeneratePressureSet = false;
for (const auto R : Members) {
MemberBV.set(CodeGenRegBank::getRegIndex(R));
if (!R->getSuperRegs().empty())
RegsWithSuperRegsTopoSigs.set(R->getTopoSig());
Artificial &= R->Artificial;
}
}
// Compute inherited properties for a synthesized register class.
void CodeGenRegisterClass::inheritProperties(CodeGenRegBank &RegBank) {
assert(!getDef() && "Only synthesized classes can inherit properties");
assert(!SuperClasses.empty() && "Synthesized class without super class");
// The last super-class is the smallest one in topological order. Check for
// allocatable super-classes and inherit from the nearest allocatable one if
// any.
auto NearestAllocSCRIt =
find_if(reverse(SuperClasses),
[&](const CodeGenRegisterClass *S) { return S->Allocatable; });
CodeGenRegisterClass &Super = NearestAllocSCRIt == SuperClasses.rend()
? *SuperClasses.back()
: **NearestAllocSCRIt;
// Most properties are copied directly.
// Exceptions are members, size, and alignment
Namespace = Super.Namespace;
VTs = Super.VTs;
CopyCost = Super.CopyCost;
Allocatable = Super.Allocatable;
AltOrderSelect = Super.AltOrderSelect;
AllocationPriority = Super.AllocationPriority;
GlobalPriority = Super.GlobalPriority;
TSFlags = Super.TSFlags;
GeneratePressureSet |= Super.GeneratePressureSet;
// Copy all allocation orders, filter out foreign registers from the larger
// super-class.
Orders.resize(Super.Orders.size());
for (auto [Idx, Outer] : enumerate(Super.Orders))
for (const Record *Reg : Outer)
if (contains(RegBank.getReg(Reg)))
Orders[Idx].push_back(Reg);
}
bool CodeGenRegisterClass::hasType(const ValueTypeByHwMode &VT) const {
if (llvm::is_contained(VTs, VT))
return true;
// If VT is not identical to any of this class's types, but is a simple
// type, check if any of the types for this class contain it under some
// mode.
// The motivating example came from RISC-V, where (likely because of being
// guarded by "64-bit" predicate), the type of X5 was {*:[i64]}, but the
// type in GRC was {*:[i32], m1:[i64]}.
if (VT.isSimple()) {
MVT T = VT.getSimple();
for (const ValueTypeByHwMode &OurVT : VTs) {
if (llvm::is_contained(llvm::make_second_range(OurVT), T))
return true;
}
}
return false;
}
bool CodeGenRegisterClass::contains(const CodeGenRegister *Reg) const {
return MemberBV.test(CodeGenRegBank::getRegIndex(Reg));
}
unsigned CodeGenRegisterClass::getWeight(const CodeGenRegBank &RegBank) const {
if (TheDef && !TheDef->isValueUnset("Weight"))
return TheDef->getValueAsInt("Weight");
if (Members.empty() || Artificial)
return 0;
return (*Members.begin())->getWeight(RegBank);
}
// This is a simple lexicographical order that can be used to search for sets.
// It is not the same as the topological order provided by TopoOrderRC.
bool CodeGenRegisterClass::Key::operator<(
const CodeGenRegisterClass::Key &B) const {
assert(Members && B.Members);
if (!IgnoreArtificialMembers)
return std::tie(*Members, RSI) < std::tie(*B.Members, B.RSI);
// Do the same lexicographical comparison, but ignoring
// artificial registers.
auto IA = Members->begin(), EA = Members->end();
auto IB = B.Members->begin(), EB = B.Members->end();
while (IA != EA && IB != EB) {
if ((*IA)->Artificial) {
++IA;
continue;
}
if ((*IB)->Artificial) {
++IB;
continue;
}
if (*IA != *IB)
return *IA < *IB;
++IA;
++IB;
}
if (IA == EA && IB == EB)
return RSI < B.RSI;
return IA == EA;
}
// Returns true if RC is a strict subclass.
// RC is a sub-class of this class if it is a valid replacement for any
// instruction operand where a register of this classis required. It must
// satisfy these conditions:
//
// 1. All RC registers are also in this.
// 2. The RC spill size must not be smaller than our spill size.
// 3. RC spill alignment must be compatible with ours.
//
static bool testSubClass(const CodeGenRegisterClass *A,
const CodeGenRegisterClass *B) {
return A->RSI.isSubClassOf(B->RSI) &&
llvm::includes(A->getMembers(), B->getMembers(), deref<std::less<>>());
}
/// Sorting predicate for register classes. This provides a topological
/// ordering that arranges all register classes before their sub-classes.
///
/// Register classes with the same registers, spill size, and alignment form a
/// clique. They will be ordered alphabetically.
///
static bool TopoOrderRC(const CodeGenRegisterClass &A,
const CodeGenRegisterClass &B) {
if (&A == &B)
return false;
constexpr size_t SIZET_MAX = std::numeric_limits<size_t>::max();
// Sort in the following order:
// (a) first by register size in ascending order.
// (b) then by set size in descending order.
// (c) finally, by name as a tie breaker.
//
// For set size, note that the classes' allocation order may not have been
// computed yet, but the members set is always valid. Also, since we use
// std::tie() < operator for ordering, we can achieve the descending set size
// ordering by using (SIZET_MAX - set_size) in the std::tie.
return std::tuple(A.RSI, SIZET_MAX - A.getMembers().size(),
StringRef(A.getName())) <
std::tuple(B.RSI, SIZET_MAX - B.getMembers().size(),
StringRef(B.getName()));
}
std::string CodeGenRegisterClass::getNamespaceQualification() const {
return Namespace.empty() ? "" : (Namespace + "::").str();
}
std::string CodeGenRegisterClass::getQualifiedName() const {
return getNamespaceQualification() + getName();
}
std::string CodeGenRegisterClass::getIdName() const {
return getName() + "RegClassID";
}
std::string CodeGenRegisterClass::getQualifiedIdName() const {
return getNamespaceQualification() + getIdName();
}
// Compute sub-classes of all register classes.
// Assume the classes are ordered topologically.
void CodeGenRegisterClass::computeSubClasses(CodeGenRegBank &RegBank) {
std::list<CodeGenRegisterClass> &RegClasses = RegBank.getRegClasses();
const size_t NumRegClasses = RegClasses.size();
// Visit backwards so sub-classes are seen first.
for (auto I = RegClasses.rbegin(), E = RegClasses.rend(); I != E; ++I) {
CodeGenRegisterClass &RC = *I;
RC.SubClasses.resize(NumRegClasses);
RC.SubClasses.set(RC.EnumValue);
if (RC.Artificial)
continue;
// Normally, all subclasses have IDs >= rci, unless RC is part of a clique.
for (auto I2 = I.base(), E2 = RegClasses.end(); I2 != E2; ++I2) {
CodeGenRegisterClass &SubRC = *I2;
if (RC.SubClasses.test(SubRC.EnumValue))
continue;
if (!testSubClass(&RC, &SubRC))
continue;
// SubRC is a sub-class. Grap all its sub-classes so we won't have to
// check them again.
RC.SubClasses |= SubRC.SubClasses;
}
// Sweep up missed clique members. They will be immediately preceding RC.
for (auto I2 = std::next(I); I2 != E && testSubClass(&RC, &*I2); ++I2)
RC.SubClasses.set(I2->EnumValue);
}
// Compute the SuperClasses lists from the SubClasses vectors.
for (auto &RC : RegClasses) {
const BitVector &SC = RC.getSubClasses();
auto I = RegClasses.begin();
for (int s = 0, next_s = SC.find_first(); next_s != -1;
next_s = SC.find_next(s)) {
std::advance(I, next_s - s);
s = next_s;
if (&*I == &RC)
continue;
I->SuperClasses.push_back(&RC);
}
}
// With the class hierarchy in place, let synthesized register classes inherit
// properties from their closest super-class. The iteration order here can
// propagate properties down multiple levels.
for (CodeGenRegisterClass &RC : RegClasses)
if (!RC.getDef())
RC.inheritProperties(RegBank);
}
std::optional<std::pair<CodeGenRegisterClass *, CodeGenRegisterClass *>>
CodeGenRegisterClass::getMatchingSubClassWithSubRegs(
CodeGenRegBank &RegBank, const CodeGenSubRegIndex *SubIdx) const {
auto WeakSizeOrder = [this](const CodeGenRegisterClass *A,
const CodeGenRegisterClass *B) {
// If there are multiple, identical register classes, prefer the original
// register class.
if (A == B)
return false;
if (A->getMembers().size() == B->getMembers().size()) {
if (A->getBaseClassOrder() != B->getBaseClassOrder())
return A->getBaseClassOrder() > B->getBaseClassOrder();
return A == this;
}
return A->getMembers().size() > B->getMembers().size();
};
std::list<CodeGenRegisterClass> &RegClasses = RegBank.getRegClasses();
// Find all the subclasses of this one that fully support the sub-register
// index and order them by size. BiggestSuperRC should always be first.
CodeGenRegisterClass *BiggestSuperRegRC = getSubClassWithSubReg(SubIdx);
if (!BiggestSuperRegRC)
return std::nullopt;
BitVector SuperRegRCsBV = BiggestSuperRegRC->getSubClasses();
std::vector<CodeGenRegisterClass *> SuperRegRCs;
for (auto &RC : RegClasses)
if (SuperRegRCsBV[RC.EnumValue])
SuperRegRCs.emplace_back(&RC);
llvm::stable_sort(SuperRegRCs, WeakSizeOrder);
assert((SuperRegRCs.front() == BiggestSuperRegRC ||
SuperRegRCs.front()->getBaseClassOrder() >
BiggestSuperRegRC->getBaseClassOrder()) &&
"Biggest class wasn't first");
// Find all the subreg classes and order them by size too.
std::vector<std::pair<CodeGenRegisterClass *, BitVector>> SuperRegClasses;
for (auto &RC : RegClasses) {
BitVector SuperRegClassesBV(RegClasses.size());
RC.getSuperRegClasses(SubIdx, SuperRegClassesBV);
if (SuperRegClassesBV.any())
SuperRegClasses.emplace_back(&RC, SuperRegClassesBV);
}
llvm::stable_sort(SuperRegClasses,
[&](const std::pair<CodeGenRegisterClass *, BitVector> &A,
const std::pair<CodeGenRegisterClass *, BitVector> &B) {
return WeakSizeOrder(A.first, B.first);
});
// Find the biggest subclass and subreg class such that R:subidx is in the
// subreg class for all R in subclass.
//
// For example:
// All registers in X86's GR64 have a sub_32bit subregister but no class
// exists that contains all the 32-bit subregisters because GR64 contains RIP
// but GR32 does not contain EIP. Instead, we constrain SuperRegRC to
// GR32_with_sub_8bit (which is identical to GR32_with_sub_32bit) and then,
// having excluded RIP, we are able to find a SubRegRC (GR32).
CodeGenRegisterClass *ChosenSuperRegClass = nullptr;
CodeGenRegisterClass *SubRegRC = nullptr;
for (CodeGenRegisterClass *SuperRegRC : SuperRegRCs) {
for (const auto &[SuperRegClass, SuperRegClassBV] : SuperRegClasses) {
if (SuperRegClassBV[SuperRegRC->EnumValue]) {
SubRegRC = SuperRegClass;
ChosenSuperRegClass = SuperRegRC;
// If SubRegRC is bigger than SuperRegRC then there are members of
// SubRegRC that don't have super registers via SubIdx. Keep looking to
// find a better fit and fall back on this one if there isn't one.
//
// This is intended to prevent X86 from making odd choices such as
// picking LOW32_ADDR_ACCESS_RBP instead of GR32 in the example above.
// LOW32_ADDR_ACCESS_RBP is a valid choice but contains registers that
// aren't subregisters of SuperRegRC whereas GR32 has a direct 1:1
// mapping.
if (SuperRegRC->getMembers().size() >= SubRegRC->getMembers().size())
return std::pair(ChosenSuperRegClass, SubRegRC);
}
}
// If we found a fit but it wasn't quite ideal because SubRegRC had excess
// registers, then we're done.
if (ChosenSuperRegClass)
return std::pair(ChosenSuperRegClass, SubRegRC);
}
return std::nullopt;
}
void CodeGenRegisterClass::getSuperRegClasses(const CodeGenSubRegIndex *SubIdx,
BitVector &Out) const {
auto FindI = SuperRegClasses.find(SubIdx);
if (FindI == SuperRegClasses.end())
return;
for (CodeGenRegisterClass *RC : FindI->second)
Out.set(RC->EnumValue);
}
// Populate a unique sorted list of units from a register set.
void CodeGenRegisterClass::buildRegUnitSet(
const CodeGenRegBank &RegBank, std::vector<unsigned> &RegUnits) const {
std::vector<unsigned> TmpUnits;
for (const CodeGenRegister *Reg : Members) {
for (unsigned UnitI : Reg->getRegUnits()) {
const RegUnit &RU = RegBank.getRegUnit(UnitI);
if (!RU.Artificial)
TmpUnits.push_back(UnitI);
}
}
llvm::sort(TmpUnits);
std::unique_copy(TmpUnits.begin(), TmpUnits.end(),
std::back_inserter(RegUnits));
}
// Combine our super classes of the given sub-register index with all of their
// super classes in turn.
void CodeGenRegisterClass::extendSuperRegClasses(CodeGenSubRegIndex *SubIdx) {
auto It = SuperRegClasses.find(SubIdx);
if (It == SuperRegClasses.end())
return;
SmallVector<CodeGenRegisterClass *> MidRCs;
llvm::append_range(MidRCs, It->second);
for (CodeGenRegisterClass *MidRC : MidRCs) {
for (auto &Pair : MidRC->SuperRegClasses) {
CodeGenSubRegIndex *ComposedSubIdx = Pair.first->compose(SubIdx);
if (!ComposedSubIdx)
continue;
for (CodeGenRegisterClass *SuperRC : Pair.second)
addSuperRegClass(ComposedSubIdx, SuperRC);
}
}
}
//===----------------------------------------------------------------------===//
// CodeGenRegisterCategory
//===----------------------------------------------------------------------===//
CodeGenRegisterCategory::CodeGenRegisterCategory(CodeGenRegBank &RegBank,
const Record *R)
: TheDef(R), Name(R->getName().str()) {
for (const Record *RegClass : R->getValueAsListOfDefs("Classes"))
Classes.push_back(RegBank.getRegClass(RegClass));
}
//===----------------------------------------------------------------------===//
// CodeGenRegBank
//===----------------------------------------------------------------------===//
CodeGenRegBank::CodeGenRegBank(const RecordKeeper &Records,
const CodeGenHwModes &Modes,
const bool RegistersAreIntervals)
: Records(Records), CGH(Modes),
RegistersAreIntervals(RegistersAreIntervals) {
// Configure register Sets to understand register classes and tuples.
Sets.addFieldExpander("RegisterClass", "MemberList");
Sets.addFieldExpander("CalleeSavedRegs", "SaveList");
Sets.addExpander("RegisterTuples",
std::make_unique<TupleExpander>(SynthDefs));
// Read in the user-defined (named) sub-register indices.
// More indices will be synthesized later.
for (const Record *SRI : Records.getAllDerivedDefinitions("SubRegIndex"))
getSubRegIdx(SRI);
// Build composite maps from ComposedOf fields.
for (auto &Idx : SubRegIndices)
Idx.updateComponents(*this);
// Read in the register and register tuple definitions.
const RecordKeeper &RC = Records;
std::vector<const Record *> Regs = RC.getAllDerivedDefinitions("Register");
if (!Regs.empty() && Regs[0]->isSubClassOf("X86Reg")) {
// For X86, we need to sort Registers and RegisterTuples together to list
// new registers and register tuples at a later position. So that we can
// reduce unnecessary iterations on unsupported registers in LiveVariables.
// TODO: Remove this logic when migrate from LiveVariables to LiveIntervals
// completely.
for (const Record *R : Records.getAllDerivedDefinitions("RegisterTuples")) {
// Expand tuples and merge the vectors
std::vector<const Record *> TupRegs = *Sets.expand(R);
llvm::append_range(Regs, TupRegs);
}
llvm::sort(Regs, LessRecordRegister());
// Assign the enumeration values.
for (const Record *Reg : Regs)
getReg(Reg);
} else {
llvm::sort(Regs, LessRecordRegister());
// Assign the enumeration values.
for (const Record *Reg : Regs)
getReg(Reg);
// Expand tuples and number the new registers.
for (const Record *R : Records.getAllDerivedDefinitions("RegisterTuples")) {
std::vector<const Record *> TupRegs = *Sets.expand(R);
llvm::sort(TupRegs, LessRecordRegister());
for (const Record *RC : TupRegs)
getReg(RC);
}
}
// Now all the registers are known. Build the object graph of explicit
// register-register references.
for (CodeGenRegister &Reg : Registers)
Reg.buildObjectGraph(*this);
// Compute register name map.
for (CodeGenRegister &Reg : Registers)
// FIXME: This could just be RegistersByName[name] = register, except that
// causes some failures in MIPS - perhaps they have duplicate register name
// entries? (or maybe there's a reason for it - I don't know much about this
// code, just drive-by refactoring)
RegistersByName.try_emplace(Reg.TheDef->getValueAsString("AsmName"), &Reg);
// Precompute all sub-register maps.
// This will create Composite entries for all inferred sub-register indices.
for (CodeGenRegister &Reg : Registers)
Reg.computeSubRegs(*this);
// Compute transitive closure of subregister index ConcatenationOf vectors
// and initialize ConcatIdx map.
for (CodeGenSubRegIndex &SRI : SubRegIndices) {
SRI.computeConcatTransitiveClosure();
if (!SRI.ConcatenationOf.empty())
ConcatIdx.try_emplace(
SmallVector<CodeGenSubRegIndex *, 8>(SRI.ConcatenationOf.begin(),
SRI.ConcatenationOf.end()),
&SRI);
}
// Infer even more sub-registers by combining leading super-registers.
for (CodeGenRegister &Reg : Registers)
if (Reg.CoveredBySubRegs)
Reg.computeSecondarySubRegs(*this);
// After the sub-register graph is complete, compute the topologically
// ordered SuperRegs list.
for (CodeGenRegister &Reg : Registers)
Reg.computeSuperRegs(*this);
// For each pair of Reg:SR, if both are non-artificial, mark the
// corresponding sub-register index as non-artificial.
for (CodeGenRegister &Reg : Registers) {
if (Reg.Artificial)
continue;
for (auto [SRI, SR] : Reg.getSubRegs()) {
if (!SR->Artificial)
SRI->Artificial = false;
}
}
computeSubRegIndicesRPOT();
// Native register units are associated with a leaf register. They've all been
// discovered now.
NumNativeRegUnits = RegUnits.size();
// Read in register class definitions.
ArrayRef<const Record *> RCs =
Records.getAllDerivedDefinitions("RegisterClass");
if (RCs.empty())
PrintFatalError("No 'RegisterClass' subclasses defined!");
// Allocate user-defined register classes.
for (const Record *R : RCs) {
RegClasses.emplace_back(*this, R);
CodeGenRegisterClass &RC = RegClasses.back();
if (!RC.Artificial)
addToMaps(&RC);
}
// Infer missing classes to create a full algebra.
computeInferredRegisterClasses();
// Order register classes topologically and assign enum values.
RegClasses.sort(TopoOrderRC);
for (auto [Idx, RC] : enumerate(RegClasses))
RC.EnumValue = Idx;
CodeGenRegisterClass::computeSubClasses(*this);
// Read in the register category definitions.
for (const Record *R : Records.getAllDerivedDefinitions("RegisterCategory"))
RegCategories.emplace_back(*this, R);
}
// Create a synthetic CodeGenSubRegIndex without a corresponding Record.
CodeGenSubRegIndex *CodeGenRegBank::createSubRegIndex(StringRef Name,
StringRef Namespace) {
SubRegIndices.emplace_back(Name, Namespace, SubRegIndices.size() + 1);
return &SubRegIndices.back();
}
CodeGenSubRegIndex *CodeGenRegBank::getSubRegIdx(const Record *Def) {
CodeGenSubRegIndex *&Idx = Def2SubRegIdx[Def];
if (Idx)
return Idx;
SubRegIndices.emplace_back(Def, SubRegIndices.size() + 1, getHwModes());
Idx = &SubRegIndices.back();
return Idx;
}
const CodeGenSubRegIndex *
CodeGenRegBank::findSubRegIdx(const Record *Def) const {
return Def2SubRegIdx.at(Def);
}
CodeGenRegister *CodeGenRegBank::getReg(const Record *Def) {
CodeGenRegister *&Reg = Def2Reg[Def];
if (Reg)
return Reg;
Registers.emplace_back(Def, Registers.size() + 1);
Reg = &Registers.back();
return Reg;
}
void CodeGenRegBank::addToMaps(CodeGenRegisterClass *RC) {
if (const Record *Def = RC->getDef())
Def2RC.try_emplace(Def, RC);
// Duplicate classes are rejected by insert().
// That's OK, we only care about the properties handled by CGRC::Key.
CodeGenRegisterClass::Key K(*RC, /*IgnoreArtificialMembers=*/true);
Key2RC.try_emplace(K, RC);
}
// Create a synthetic sub-class if it is missing.
std::pair<CodeGenRegisterClass *, bool>
CodeGenRegBank::getOrCreateSubClass(const CodeGenRegisterClass *RC,
const CodeGenRegister::Vec *Members,
StringRef Name) {
// Synthetic sub-class has the same size and alignment as RC.
CodeGenRegisterClass::Key K(Members, RC->RSI,
/*IgnoreArtificialMembers=*/true);
RCKeyMap::const_iterator FoundI = Key2RC.find(K);
if (FoundI != Key2RC.end())
return {FoundI->second, false};
// Sub-class doesn't exist, create a new one.
RegClasses.emplace_back(*this, Name, K);
addToMaps(&RegClasses.back());
return {&RegClasses.back(), true};
}
CodeGenRegisterClass *CodeGenRegBank::getRegClass(const Record *Def,
ArrayRef<SMLoc> Loc) const {
assert(Def->isSubClassOf("RegisterClassLike"));
if (CodeGenRegisterClass *RC = Def2RC.lookup(Def))
return RC;
ArrayRef<SMLoc> DiagLoc = Loc.empty() ? Def->getLoc() : Loc;
// TODO: Ideally we should update the API to allow resolving HwMode.
if (Def->isSubClassOf("RegClassByHwMode"))
PrintError(DiagLoc, "cannot resolve HwMode for " + Def->getName());
else
PrintError(DiagLoc, Def->getName() + " is not a known RegisterClass!");
PrintFatalNote(Def->getLoc(), Def->getName() + " defined here");
}
CodeGenSubRegIndex *
CodeGenRegBank::getCompositeSubRegIndex(CodeGenSubRegIndex *A,
CodeGenSubRegIndex *B) {
// Look for an existing entry.
CodeGenSubRegIndex *Comp = A->compose(B);
if (Comp)
return Comp;
// None exists, synthesize one.
std::string Name = A->getName() + "_then_" + B->getName();
Comp = createSubRegIndex(Name, A->getNamespace());
A->addComposite(B, Comp, getHwModes());
return Comp;
}
CodeGenSubRegIndex *CodeGenRegBank::getConcatSubRegIndex(
const SmallVector<CodeGenSubRegIndex *, 8> &Parts,
const CodeGenHwModes &CGH) {
assert(Parts.size() > 1 && "Need two parts to concatenate");
#ifndef NDEBUG
for (CodeGenSubRegIndex *Idx : Parts) {
assert(Idx->ConcatenationOf.empty() && "No transitive closure?");
}
#endif
// Look for an existing entry.
CodeGenSubRegIndex *&Idx = ConcatIdx[Parts];
if (Idx)
return Idx;
// None exists, synthesize one.
std::string Name = Parts.front()->getName();
const unsigned UnknownSize = (uint16_t)-1;
for (const CodeGenSubRegIndex *Part : ArrayRef(Parts).drop_front()) {
Name += '_';
Name += Part->getName();
}
Idx = createSubRegIndex(Name, Parts.front()->getNamespace());
Idx->ConcatenationOf.assign(Parts.begin(), Parts.end());
unsigned NumModes = CGH.getNumModeIds();
for (unsigned M = 0; M < NumModes; ++M) {
const CodeGenSubRegIndex *FirstPart = Parts.front();
// Determine whether all parts are contiguous.
bool IsContinuous = true;
const SubRegRange &FirstPartRange = FirstPart->Range.get(M);
unsigned Size = FirstPartRange.Size;
unsigned LastOffset = FirstPartRange.Offset;
unsigned LastSize = FirstPartRange.Size;
for (const CodeGenSubRegIndex *Part : ArrayRef(Parts).drop_front()) {
const SubRegRange &PartRange = Part->Range.get(M);
if (Size == UnknownSize || PartRange.Size == UnknownSize)
Size = UnknownSize;
else
Size += PartRange.Size;
if (LastSize == UnknownSize ||
PartRange.Offset != (LastOffset + LastSize))
IsContinuous = false;
LastOffset = PartRange.Offset;
LastSize = PartRange.Size;
}
unsigned Offset = IsContinuous ? FirstPartRange.Offset : -1;
Idx->Range.get(M) = SubRegRange(Size, Offset);
}
return Idx;
}
void CodeGenRegBank::computeComposites() {
using RegMap = std::map<const CodeGenRegister *, const CodeGenRegister *>;
// Subreg -> { Reg->Reg }, where the right-hand side is the mapping from
// register to (sub)register associated with the action of the left-hand
// side subregister.
std::map<const CodeGenSubRegIndex *, RegMap> SubRegAction;
for (const CodeGenRegister &R : Registers) {
const CodeGenRegister::SubRegMap &SM = R.getSubRegs();
for (auto [SRI, SubReg] : SM)
SubRegAction[SRI].try_emplace(&R, SubReg);
}
// Calculate the composition of two subregisters as compositions of their
// associated actions.
auto compose = [&SubRegAction](const CodeGenSubRegIndex *Sub1,
const CodeGenSubRegIndex *Sub2) {
RegMap C;
const RegMap &Img1 = SubRegAction.at(Sub1);
const RegMap &Img2 = SubRegAction.at(Sub2);
for (auto [R, SubReg] : Img1) {
auto F = Img2.find(SubReg);
if (F != Img2.end())
C.try_emplace(R, F->second);
}
return C;
};
// Check if the two maps agree on the intersection of their domains.
auto agree = [](const RegMap &Map1, const RegMap &Map2) {
// Technically speaking, an empty map agrees with any other map, but
// this could flag false positives. We're interested in non-vacuous
// agreements.
if (Map1.empty() || Map2.empty())
return false;
for (auto [K, V] : Map1) {
auto F = Map2.find(K);
if (F == Map2.end() || V != F->second)
return false;
}
return true;
};
using CompositePair =
std::pair<const CodeGenSubRegIndex *, const CodeGenSubRegIndex *>;
SmallSet<CompositePair, 4> UserDefined;
for (const CodeGenSubRegIndex &Idx : SubRegIndices)
for (auto P : Idx.getComposites())
UserDefined.insert({&Idx, P.first});
// Keep track of TopoSigs visited. We only need to visit each TopoSig once,
// and many registers will share TopoSigs on regular architectures.
BitVector TopoSigs(getNumTopoSigs());
for (const CodeGenRegister &Reg1 : Registers) {
// Skip identical subreg structures already processed.
if (TopoSigs.test(Reg1.getTopoSig()))
continue;
TopoSigs.set(Reg1.getTopoSig());
const CodeGenRegister::SubRegMap &SRM1 = Reg1.getSubRegs();
for (auto [Idx1, Reg2] : SRM1) {
// Ignore identity compositions.
if (&Reg1 == Reg2)
continue;
const CodeGenRegister::SubRegMap &SRM2 = Reg2->getSubRegs();
// Try composing Idx1 with another SubRegIndex.
for (auto I2 : SRM2) {
CodeGenSubRegIndex *Idx2 = I2.first;
CodeGenRegister *Reg3 = I2.second;
// Ignore identity compositions.
if (Reg2 == Reg3)
continue;
// OK Reg1:IdxPair == Reg3. Find the index with Reg:Idx == Reg3.
CodeGenSubRegIndex *Idx3 = Reg1.getSubRegIndex(Reg3);
assert(Idx3 && "Sub-register doesn't have an index");
// Conflicting composition? Emit a warning but allow it.
if (CodeGenSubRegIndex *Prev =
Idx1->addComposite(Idx2, Idx3, getHwModes())) {
// If the composition was not user-defined, always emit a warning.
if (!UserDefined.contains({Idx1, Idx2}) ||
agree(compose(Idx1, Idx2), SubRegAction.at(Idx3)))
PrintWarning(Twine("SubRegIndex ") + Idx1->getQualifiedName() +
" and " + Idx2->getQualifiedName() +
" compose ambiguously as " + Prev->getQualifiedName() +
" or " + Idx3->getQualifiedName());
}
}
}
}
}
// Compute lane masks. This is similar to register units, but at the
// sub-register index level. Each bit in the lane mask is like a register unit
// class, and two lane masks will have a bit in common if two sub-register
// indices overlap in some register.
//
// Conservatively share a lane mask bit if two sub-register indices overlap in
// some registers, but not in others. That shouldn't happen a lot.
void CodeGenRegBank::computeSubRegLaneMasks() {
// First assign individual bits to all the leaf indices.
unsigned Bit = 0;
// Determine mask of lanes that cover their registers.
CoveringLanes = LaneBitmask::getAll();
for (CodeGenSubRegIndex &Idx : SubRegIndices) {
if (Idx.getComposites().empty()) {
if (Bit > LaneBitmask::BitWidth) {
PrintFatalError(
Twine("Ran out of lanemask bits to represent subregister ") +
Idx.getName());
}
Idx.LaneMask = LaneBitmask::getLane(Bit);
++Bit;
} else {
Idx.LaneMask = LaneBitmask::getNone();
}
}
// Compute transformation sequences for composeSubRegIndexLaneMask. The idea
// here is that for each possible target subregister we look at the leafs
// in the subregister graph that compose for this target and create
// transformation sequences for the lanemasks. Each step in the sequence
// consists of a bitmask and a bitrotate operation. As the rotation amounts
// are usually the same for many subregisters we can easily combine the steps
// by combining the masks.
for (const CodeGenSubRegIndex &Idx : SubRegIndices) {
const CodeGenSubRegIndex::CompMap &Composites = Idx.getComposites();
auto &LaneTransforms = Idx.CompositionLaneMaskTransform;
if (Composites.empty()) {
// Moving from a class with no subregisters we just had a single lane:
// The subregister must be a leaf subregister and only occupies 1 bit.
// Move the bit from the class without subregisters into that position.
unsigned DstBit = Idx.LaneMask.getHighestLane();
assert(Idx.LaneMask == LaneBitmask::getLane(DstBit) &&
"Must be a leaf subregister");
MaskRolPair MaskRol = {LaneBitmask::getLane(0), (uint8_t)DstBit};
LaneTransforms.push_back(MaskRol);
} else {
// Go through all leaf subregisters and find the ones that compose with
// Idx. These make out all possible valid bits in the lane mask we want to
// transform. Looking only at the leafs ensure that only a single bit in
// the mask is set.
unsigned NextBit = 0;
for (CodeGenSubRegIndex &Idx2 : SubRegIndices) {
// Skip non-leaf subregisters.
if (!Idx2.getComposites().empty())
continue;
// Replicate the behaviour from the lane mask generation loop above.
unsigned SrcBit = NextBit;
LaneBitmask SrcMask = LaneBitmask::getLane(SrcBit);
if (NextBit < LaneBitmask::BitWidth - 1)
++NextBit;
assert(Idx2.LaneMask == SrcMask);
// Get the composed subregister if there is any.
auto C = Composites.find(&Idx2);
if (C == Composites.end())
continue;
const CodeGenSubRegIndex *Composite = C->second;
// The Composed subreg should be a leaf subreg too
assert(Composite->getComposites().empty());
// Create Mask+Rotate operation and merge with existing ops if possible.
unsigned DstBit = Composite->LaneMask.getHighestLane();
int Shift = DstBit - SrcBit;
uint8_t RotateLeft =
Shift >= 0 ? (uint8_t)Shift : LaneBitmask::BitWidth + Shift;
for (MaskRolPair &I : LaneTransforms) {
if (I.RotateLeft == RotateLeft) {
I.Mask |= SrcMask;
SrcMask = LaneBitmask::getNone();
}
}
if (SrcMask.any()) {
MaskRolPair MaskRol = {SrcMask, RotateLeft};
LaneTransforms.push_back(MaskRol);
}
}
}
// Optimize if the transformation consists of one step only: Set mask to
// 0xffffffff (including some irrelevant invalid bits) so that it should
// merge with more entries later while compressing the table.
if (LaneTransforms.size() == 1)
LaneTransforms[0].Mask = LaneBitmask::getAll();
// Further compression optimization: For invalid compositions resulting
// in a sequence with 0 entries we can just pick any other. Choose
// Mask 0xffffffff with Rotation 0.
if (LaneTransforms.size() == 0) {
MaskRolPair P = {LaneBitmask::getAll(), 0};
LaneTransforms.push_back(P);
}
}
// FIXME: What if ad-hoc aliasing introduces overlaps that aren't represented
// by the sub-register graph? This doesn't occur in any known targets.
// Inherit lanes from composites.
for (const CodeGenSubRegIndex &Idx : SubRegIndices) {
LaneBitmask Mask = Idx.computeLaneMask();
// If some super-registers without CoveredBySubRegs use this index, we can
// no longer assume that the lanes are covering their registers.
if (!Idx.AllSuperRegsCovered)
CoveringLanes &= ~Mask;
}
// Compute lane mask combinations for register classes.
for (auto &RegClass : RegClasses) {
LaneBitmask LaneMask;
for (const CodeGenSubRegIndex &SubRegIndex : SubRegIndices) {
if (RegClass.getSubClassWithSubReg(&SubRegIndex) == nullptr)
continue;
LaneMask |= SubRegIndex.LaneMask;
}
// For classes without any subregisters set LaneMask to 1 instead of 0.
// This makes it easier for client code to handle classes uniformly.
if (LaneMask.none())
LaneMask = LaneBitmask::getLane(0);
RegClass.LaneMask = LaneMask;
}
}
namespace {
// A directed graph on sub-register indices with a virtual source node that
// has an arc to all other nodes, and an arc from A to B if sub-register index
// B can be obtained by composing A with some other sub-register index.
struct SubRegIndexCompositionGraph {
std::deque<CodeGenSubRegIndex> &SubRegIndices;
CodeGenSubRegIndex::CompMap EntryNode;
SubRegIndexCompositionGraph(std::deque<CodeGenSubRegIndex> &SubRegIndices)
: SubRegIndices(SubRegIndices) {
for (CodeGenSubRegIndex &Idx : SubRegIndices) {
EntryNode.try_emplace(&Idx, &Idx);
}
}
};
} // namespace
template <> struct llvm::GraphTraits<SubRegIndexCompositionGraph> {
using NodeRef =
PointerUnion<CodeGenSubRegIndex *, const CodeGenSubRegIndex::CompMap *>;
// Using a reverse iterator causes sub-register indices to appear in their
// more natural order in RPOT.
using CompMapIt = CodeGenSubRegIndex::CompMap::const_reverse_iterator;
struct ChildIteratorType
: public iterator_adaptor_base<
ChildIteratorType, CompMapIt,
std::iterator_traits<CompMapIt>::iterator_category, NodeRef> {
ChildIteratorType(CompMapIt I)
: ChildIteratorType::iterator_adaptor_base(I) {}
NodeRef operator*() const { return wrapped()->second; }
};
static NodeRef getEntryNode(const SubRegIndexCompositionGraph &G) {
return &G.EntryNode;
}
static const CodeGenSubRegIndex::CompMap *children(NodeRef N) {
if (auto *Idx = dyn_cast<CodeGenSubRegIndex *>(N))
return &Idx->getComposites();
return cast<const CodeGenSubRegIndex::CompMap *>(N);
}
static ChildIteratorType child_begin(NodeRef N) {
return ChildIteratorType(children(N)->rbegin());
}
static ChildIteratorType child_end(NodeRef N) {
return ChildIteratorType(children(N)->rend());
}
static auto nodes_begin(SubRegIndexCompositionGraph *G) {
return G->SubRegIndices.begin();
}
static auto nodes_end(SubRegIndexCompositionGraph *G) {
return G->SubRegIndices.end();
}
static unsigned size(SubRegIndexCompositionGraph *G) {
return G->SubRegIndices.size();
}
};
void CodeGenRegBank::computeSubRegIndicesRPOT() {
SubRegIndexCompositionGraph G(SubRegIndices);
ReversePostOrderTraversal<SubRegIndexCompositionGraph> RPOT(G);
for (const auto N : RPOT) {
if (auto *Idx = dyn_cast<CodeGenSubRegIndex *>(N))
SubRegIndicesRPOT.push_back(Idx);
}
}
namespace {
// UberRegSet is a helper class for computeRegUnitWeights. Each UberRegSet is
// the transitive closure of the union of overlapping register
// classes. Together, the UberRegSets form a partition of the registers. If we
// consider overlapping register classes to be connected, then each UberRegSet
// is a set of connected components.
//
// An UberRegSet will likely be a horizontal slice of register names of
// the same width. Nontrivial subregisters should then be in a separate
// UberRegSet. But this property isn't required for valid computation of
// register unit weights.
//
// A Weight field caches the max per-register unit weight in each UberRegSet.
//
// A set of SingularDeterminants flags single units of some register in this set
// for which the unit weight equals the set weight. These units should not have
// their weight increased.
struct UberRegSet {
CodeGenRegister::Vec Regs;
unsigned Weight = 0;
CodeGenRegister::RegUnitList SingularDeterminants;
UberRegSet() = default;
};
} // end anonymous namespace
// Partition registers into UberRegSets, where each set is the transitive
// closure of the union of overlapping register classes.
//
// UberRegSets[0] is a special non-allocatable set.
static void computeUberSets(std::vector<UberRegSet> &UberSets,
std::vector<UberRegSet *> &RegSets,
CodeGenRegBank &RegBank) {
const auto &Registers = RegBank.getRegisters();
// The Register EnumValue is one greater than its index into Registers.
assert(Registers.size() == Registers.back().EnumValue &&
"register enum value mismatch");
// For simplicitly make the SetID the same as EnumValue.
IntEqClasses UberSetIDs(Registers.size() + 1);
BitVector AllocatableRegs(Registers.size() + 1);
for (CodeGenRegisterClass &RegClass : RegBank.getRegClasses()) {
if (!RegClass.Allocatable)
continue;
// Ignore artificial registers. They may be members of register
// classes that together include registers and their subregisters,
// in which case it is impossible to normalize the weights of
// their register units.
CodeGenRegister::Vec Regs;
for (const CodeGenRegister *Reg : RegClass.getMembers()) {
if (!Reg->Artificial)
Regs.push_back(Reg);
}
if (Regs.empty())
continue;
unsigned USetID = UberSetIDs.findLeader((*Regs.begin())->EnumValue);
assert(USetID && "register number 0 is invalid");
AllocatableRegs.set((*Regs.begin())->EnumValue);
for (const CodeGenRegister *CGR : llvm::drop_begin(Regs)) {
AllocatableRegs.set(CGR->EnumValue);
UberSetIDs.join(USetID, CGR->EnumValue);
}
}
// Combine non-allocatable regs.
for (const CodeGenRegister &Reg : Registers) {
unsigned RegNum = Reg.EnumValue;
if (AllocatableRegs.test(RegNum))
continue;
UberSetIDs.join(0, RegNum);
}
UberSetIDs.compress();
// Make the first UberSet a special unallocatable set.
unsigned ZeroID = UberSetIDs[0];
// Insert Registers into the UberSets formed by union-find.
// Do not resize after this.
UberSets.resize(UberSetIDs.getNumClasses());
for (auto [Idx, Reg] : enumerate(Registers)) {
unsigned USetID = UberSetIDs[Reg.EnumValue];
if (!USetID)
USetID = ZeroID;
else if (USetID == ZeroID)
USetID = 0;
UberRegSet *USet = &UberSets[USetID];
USet->Regs.push_back(&Reg);
RegSets[Idx] = USet;
}
}
// Recompute each UberSet weight after changing unit weights.
static void computeUberWeights(MutableArrayRef<UberRegSet> UberSets,
CodeGenRegBank &RegBank) {
// Skip the first unallocatable set.
for (UberRegSet &S : UberSets.drop_front()) {
// Initialize all unit weights in this set, and remember the max units/reg.
unsigned MaxWeight = 0;
for (const CodeGenRegister *R : S.Regs) {
unsigned Weight = 0;
for (unsigned U : R->getRegUnits()) {
if (!RegBank.getRegUnit(U).Artificial) {
unsigned UWeight = RegBank.getRegUnit(U).Weight;
if (!UWeight) {
UWeight = 1;
RegBank.increaseRegUnitWeight(U, UWeight);
}
Weight += UWeight;
}
}
MaxWeight = std::max(MaxWeight, Weight);
}
if (S.Weight != MaxWeight) {
LLVM_DEBUG({
dbgs() << "UberSet " << &S - UberSets.begin() << " Weight "
<< MaxWeight;
for (const CodeGenRegister *R : S.Regs)
dbgs() << " " << R->getName();
dbgs() << '\n';
});
// Update the set weight.
S.Weight = MaxWeight;
}
// Find singular determinants.
for (const CodeGenRegister *R : S.Regs)
if (R->getRegUnits().count() == 1 && R->getWeight(RegBank) == S.Weight)
S.SingularDeterminants |= R->getRegUnits();
}
}
// normalizeWeight is a computeRegUnitWeights helper that adjusts the weight of
// a register and its subregisters so that they have the same weight as their
// UberSet. Self-recursion processes the subregister tree in postorder so
// subregisters are normalized first.
//
// Side effects:
// - creates new adopted register units
// - causes superregisters to inherit adopted units
// - increases the weight of "singular" units
// - induces recomputation of UberWeights.
static bool normalizeWeight(CodeGenRegister *Reg,
std::vector<UberRegSet> &UberSets,
std::vector<UberRegSet *> &RegSets,
BitVector &NormalRegs,
CodeGenRegister::RegUnitList &NormalUnits,
CodeGenRegBank &RegBank) {
NormalRegs.resize(std::max(Reg->EnumValue + 1, NormalRegs.size()));
if (NormalRegs.test(Reg->EnumValue))
return false;
NormalRegs.set(Reg->EnumValue);
bool Changed = false;
const CodeGenRegister::SubRegMap &SRM = Reg->getSubRegs();
for (auto SRI : SRM) {
if (SRI.second == Reg)
continue; // self-cycles happen
Changed |= normalizeWeight(SRI.second, UberSets, RegSets, NormalRegs,
NormalUnits, RegBank);
}
// Postorder register normalization.
// Inherit register units newly adopted by subregisters.
if (Reg->inheritRegUnits(RegBank))
computeUberWeights(UberSets, RegBank);
// Check if this register is too skinny for its UberRegSet.
UberRegSet *UberSet = RegSets[RegBank.getRegIndex(Reg)];
unsigned RegWeight = Reg->getWeight(RegBank);
if (UberSet->Weight > RegWeight) {
// A register unit's weight can be adjusted only if it is the singular unit
// for this register, has not been used to normalize a subregister's set,
// and has not already been used to singularly determine this UberRegSet.
unsigned AdjustUnit = *Reg->getRegUnits().begin();
if (Reg->getRegUnits().count() != 1 || NormalUnits.test(AdjustUnit) ||
UberSet->SingularDeterminants.test(AdjustUnit)) {
// We don't have an adjustable unit, so adopt a new one.
AdjustUnit = RegBank.newRegUnit(UberSet->Weight - RegWeight);
Reg->adoptRegUnit(AdjustUnit);
// Adopting a unit does not immediately require recomputing set weights.
} else {
// Adjust the existing single unit.
if (!RegBank.getRegUnit(AdjustUnit).Artificial)
RegBank.increaseRegUnitWeight(AdjustUnit, UberSet->Weight - RegWeight);
// The unit may be shared among sets and registers within this set.
computeUberWeights(UberSets, RegBank);
}
Changed = true;
}
// Mark these units normalized so superregisters can't change their weights.
NormalUnits |= Reg->getRegUnits();
return Changed;
}
// Compute a weight for each register unit created during getSubRegs.
//
// The goal is that two registers in the same class will have the same weight,
// where each register's weight is defined as sum of its units' weights.
void CodeGenRegBank::computeRegUnitWeights() {
std::vector<UberRegSet> UberSets;
std::vector<UberRegSet *> RegSets(Registers.size());
computeUberSets(UberSets, RegSets, *this);
// UberSets and RegSets are now immutable.
computeUberWeights(UberSets, *this);
// Iterate over each Register, normalizing the unit weights until reaching
// a fix point.
unsigned NumIters = 0;
for (bool Changed = true; Changed; ++NumIters) {
assert(NumIters <= NumNativeRegUnits && "Runaway register unit weights");
(void)NumIters;
Changed = false;
for (CodeGenRegister &Reg : Registers) {
CodeGenRegister::RegUnitList NormalUnits;
BitVector NormalRegs;
Changed |= normalizeWeight(&Reg, UberSets, RegSets, NormalRegs,
NormalUnits, *this);
}
}
}
// isContiguous is a enforceRegUnitIntervals helper that returns true if all
// units in Units form a contiguous interval.
static bool isContiguous(const CodeGenRegister::RegUnitList &Units) {
unsigned LastUnit = Units.find_first();
for (auto ThisUnit : llvm::make_range(++Units.begin(), Units.end())) {
if (ThisUnit != LastUnit + 1)
return false;
LastUnit = ThisUnit;
}
return true;
}
// Enforce that all registers are intervals of regunits if the target
// requests this property. This will renumber regunits to ensure the
// interval property holds, or error out if it cannot be satisfied.
void CodeGenRegBank::enforceRegUnitIntervals() {
if (!RegistersAreIntervals)
return;
LLVM_DEBUG(dbgs() << "Enforcing regunit intervals for target\n");
std::vector<unsigned> RegUnitRenumbering(RegUnits.size(), ~0u);
// RegUnits that have been renumbered from X -> Y. Y is what is marked so that
// it doesn't create a chain of swaps.
SparseBitVector<> DontRenumberUnits;
auto GetRenumberedUnit = [&](unsigned RegUnit) -> unsigned {
if (unsigned RenumberedUnit = RegUnitRenumbering[RegUnit];
RenumberedUnit != ~0u)
return RenumberedUnit;
return RegUnit;
};
// Process registers in definition order
for (CodeGenRegister &Reg : Registers) {
LLVM_DEBUG(dbgs() << "Processing register " << Reg.getName() << "\n");
const auto &Units = Reg.getNativeRegUnits();
if (Units.empty())
continue;
SparseBitVector<> RenumberedUnits;
// First renumber all the units for this register according to previous
// renumbering.
LLVM_DEBUG(dbgs() << " Original (Renumbered) units:");
for (unsigned U : Units) {
LLVM_DEBUG(dbgs() << " " << U << "(" << GetRenumberedUnit(U) << "), ");
RenumberedUnits.set(GetRenumberedUnit(U));
}
LLVM_DEBUG(dbgs() << "\n");
unsigned LastUnit = RenumberedUnits.find_first();
for (auto ThisUnit :
llvm::make_range(++RenumberedUnits.begin(), RenumberedUnits.end())) {
if (ThisUnit != LastUnit + 1) {
if (DontRenumberUnits.test(LastUnit + 1)) {
PrintFatalError(
"cannot enforce regunit intervals for register " + Reg.getName() +
": unit " + Twine(LastUnit + 1) +
" (root: " + RegUnits[LastUnit + 1].Roots[0]->getName() +
") has already been renumbered and cannot be swapped");
}
LLVM_DEBUG(dbgs() << " Renumbering unit " << ThisUnit << " to "
<< (LastUnit + 1) << "\n");
RegUnitRenumbering[LastUnit + 1] = ThisUnit;
RegUnitRenumbering[ThisUnit] = LastUnit + 1;
DontRenumberUnits.set(LastUnit + 1);
ThisUnit = LastUnit + 1;
}
LastUnit = ThisUnit;
}
}
// Apply the renumbering to all registers
for (CodeGenRegister &Reg : Registers) {
CodeGenRegister::RegUnitList NewRegUnits;
for (unsigned OldUnit : Reg.getRegUnits())
NewRegUnits.set(GetRenumberedUnit(OldUnit));
Reg.setNewRegUnits(NewRegUnits);
CodeGenRegister::RegUnitList NewNativeUnits;
for (unsigned OldUnit : Reg.getNativeRegUnits())
NewNativeUnits.set(GetRenumberedUnit(OldUnit));
if (!isContiguous(NewNativeUnits)) {
PrintFatalError("cannot enforce regunit intervals, final "
"renumbering did not produce contiguous units "
"for register " +
Reg.getName() + "\n");
}
Reg.NativeRegUnits = NewNativeUnits;
}
}
// Find a set in UniqueSets with the same elements as Set.
// Return an iterator into UniqueSets.
static std::vector<RegUnitSet>::const_iterator
findRegUnitSet(const std::vector<RegUnitSet> &UniqueSets,
const RegUnitSet &Set) {
return llvm::find_if(
UniqueSets, [&Set](const RegUnitSet &I) { return I.Units == Set.Units; });
}
// Return true if the RUSubSet is a subset of RUSuperSet.
static bool isRegUnitSubSet(const std::vector<unsigned> &RUSubSet,
const std::vector<unsigned> &RUSuperSet) {
return llvm::includes(RUSuperSet, RUSubSet);
}
/// Iteratively prune unit sets. Prune subsets that are close to the superset,
/// but with one or two registers removed. We occasionally have registers like
/// APSR and PC thrown in with the general registers. We also see many
/// special-purpose register subsets, such as tail-call and Thumb
/// encodings. Generating all possible overlapping sets is combinatorial and
/// overkill for modeling pressure. Ideally we could fix this statically in
/// tablegen by (1) having the target define register classes that only include
/// the allocatable registers and marking other classes as non-allocatable and
/// (2) having a way to mark special purpose classes as "don't-care" classes for
/// the purpose of pressure. However, we make an attempt to handle targets that
/// are not nicely defined by merging nearly identical register unit sets
/// statically. This generates smaller tables. Then, dynamically, we adjust the
/// set limit by filtering the reserved registers.
///
/// Merge sets only if the units have the same weight. For example, on ARM,
/// Q-tuples with ssub index 0 include all S regs but also include D16+. We
/// should not expand the S set to include D regs.
void CodeGenRegBank::pruneUnitSets() {
assert(RegClassUnitSets.empty() && "this invalidates RegClassUnitSets");
// Form an equivalence class of UnitSets with no significant difference.
std::vector<unsigned> SuperSetIDs;
unsigned EndIdx = RegUnitSets.size();
for (auto [SubIdx, SubSet] : enumerate(RegUnitSets)) {
unsigned SuperIdx = 0;
for (; SuperIdx != EndIdx; ++SuperIdx) {
if (SuperIdx == SubIdx)
continue;
unsigned UnitWeight = RegUnits[SubSet.Units[0]].Weight;
const RegUnitSet &SuperSet = RegUnitSets[SuperIdx];
if (isRegUnitSubSet(SubSet.Units, SuperSet.Units) &&
(SubSet.Units.size() + 3 > SuperSet.Units.size()) &&
UnitWeight == RegUnits[SuperSet.Units[0]].Weight &&
UnitWeight == RegUnits[SuperSet.Units.back()].Weight) {
LLVM_DEBUG({
dbgs() << "UnitSet " << SubIdx << " subsumed by " << SuperIdx << '\n';
});
// We can pick any of the set names for the merged set. Go for the
// shortest one to avoid picking the name of one of the classes that are
// artificially created by tablegen. So "FPR128_lo" instead of
// "QQQQ_with_qsub3_in_FPR128_lo".
if (RegUnitSets[SubIdx].Name.size() < RegUnitSets[SuperIdx].Name.size())
RegUnitSets[SuperIdx].Name = RegUnitSets[SubIdx].Name;
break;
}
}
if (SuperIdx == EndIdx)
SuperSetIDs.push_back(SubIdx);
}
// Populate PrunedUnitSets with each equivalence class's superset.
std::vector<RegUnitSet> PrunedUnitSets;
PrunedUnitSets.reserve(SuperSetIDs.size());
for (unsigned SuperIdx : SuperSetIDs) {
PrunedUnitSets.emplace_back(RegUnitSets[SuperIdx].Name);
PrunedUnitSets.back().Units = std::move(RegUnitSets[SuperIdx].Units);
}
RegUnitSets = std::move(PrunedUnitSets);
}
// Create a RegUnitSet for each RegClass that contains all units in the class
// including adopted units that are necessary to model register pressure. Then
// iteratively compute RegUnitSets such that the union of any two overlapping
// RegUnitSets is represented.
//
// RegisterInfoEmitter will map each RegClass to its RegUnitClass and any
// RegUnitSet that is a superset of that RegUnitClass.
void CodeGenRegBank::computeRegUnitSets() {
assert(RegUnitSets.empty() && "dirty RegUnitSets");
#ifndef NDEBUG
// Helper to print register unit sets.
auto PrintRegUnitSets = [this]() {
for (auto [USIdx, US] : enumerate(RegUnitSets)) {
dbgs() << "UnitSet " << USIdx << " " << US.Name << ":";
printRegUnitNames(US.Units);
}
};
#endif // NDEBUG
// Compute a unique RegUnitSet for each RegClass.
auto &RegClasses = getRegClasses();
for (CodeGenRegisterClass &RC : RegClasses) {
if (!RC.Allocatable || RC.Artificial || !RC.GeneratePressureSet)
continue;
// Compute a sorted list of units in this class.
RegUnitSet RUSet(RC.getName());
RC.buildRegUnitSet(*this, RUSet.Units);
// Find an existing RegUnitSet.
if (findRegUnitSet(RegUnitSets, RUSet) == RegUnitSets.end())
RegUnitSets.push_back(std::move(RUSet));
}
if (RegUnitSets.empty())
PrintFatalError("RegUnitSets cannot be empty!");
LLVM_DEBUG({
dbgs() << "\nBefore pruning:\n";
PrintRegUnitSets();
});
// Iteratively prune unit sets.
pruneUnitSets();
LLVM_DEBUG({
dbgs() << "\nBefore union:\n";
PrintRegUnitSets();
dbgs() << "\nUnion sets:\n";
});
// Iterate over all unit sets, including new ones added by this loop.
// FIXME: Since `EndIdx` is computed just once during loop initialization,
// does this really iterate over new unit sets added by this loop?
unsigned NumRegUnitSubSets = RegUnitSets.size();
for (unsigned Idx = 0, EndIdx = RegUnitSets.size(); Idx != EndIdx; ++Idx) {
// In theory, this is combinatorial. In practice, it needs to be bounded
// by a small number of sets for regpressure to be efficient.
// If the assert is hit, we need to implement pruning.
assert(Idx < (2 * NumRegUnitSubSets) && "runaway unit set inference");
// Compare new sets with all original classes.
for (unsigned SearchIdx = (Idx >= NumRegUnitSubSets) ? 0 : Idx + 1;
SearchIdx != EndIdx; ++SearchIdx) {
std::vector<unsigned> Intersection;
std::set_intersection(
RegUnitSets[Idx].Units.begin(), RegUnitSets[Idx].Units.end(),
RegUnitSets[SearchIdx].Units.begin(),
RegUnitSets[SearchIdx].Units.end(), std::back_inserter(Intersection));
if (Intersection.empty())
continue;
RegUnitSet RUSet(RegUnitSets[Idx].Name + "_with_" +
RegUnitSets[SearchIdx].Name);
std::set_union(RegUnitSets[Idx].Units.begin(),
RegUnitSets[Idx].Units.end(),
RegUnitSets[SearchIdx].Units.begin(),
RegUnitSets[SearchIdx].Units.end(),
std::inserter(RUSet.Units, RUSet.Units.begin()));
// Find an existing RegUnitSet, or add the union to the unique sets.
if (findRegUnitSet(RegUnitSets, RUSet) == RegUnitSets.end()) {
LLVM_DEBUG({
dbgs() << "UnitSet " << RegUnitSets.size() << " " << RUSet.Name
<< ":";
printRegUnitNames(RUSet.Units);
});
RegUnitSets.push_back(std::move(RUSet));
}
}
}
// Iteratively prune unit sets after inferring supersets.
pruneUnitSets();
LLVM_DEBUG({
dbgs() << '\n';
PrintRegUnitSets();
});
// For each register class, list the UnitSets that are supersets.
RegClassUnitSets.resize(RegClasses.size());
for (CodeGenRegisterClass &RC : RegClasses) {
if (!RC.Allocatable)
continue;
// Recompute the sorted list of units in this class.
std::vector<unsigned> RCRegUnits;
RC.buildRegUnitSet(*this, RCRegUnits);
// Don't increase pressure for unallocatable regclasses.
if (RCRegUnits.empty())
continue;
LLVM_DEBUG({
dbgs() << "RC " << RC.getName() << " Units:\n";
printRegUnitNames(RCRegUnits);
dbgs() << "UnitSetIDs:";
});
// Find all supersets.
for (const auto &[USIdx, Set] : enumerate(RegUnitSets)) {
if (isRegUnitSubSet(RCRegUnits, Set.Units)) {
LLVM_DEBUG(dbgs() << " " << USIdx);
RegClassUnitSets[RC.EnumValue].push_back(USIdx);
}
}
LLVM_DEBUG(dbgs() << '\n');
assert(
(!RegClassUnitSets[RC.EnumValue].empty() || !RC.GeneratePressureSet) &&
"missing unit set for regclass");
}
// For each register unit, ensure that we have the list of UnitSets that
// contain the unit. Normally, this matches an existing list of UnitSets for a
// register class. If not, we create a new entry in RegClassUnitSets as a
// "fake" register class.
for (unsigned UnitIdx = 0, UnitEnd = NumNativeRegUnits; UnitIdx < UnitEnd;
++UnitIdx) {
std::vector<unsigned> RUSets;
for (auto [Idx, S] : enumerate(RegUnitSets))
if (is_contained(S.Units, UnitIdx))
RUSets.push_back(Idx);
unsigned RCUnitSetsIdx = 0;
for (unsigned e = RegClassUnitSets.size(); RCUnitSetsIdx != e;
++RCUnitSetsIdx) {
if (RegClassUnitSets[RCUnitSetsIdx] == RUSets) {
break;
}
}
RegUnits[UnitIdx].RegClassUnitSetsIdx = RCUnitSetsIdx;
if (RCUnitSetsIdx == RegClassUnitSets.size()) {
// Create a new list of UnitSets as a "fake" register class.
RegClassUnitSets.push_back(std::move(RUSets));
}
}
}
void CodeGenRegBank::computeRegUnitLaneMasks() {
for (CodeGenRegister &Register : Registers) {
// Create an initial lane mask for all register units.
const auto &RegUnits = Register.getRegUnits();
CodeGenRegister::RegUnitLaneMaskList RegUnitLaneMasks(
RegUnits.count(), LaneBitmask::getAll());
// Iterate through SubRegisters.
using SubRegMap = CodeGenRegister::SubRegMap;
const SubRegMap &SubRegs = Register.getSubRegs();
for (auto [SubRegIndex, SubReg] : SubRegs) {
// Ignore non-leaf subregisters, their lane masks are fully covered by
// the leaf subregisters anyway.
if (!SubReg->getSubRegs().empty())
continue;
LaneBitmask LaneMask = SubRegIndex->LaneMask;
// Distribute LaneMask to Register Units touched.
for (unsigned SUI : SubReg->getRegUnits()) {
bool Found = false;
unsigned u = 0;
for (unsigned RU : RegUnits) {
if (SUI == RU) {
RegUnitLaneMasks[u] &= LaneMask;
assert(!Found);
Found = true;
}
++u;
}
(void)Found;
assert(Found);
}
}
Register.setRegUnitLaneMasks(RegUnitLaneMasks);
}
}
void CodeGenRegBank::computeDerivedInfo() {
computeComposites();
computeSubRegLaneMasks();
// Compute a weight for each register unit created during getSubRegs.
// This may create adopted register units (with unit # >= NumNativeRegUnits).
Records.getTimer().startTimer("Compute reg unit weights");
computeRegUnitWeights();
Records.getTimer().stopTimer();
// Enforce regunit intervals if requested by the target.
Records.getTimer().startTimer("Enforce regunit intervals");
enforceRegUnitIntervals();
Records.getTimer().stopTimer();
// Compute a unique set of RegUnitSets. One for each RegClass and inferred
// supersets for the union of overlapping sets.
computeRegUnitSets();
computeRegUnitLaneMasks();
// Compute register class HasDisjunctSubRegs/CoveredBySubRegs flag.
for (CodeGenRegisterClass &RC : RegClasses) {
RC.HasDisjunctSubRegs = false;
RC.CoveredBySubRegs = true;
for (const CodeGenRegister *Reg : RC.getMembers()) {
RC.HasDisjunctSubRegs |= Reg->HasDisjunctSubRegs;
RC.CoveredBySubRegs &= Reg->CoveredBySubRegs;
}
}
// Get the weight of each set.
for (auto [Idx, US] : enumerate(RegUnitSets))
RegUnitSets[Idx].Weight = getRegUnitSetWeight(US.Units);
// Find the order of each set.
RegUnitSetOrder.reserve(RegUnitSets.size());
for (unsigned Idx : seq<unsigned>(RegUnitSets.size()))
RegUnitSetOrder.push_back(Idx);
llvm::stable_sort(RegUnitSetOrder, [this](unsigned ID1, unsigned ID2) {
return getRegPressureSet(ID1).Units.size() <
getRegPressureSet(ID2).Units.size();
});
for (unsigned Idx = 0, EndIdx = RegUnitSets.size(); Idx != EndIdx; ++Idx)
RegUnitSets[RegUnitSetOrder[Idx]].Order = Idx;
}
//
// Synthesize missing register class intersections.
//
// Make sure that sub-classes of RC exists such that getCommonSubClass(RC, X)
// returns a maximal register class for all X.
//
void CodeGenRegBank::inferCommonSubClass(CodeGenRegisterClass *RC) {
assert(!RegClasses.empty());
// Stash the iterator to the last element so that this loop doesn't visit
// elements added by the getOrCreateSubClass call within it.
for (auto I = RegClasses.begin(), E = std::prev(RegClasses.end());
I != std::next(E); ++I) {
CodeGenRegisterClass *RC1 = RC;
CodeGenRegisterClass *RC2 = &*I;
if (RC1 == RC2)
continue;
// Compute the set intersection of RC1 and RC2.
const CodeGenRegister::Vec &Memb1 = RC1->getMembers();
const CodeGenRegister::Vec &Memb2 = RC2->getMembers();
CodeGenRegister::Vec Intersection;
std::set_intersection(Memb1.begin(), Memb1.end(), Memb2.begin(),
Memb2.end(),
std::inserter(Intersection, Intersection.begin()),
deref<std::less<>>());
// Skip disjoint class pairs.
if (Intersection.empty())
continue;
// Skip casses where the intersection is composed of artificial
// registers.
if (llvm::all_of(Intersection, [](const CodeGenRegister *Reg) {
return Reg->Artificial;
}))
continue;
// If RC1 and RC2 have different spill sizes or alignments, use the
// stricter one for sub-classing. If they are equal, prefer RC1.
if (RC2->RSI.hasStricterSpillThan(RC1->RSI))
std::swap(RC1, RC2);
getOrCreateSubClass(RC1, &Intersection,
RC1->getName() + "_and_" + RC2->getName());
}
}
//
// Synthesize missing sub-classes for getSubClassWithSubReg().
//
// Make sure that the set of registers in RC with a given SubIdx sub-register
// form a register class. Update RC->SubClassWithSubReg.
//
void CodeGenRegBank::inferSubClassWithSubReg(CodeGenRegisterClass *RC) {
// Map SubRegIndex to set of registers in RC supporting that SubRegIndex.
using SubReg2SetMap = std::map<const CodeGenSubRegIndex *,
CodeGenRegister::Vec, deref<std::less<>>>;
// Compute the set of registers supporting each SubRegIndex.
SubReg2SetMap SRSets;
for (const CodeGenRegister *R : RC->getMembers()) {
if (R->Artificial)
continue;
const CodeGenRegister::SubRegMap &SRM = R->getSubRegs();
for (auto [I, _] : SRM)
SRSets[I].push_back(R);
}
// Find matching classes for all SRSets entries. Iterate in SubRegIndex
// numerical order to visit synthetic indices last.
for (const CodeGenSubRegIndex &SubIdx : SubRegIndices) {
SubReg2SetMap::const_iterator I = SRSets.find(&SubIdx);
// Unsupported SubRegIndex. Skip it.
if (I == SRSets.end())
continue;
// In most cases, all RC registers support the SubRegIndex.
auto IsNotArtificial = [](const CodeGenRegister *R) {
return !R->Artificial;
};
if (I->second.size() ==
(size_t)count_if(RC->getMembers(), IsNotArtificial)) {
RC->setSubClassWithSubReg(&SubIdx, RC);
continue;
}
if (SubIdx.Artificial)
continue;
// This is a real subset. See if we have a matching class.
CodeGenRegisterClass *SubRC =
getOrCreateSubClass(RC, &I->second,
RC->getName() + "_with_" + I->first->getName())
.first;
RC->setSubClassWithSubReg(&SubIdx, SubRC);
}
}
//
// Synthesize missing sub-classes of RC for getMatchingSuperRegClass().
//
// Create sub-classes of RC such that getMatchingSuperRegClass(RC, SubIdx, X)
// has a maximal result for any SubIdx and any X >= FirstSubRegRC.
//
void CodeGenRegBank::inferMatchingSuperRegClass(
CodeGenRegisterClass *RC,
std::list<CodeGenRegisterClass>::iterator FirstSubRegRC) {
DenseSet<const CodeGenSubRegIndex *> ImpliedSubRegIndices;
std::vector<const CodeGenRegister *> SubRegs;
BitVector TopoSigs(getNumTopoSigs());
// Iterate subregister indices in topological order to visit larger indices
// first. This allows us to skip the smaller indices in many cases because
// their inferred super-register classes are implied.
for (CodeGenSubRegIndex *SubIdx : SubRegIndicesRPOT) {
// Skip indexes that aren't fully supported by RC's registers. This was
// computed by inferSubClassWithSubReg() above which should have been
// called first.
if (RC->getSubClassWithSubReg(SubIdx) != RC)
continue;
if (ImpliedSubRegIndices.contains(SubIdx))
continue;
// Build list of (Sub, Super) pairs for this SubIdx, sorted by Sub. Note
// that the list may contain entries with the same Sub but different Supers.
SubRegs.clear();
TopoSigs.reset();
for (const CodeGenRegister *Super : RC->getMembers()) {
const CodeGenRegister *Sub = Super->getSubRegs().find(SubIdx)->second;
if (Super->Artificial)
continue;
assert(Sub && "Missing sub-register");
SubRegs.push_back(Sub);
TopoSigs.set(Sub->getTopoSig());
}
// Iterate over sub-register class candidates. Ignore classes created by
// this loop. They will never be useful.
// Store an iterator to the last element (not end) so that this loop doesn't
// visit newly inserted elements.
assert(!RegClasses.empty());
for (auto I = FirstSubRegRC, E = std::prev(RegClasses.end());
I != std::next(E); ++I) {
CodeGenRegisterClass &SubRC = *I;
if (SubRC.Artificial)
continue;
// Topological shortcut: SubRC members have the wrong shape.
if (!TopoSigs.anyCommon(SubRC.getRegsWithSuperRegsTopoSigs()))
continue;
// Compute the subset of RC that maps into SubRC.
CodeGenRegister::Vec SubSetVec;
auto IsNotArtificial = [](const CodeGenRegister *R) {
return !R->Artificial;
};
auto NonArtificialMembers =
make_filter_range(RC->getMembers(), IsNotArtificial);
for (const auto &[Sub, Super] :
zip_equal(SubRegs, NonArtificialMembers)) {
if (SubRC.contains(Sub))
SubSetVec.push_back(Super);
}
if (SubSetVec.empty())
continue;
// RC injects completely into SubRC.
if (SubSetVec.size() ==
(size_t)count_if(RC->getMembers(), IsNotArtificial)) {
SubRC.addSuperRegClass(SubIdx, RC);
// We can skip checking subregister indices that can be composed from
// the current SubIdx.
//
// Proof sketch: Let SubRC' be another register class and SubSubIdx
// a subregister index that can be composed from SubIdx.
//
// Calling this function with SubRC in place of RC ensures the existence
// of a subclass X of SubRC with the registers that have subregisters in
// SubRC'.
//
// The set of registers in RC with SubSubIdx in SubRC' is equal to the
// set of registers in RC with SubIdx in X (because every register in
// RC has a corresponding subregister in SubRC), and so checking the
// pair (SubSubIdx, SubRC') is redundant with checking (SubIdx, X).
for (const auto &SubSubIdx : SubIdx->getComposites())
ImpliedSubRegIndices.insert(SubSubIdx.second);
continue;
}
// Only a subset of RC maps into SubRC. Make sure it is represented by a
// class.
//
// The name of the inferred register class follows the template
// "<RC>_with_<SubIdx>_in_<SubRC>".
//
// When SubRC is already an inferred class, prefer a name of the form
// "<RC>_with_<CompositeSubIdx>_in_<SubSubRC>" over a chain of the form
// "<RC>_with_<SubIdx>_in_<OtherRc>_with_<SubSubIdx>_in_<SubSubRC>".
CodeGenSubRegIndex *CompositeSubIdx = SubIdx;
CodeGenRegisterClass *CompositeSubRC = &SubRC;
if (CodeGenSubRegIndex *SubSubIdx = SubRC.getInferredFromSubRegIdx()) {
auto It = SubIdx->getComposites().find(SubSubIdx);
if (It != SubIdx->getComposites().end()) {
CompositeSubIdx = It->second;
CompositeSubRC = SubRC.getInferredFromRC();
}
}
auto [SubSetRC, Inserted] = getOrCreateSubClass(
RC, &SubSetVec,
RC->getName() + "_with_" + CompositeSubIdx->getName() + "_in_" +
CompositeSubRC->getName());
if (Inserted)
SubSetRC->setInferredFrom(CompositeSubIdx, CompositeSubRC);
}
}
}
//
// Infer missing register classes.
//
void CodeGenRegBank::computeInferredRegisterClasses() {
assert(!RegClasses.empty());
// When this function is called, the register classes have not been sorted
// and assigned EnumValues yet. That means getSubClasses(),
// getSuperClasses(), and hasSubClass() functions are defunct.
Records.getTimer().startTimer("Compute inferred register classes");
// Use one-before-the-end so it doesn't move forward when new elements are
// added.
auto FirstNewRC = std::prev(RegClasses.end());
// Visit all register classes, including the ones being added by the loop.
// Watch out for iterator invalidation here.
for (auto I = RegClasses.begin(), E = RegClasses.end(); I != E; ++I) {
CodeGenRegisterClass *RC = &*I;
if (RC->Artificial)
continue;
// Synthesize answers for getSubClassWithSubReg().
inferSubClassWithSubReg(RC);
// Synthesize answers for getCommonSubClass().
inferCommonSubClass(RC);
// Synthesize answers for getMatchingSuperRegClass().
inferMatchingSuperRegClass(RC);
// New register classes are created while this loop is running, and we need
// to visit all of them. In particular, inferMatchingSuperRegClass needs
// to match old super-register classes with sub-register classes created
// after inferMatchingSuperRegClass was called. At this point,
// inferMatchingSuperRegClass has checked SuperRC = [0..rci] with SubRC =
// [0..FirstNewRC). We need to cover SubRC = [FirstNewRC..rci].
if (I == FirstNewRC) {
auto NextNewRC = std::prev(RegClasses.end());
for (auto I2 = RegClasses.begin(), E2 = std::next(FirstNewRC); I2 != E2;
++I2)
inferMatchingSuperRegClass(&*I2, E2);
FirstNewRC = NextNewRC;
}
}
Records.getTimer().startTimer("Extend super-register classes");
// Compute the transitive closure for super-register classes.
//
// By iterating over sub-register indices in topological order, we only ever
// add super-register classes for sub-register indices that have not already
// been visited. That allows computing the transitive closure in a single
// pass.
for (CodeGenSubRegIndex *SubIdx : SubRegIndicesRPOT) {
for (CodeGenRegisterClass &SubRC : RegClasses)
SubRC.extendSuperRegClasses(SubIdx);
}
Records.getTimer().stopTimer();
}
/// getRegisterClassForRegister - Find the register class that contains the
/// specified physical register. If the register is not in a register class,
/// return null. If the register is in multiple classes, and the classes have a
/// superset-subset relationship and the same set of types, return the
/// superclass. Otherwise return null.
const CodeGenRegisterClass *
CodeGenRegBank::getRegClassForRegister(const Record *R) {
const CodeGenRegister *Reg = getReg(R);
const CodeGenRegisterClass *FoundRC = nullptr;
for (const CodeGenRegisterClass &RC : getRegClasses()) {
if (!RC.contains(Reg))
continue;
// If this is the first class that contains the register,
// make a note of it and go on to the next class.
if (!FoundRC) {
FoundRC = &RC;
continue;
}
// If a register's classes have different types, return null.
if (RC.getValueTypes() != FoundRC->getValueTypes())
return nullptr;
// Check to see if the previously found class that contains
// the register is a subclass of the current class. If so,
// prefer the superclass.
if (RC.hasSubClass(FoundRC)) {
FoundRC = &RC;
continue;
}
// Check to see if the previously found class that contains
// the register is a superclass of the current class. If so,
// prefer the superclass.
if (FoundRC->hasSubClass(&RC))
continue;
// Multiple classes, and neither is a superclass of the other.
// Return null.
return nullptr;
}
return FoundRC;
}
bool CodeGenRegBank::regClassContainsReg(const Record *RegClassDef,
const Record *RegDef,
ArrayRef<SMLoc> Loc) {
// Check all four combinations of Register[ByHwMode] X RegClass[ByHwMode],
// starting with the two RegClassByHwMode cases.
unsigned NumModes = CGH.getNumModeIds();
std::optional<RegisterByHwMode> RegByMode;
CodeGenRegister *Reg = nullptr;
if (RegDef->isSubClassOf("RegisterByHwMode"))
RegByMode = RegisterByHwMode(RegDef, *this);
else
Reg = getReg(RegDef);
if (RegClassDef->isSubClassOf("RegClassByHwMode")) {
RegClassByHwMode RC(RegClassDef, *this);
for (unsigned M = 0; M < NumModes; ++M) {
if (RC.hasMode(M) && !RC.get(M)->contains(Reg ? Reg : RegByMode->get(M)))
return false;
}
return true;
}
// Otherwise we have a plain register class, check Register[ByHwMode]
CodeGenRegisterClass *RC = getRegClass(RegClassDef, Loc);
if (Reg)
return RC->contains(Reg);
for (unsigned M = 0; M < NumModes; ++M) {
if (RegByMode->hasMode(M) && !RC->contains(RegByMode->get(M)))
return false;
}
return true; // RegByMode contained for all possible modes.
}
const CodeGenRegisterClass *
CodeGenRegBank::getMinimalPhysRegClass(const Record *RegRecord,
ValueTypeByHwMode *VT) {
const CodeGenRegister *Reg = getReg(RegRecord);
const CodeGenRegisterClass *BestRC = nullptr;
for (const CodeGenRegisterClass &RC : getRegClasses()) {
if ((!VT || RC.hasType(*VT)) && RC.contains(Reg) &&
(!BestRC || BestRC->hasSubClass(&RC)))
BestRC = &RC;
}
assert(BestRC && "Couldn't find the register class");
return BestRC;
}
const CodeGenRegisterClass *
CodeGenRegBank::getSuperRegForSubReg(const ValueTypeByHwMode &ValueTy,
const CodeGenSubRegIndex *SubIdx,
bool MustBeAllocatable) const {
std::vector<const CodeGenRegisterClass *> Candidates;
auto &RegClasses = getRegClasses();
// Try to find a register class which supports ValueTy, and also contains
// SubIdx.
for (const CodeGenRegisterClass &RC : RegClasses) {
// Is there a subclass of this class which contains this subregister index?
const CodeGenRegisterClass *SubClassWithSubReg =
RC.getSubClassWithSubReg(SubIdx);
if (!SubClassWithSubReg)
continue;
// We have a class. Check if it supports this value type.
if (!llvm::is_contained(SubClassWithSubReg->VTs, ValueTy))
continue;
// If necessary, check that it is allocatable.
if (MustBeAllocatable && !SubClassWithSubReg->Allocatable)
continue;
// We have a register class which supports both the value type and
// subregister index. Remember it.
Candidates.push_back(SubClassWithSubReg);
}
// If we didn't find anything, we're done.
if (Candidates.empty())
return nullptr;
// Find and return the largest of our candidate classes.
llvm::stable_sort(Candidates, [&](const CodeGenRegisterClass *A,
const CodeGenRegisterClass *B) {
if (A->getMembers().size() > B->getMembers().size())
return true;
if (A->getMembers().size() < B->getMembers().size())
return false;
// Order by name as a tie-breaker.
return StringRef(A->getName()) < B->getName();
});
return Candidates[0];
}
BitVector
CodeGenRegBank::computeCoveredRegisters(ArrayRef<const Record *> Regs) {
SetVector<const CodeGenRegister *> Set;
// First add Regs with all sub-registers.
for (const Record *RegDef : Regs) {
CodeGenRegister *Reg = getReg(RegDef);
if (Set.insert(Reg))
// Reg is new, add all sub-registers.
// The pre-ordering is not important here.
Reg->addSubRegsPreOrder(Set, *this);
}
// Second, find all super-registers that are completely covered by the set.
for (unsigned i = 0; i != Set.size(); ++i) {
for (const CodeGenRegister *Super : Set[i]->getSuperRegs()) {
if (!Super->CoveredBySubRegs || Set.contains(Super))
continue;
// This new super-register is covered by its sub-registers.
bool AllSubsInSet = true;
const CodeGenRegister::SubRegMap &SRM = Super->getSubRegs();
for (auto [_, SR] : SRM)
if (!Set.contains(SR)) {
AllSubsInSet = false;
break;
}
// All sub-registers in Set, add Super as well.
// We will visit Super later to recheck its super-registers.
if (AllSubsInSet)
Set.insert(Super);
}
}
// Convert to BitVector.
BitVector BV(Registers.size() + 1);
for (const CodeGenRegister *Reg : Set)
BV.set(Reg->EnumValue);
return BV;
}
void CodeGenRegBank::printRegUnitNames(ArrayRef<unsigned> Units) const {
for (unsigned Unit : Units) {
if (Unit < NumNativeRegUnits)
dbgs() << ' ' << RegUnits[Unit].Roots[0]->getName();
else
dbgs() << " #" << Unit;
}
dbgs() << '\n';
}