[RDF] Create build config

- Add option to ignore reserved registers
- Add possibility to track selected registers or register classes only

Tracking is done based on register units, so the set of registers to track
is translated into a set of register units.
This commit is contained in:
Krzysztof Parzyszek 2023-06-03 06:59:19 -07:00
parent ad1dd78793
commit 39ab9da920
2 changed files with 110 additions and 11 deletions

View File

@ -225,6 +225,7 @@
#define LLVM_CODEGEN_RDFGRAPH_H
#include "RDFRegisters.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/MC/LaneBitmask.h"
#include "llvm/Support/Allocator.h"
@ -336,6 +337,7 @@ struct BuildOptions {
enum : unsigned {
None = 0x00,
KeepDeadPhis = 0x01, // Do not remove dead phis during build.
OmitReserved = 0x02, // Do not track reserved registers.
};
};
@ -664,6 +666,19 @@ struct DataFlowGraph {
const MachineDominanceFrontier &mdf,
const TargetOperandInfo &toi);
struct Config {
Config() = default;
Config(unsigned Opts) : Options(Opts) {}
Config(ArrayRef<const TargetRegisterClass *> RCs) : Classes(RCs) {}
Config(ArrayRef<MCPhysReg> Track) : TrackRegs(Track.begin(), Track.end()) {}
Config(ArrayRef<RegisterId> Track)
: TrackRegs(Track.begin(), Track.end()) {}
unsigned Options = BuildOptions::None;
SmallVector<const TargetRegisterClass *> Classes;
std::set<RegisterId> TrackRegs;
};
NodeBase *ptr(NodeId N) const;
template <typename T> T ptr(NodeId N) const { //
return static_cast<T>(ptr(N));
@ -756,7 +771,9 @@ struct DataFlowGraph {
// Map: Register (physical or virtual) -> DefStack
using DefStackMap = std::unordered_map<RegisterId, DefStack>;
void build(unsigned Options = BuildOptions::None);
void build(const Config &config);
void build() { build(Config()); }
void pushAllDefs(Instr IA, DefStackMap &DM);
void markBlock(NodeId B, DefStackMap &DefM);
void releaseBlock(NodeId B, DefStackMap &DefM);
@ -793,6 +810,9 @@ struct DataFlowGraph {
removeFromOwner(DA);
}
bool isTracked(RegisterRef RR) const;
bool hasUntrackedRef(Stmt S, bool IgnoreReserved = true) const;
// Some useful filters.
template <uint16_t Kind> static bool IsRef(const Node BA) {
return BA.Addr->getType() == NodeAttrs::Ref && BA.Addr->getKind() == Kind;
@ -882,6 +902,10 @@ private:
std::map<MachineBasicBlock *, Block> BlockNodes;
// Lane mask map.
LaneMaskIndex LMI;
Config BuildCfg;
std::set<unsigned> TrackedUnits;
BitVector ReservedRegs;
}; // struct DataFlowGraph
template <typename Predicate>

View File

@ -855,8 +855,43 @@ Func DataFlowGraph::newFunc(MachineFunction *MF) {
}
// Build the data flow graph.
void DataFlowGraph::build(unsigned Options) {
void DataFlowGraph::build(const Config &config) {
reset();
BuildCfg = config;
MachineRegisterInfo &MRI = MF.getRegInfo();
ReservedRegs = MRI.getReservedRegs();
bool SkipReserved = BuildCfg.Options & BuildOptions::OmitReserved;
auto Insert = [](auto &Set, auto &&Range) {
Set.insert(Range.begin(), Range.end());
};
if (BuildCfg.TrackRegs.empty()) {
std::set<RegisterId> BaseSet;
if (BuildCfg.Classes.empty()) {
// Insert every register.
for (unsigned R = 0, E = getPRI().getTRI().getNumRegs(); R != E; ++R)
BaseSet.insert(R);
} else {
for (const TargetRegisterClass *RC : BuildCfg.Classes) {
for (MCPhysReg R : *RC)
BaseSet.insert(R);
}
}
for (RegisterId R : BaseSet) {
if (SkipReserved && ReservedRegs[R])
continue;
Insert(TrackedUnits, getPRI().getUnits(RegisterRef(R)));
}
} else {
// Track set in Config overrides everything.
for (unsigned R : BuildCfg.TrackRegs) {
if (SkipReserved && ReservedRegs[R])
continue;
Insert(TrackedUnits, getPRI().getUnits(RegisterRef(R)));
}
}
TheFunc = newFunc(&MF);
if (MF.empty())
@ -876,7 +911,6 @@ void DataFlowGraph::build(unsigned Options) {
NodeList Blocks = TheFunc.Addr->members(*this);
// Collect function live-ins and entry block live-ins.
MachineRegisterInfo &MRI = MF.getRegInfo();
MachineBasicBlock &EntryB = *EA.Addr->getCode();
assert(EntryB.pred_empty() && "Function entry block has predecessors");
for (std::pair<unsigned, unsigned> P : MRI.liveins())
@ -888,6 +922,8 @@ void DataFlowGraph::build(unsigned Options) {
// Add function-entry phi nodes for the live-in registers.
for (RegisterRef RR : LiveIns.refs()) {
if (RR.isReg() && !isTracked(RR)) // isReg is likely guaranteed
continue;
Phi PA = newPhi(EA);
uint16_t PhiFlags = NodeAttrs::PhiRef | NodeAttrs::Preserving;
Def DA = newDef(PA, RR, PhiFlags);
@ -913,6 +949,8 @@ void DataFlowGraph::build(unsigned Options) {
// Build phi nodes for each live-in.
for (RegisterRef RR : EHRegs.refs()) {
if (RR.isReg() && !isTracked(RR))
continue;
Phi PA = newPhi(BA);
uint16_t PhiFlags = NodeAttrs::PhiRef | NodeAttrs::Preserving;
// Add def:
@ -940,7 +978,7 @@ void DataFlowGraph::build(unsigned Options) {
linkBlockRefs(DM, EA);
// Finally, remove all unused phi nodes.
if (!(Options & BuildOptions::KeepDeadPhis))
if (!(BuildCfg.Options & BuildOptions::KeepDeadPhis))
removeUnusedPhis();
}
@ -1024,6 +1062,8 @@ void DataFlowGraph::pushClobbers(Instr IA, DefStackMap &DefM) {
DefM[RR.Reg].push(DA);
Defined.insert(RR.Reg);
for (RegisterId A : getPRI().getAliasSet(RR.Reg)) {
if (RegisterRef::isRegId(A) && !isTracked(RegisterRef(A)))
continue;
// Check that we don't push the same def twice.
assert(A != RR.Reg);
if (!Defined.count(A))
@ -1079,6 +1119,8 @@ void DataFlowGraph::pushDefs(Instr IA, DefStackMap &DefM) {
// The def stack traversal in linkNodeUp will check the exact aliasing.
DefM[RR.Reg].push(DA);
for (RegisterId A : getPRI().getAliasSet(RR.Reg)) {
if (RegisterRef::isRegId(A) && !isTracked(RegisterRef(A)))
continue;
// Check that we don't push the same def twice.
assert(A != RR.Reg);
DefM[A].push(DA);
@ -1107,6 +1149,8 @@ NodeList DataFlowGraph::getRelatedRefs(Instr IA, Ref RA) const {
void DataFlowGraph::reset() {
Memory.clear();
BlockNodes.clear();
TrackedUnits.clear();
ReservedRegs.clear();
TheFunc = Func();
}
@ -1245,7 +1289,7 @@ void DataFlowGraph::buildStmt(Block BA, MachineInstr &In) {
if (!Op.isReg() || !Op.isDef() || Op.isImplicit())
continue;
Register R = Op.getReg();
if (!R || !R.isPhysical())
if (!R || !R.isPhysical() || !isTracked(RegisterRef(R)))
continue;
uint16_t Flags = NodeAttrs::None;
if (TOI.isPreserving(In, OpN)) {
@ -1277,9 +1321,12 @@ void DataFlowGraph::buildStmt(Block BA, MachineInstr &In) {
SA.Addr->addMember(DA, *this);
// Record all clobbered registers in DoneDefs.
const uint32_t *RM = Op.getRegMask();
for (unsigned i = 1, e = TRI.getNumRegs(); i != e; ++i)
for (unsigned i = 1, e = TRI.getNumRegs(); i != e; ++i) {
if (!isTracked(RegisterRef(i)))
continue;
if (!(RM[i / 32] & (1u << (i % 32))))
DoneClobbers.set(i);
}
}
// Process implicit defs, skipping those that have already been added
@ -1289,7 +1336,7 @@ void DataFlowGraph::buildStmt(Block BA, MachineInstr &In) {
if (!Op.isReg() || !Op.isDef() || !Op.isImplicit())
continue;
Register R = Op.getReg();
if (!R || !R.isPhysical() || DoneDefs.test(R))
if (!R || !R.isPhysical() || !isTracked(RegisterRef(R)) || DoneDefs.test(R))
continue;
RegisterRef RR = makeRegRef(Op);
uint16_t Flags = NodeAttrs::None;
@ -1318,7 +1365,7 @@ void DataFlowGraph::buildStmt(Block BA, MachineInstr &In) {
if (!Op.isReg() || !Op.isUse())
continue;
Register R = Op.getReg();
if (!R || !R.isPhysical())
if (!R || !R.isPhysical() || !isTracked(RegisterRef(R)))
continue;
uint16_t Flags = NodeAttrs::None;
if (Op.isUndef())
@ -1348,9 +1395,13 @@ void DataFlowGraph::recordDefsForDF(BlockRefsMap &PhiM, Block BA) {
// This is done to make sure that each defined reference gets only one
// phi node, even if it is defined multiple times.
RegisterAggr Defs(getPRI());
for (Instr IA : BA.Addr->members(*this))
for (Ref RA : IA.Addr->members_if(IsDef, *this))
Defs.insert(RA.Addr->getRegRef(*this));
for (Instr IA : BA.Addr->members(*this)) {
for (Ref RA : IA.Addr->members_if(IsDef, *this)) {
RegisterRef RR = RA.Addr->getRegRef(*this);
if (RR.isReg() && isTracked(RR))
Defs.insert(RR);
}
}
// Calculate the iterated dominance frontier of BB.
const MachineDominanceFrontier::DomSetType &DF = DFLoc->second;
@ -1721,4 +1772,28 @@ void DataFlowGraph::unlinkDefDF(Def DA) {
}
}
bool DataFlowGraph::isTracked(RegisterRef RR) const {
return !disjoint(getPRI().getUnits(RR), TrackedUnits);
}
bool DataFlowGraph::hasUntrackedRef(Stmt S, bool IgnoreReserved) const {
SmallVector<MachineOperand *> Ops;
for (Ref R : S.Addr->members(*this)) {
Ops.push_back(&R.Addr->getOp());
RegisterRef RR = R.Addr->getRegRef(*this);
if (IgnoreReserved && RR.isReg() && ReservedRegs[RR.idx()])
continue;
if (!isTracked(RR))
return true;
}
for (const MachineOperand &Op : S.Addr->getCode()->operands()) {
if (!Op.isReg() && !Op.isRegMask())
continue;
if (llvm::find(Ops, &Op) == Ops.end())
return true;
}
return false;
}
} // end namespace llvm::rdf