[RDF] Fix liveness analysis for phi nodes with shadow uses
Shadow uses need to be analyzed together, since each individual shadow will only have a partial reaching def. All shadows together may cover a given register ref, while each individual shadow may not. llvm-svn: 280855
This commit is contained in:
parent
e7729c8468
commit
2db0c8b75f
|
@ -336,6 +336,13 @@ void Liveness::computePhiInfo() {
|
||||||
std::map<NodeId,std::map<NodeId,RegisterSet>> PhiUp;
|
std::map<NodeId,std::map<NodeId,RegisterSet>> PhiUp;
|
||||||
std::vector<NodeId> PhiUQ; // Work list of phis for upward propagation.
|
std::vector<NodeId> PhiUQ; // Work list of phis for upward propagation.
|
||||||
|
|
||||||
|
auto isEntryPhi = [this] (NodeId P) -> bool {
|
||||||
|
auto PA = DFG.addr<PhiNode*>(P);
|
||||||
|
NodeAddr<BlockNode*> BA = PA.Addr->getOwner(DFG);
|
||||||
|
MachineBasicBlock *BB = BA.Addr->getCode();
|
||||||
|
return BB == &BB->getParent()->front();
|
||||||
|
};
|
||||||
|
|
||||||
// Go over all phis.
|
// Go over all phis.
|
||||||
for (NodeAddr<PhiNode*> PhiA : Phis) {
|
for (NodeAddr<PhiNode*> PhiA : Phis) {
|
||||||
// Go over all defs and collect the reached uses that are non-phi uses
|
// Go over all defs and collect the reached uses that are non-phi uses
|
||||||
|
@ -353,8 +360,15 @@ void Liveness::computePhiInfo() {
|
||||||
DefQ.insert(R.Id);
|
DefQ.insert(R.Id);
|
||||||
PhiDefs.insert(R.Id);
|
PhiDefs.insert(R.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Collect the super-set of all possible reached uses. This set will
|
||||||
|
// contain all uses reached from this phi, either directly from the
|
||||||
|
// phi defs, or (recursively) via non-phi defs reached by the phi defs.
|
||||||
|
// This set of uses will later be trimmed to only contain these uses that
|
||||||
|
// are actually reached by the phi defs.
|
||||||
for (unsigned i = 0; i < DefQ.size(); ++i) {
|
for (unsigned i = 0; i < DefQ.size(); ++i) {
|
||||||
NodeAddr<DefNode*> DA = DFG.addr<DefNode*>(DefQ[i]);
|
NodeAddr<DefNode*> DA = DFG.addr<DefNode*>(DefQ[i]);
|
||||||
|
// Visit all reached uses.
|
||||||
NodeId UN = DA.Addr->getReachedUse();
|
NodeId UN = DA.Addr->getReachedUse();
|
||||||
while (UN != 0) {
|
while (UN != 0) {
|
||||||
NodeAddr<UseNode*> A = DFG.addr<UseNode*>(UN);
|
NodeAddr<UseNode*> A = DFG.addr<UseNode*>(UN);
|
||||||
|
@ -363,6 +377,9 @@ void Liveness::computePhiInfo() {
|
||||||
RealUses[getRestrictedRegRef(A)].insert(A.Id);
|
RealUses[getRestrictedRegRef(A)].insert(A.Id);
|
||||||
UN = A.Addr->getSibling();
|
UN = A.Addr->getSibling();
|
||||||
}
|
}
|
||||||
|
// Visit all reached defs, and add them to the queue. These defs may
|
||||||
|
// override some of the uses collected here, but that will be handled
|
||||||
|
// later.
|
||||||
NodeId DN = DA.Addr->getReachedDef();
|
NodeId DN = DA.Addr->getReachedDef();
|
||||||
while (DN != 0) {
|
while (DN != 0) {
|
||||||
NodeAddr<DefNode*> A = DFG.addr<DefNode*>(DN);
|
NodeAddr<DefNode*> A = DFG.addr<DefNode*>(DN);
|
||||||
|
@ -389,7 +406,7 @@ void Liveness::computePhiInfo() {
|
||||||
// = R1:0 u6 Not reached by d1 (covered collectively
|
// = R1:0 u6 Not reached by d1 (covered collectively
|
||||||
// by d3 and d5), but following reached
|
// by d3 and d5), but following reached
|
||||||
// defs and uses from d1 will lead here.
|
// defs and uses from d1 will lead here.
|
||||||
auto HasDef = [&PhiDefs] (NodeAddr<DefNode*> DA) -> bool {
|
auto InPhiDefs = [&PhiDefs] (NodeAddr<DefNode*> DA) -> bool {
|
||||||
return PhiDefs.count(DA.Id);
|
return PhiDefs.count(DA.Id);
|
||||||
};
|
};
|
||||||
for (auto UI = RealUses.begin(), UE = RealUses.end(); UI != UE; ) {
|
for (auto UI = RealUses.begin(), UE = RealUses.end(); UI != UE; ) {
|
||||||
|
@ -397,11 +414,11 @@ void Liveness::computePhiInfo() {
|
||||||
// uses of it. For each such use, check if it is reached by this phi,
|
// uses of it. For each such use, check if it is reached by this phi,
|
||||||
// i.e. check if the set of its reaching uses intersects the set of
|
// i.e. check if the set of its reaching uses intersects the set of
|
||||||
// this phi's defs.
|
// this phi's defs.
|
||||||
auto &Uses = UI->second;
|
NodeSet &Uses = UI->second;
|
||||||
for (auto I = Uses.begin(), E = Uses.end(); I != E; ) {
|
for (auto I = Uses.begin(), E = Uses.end(); I != E; ) {
|
||||||
auto UA = DFG.addr<UseNode*>(*I);
|
auto UA = DFG.addr<UseNode*>(*I);
|
||||||
NodeList RDs = getAllReachingDefs(UI->first, UA);
|
NodeList RDs = getAllReachingDefs(UI->first, UA);
|
||||||
if (any_of(RDs, HasDef))
|
if (any_of(RDs, InPhiDefs))
|
||||||
++I;
|
++I;
|
||||||
else
|
else
|
||||||
I = Uses.erase(I);
|
I = Uses.erase(I);
|
||||||
|
@ -419,26 +436,47 @@ void Liveness::computePhiInfo() {
|
||||||
|
|
||||||
// Go over all phi uses and check if the reaching def is another phi.
|
// Go over all phi uses and check if the reaching def is another phi.
|
||||||
// Collect the phis that are among the reaching defs of these uses.
|
// Collect the phis that are among the reaching defs of these uses.
|
||||||
// While traversing the list of reaching defs for each phi use, collect
|
// While traversing the list of reaching defs for each phi use, accumulate
|
||||||
// the set of registers defined between this phi (Phi) and the owner phi
|
// the set of registers defined between this phi (PhiA) and the owner phi
|
||||||
// of the reaching def.
|
// of the reaching def.
|
||||||
|
NodeSet SeenUses;
|
||||||
for (auto I : PhiRefs) {
|
for (auto I : PhiRefs) {
|
||||||
if (!DFG.IsRef<NodeAttrs::Use>(I))
|
if (!DFG.IsRef<NodeAttrs::Use>(I) || SeenUses.count(I.Id))
|
||||||
continue;
|
continue;
|
||||||
NodeAddr<UseNode*> UA = I;
|
NodeAddr<UseNode*> UA = I;
|
||||||
auto &UpMap = PhiUp[UA.Id];
|
std::map<NodeId,RegisterSet> &PUM = PhiUp[UA.Id];
|
||||||
RegisterSet DefRRs;
|
RegisterSet DefRRs;
|
||||||
for (NodeAddr<DefNode*> DA : getAllReachingDefs(UA)) {
|
NodeId RP = 0; // Phi node reached upwards.
|
||||||
if (DA.Addr->getFlags() & NodeAttrs::PhiRef)
|
|
||||||
UpMap[DA.Addr->getOwner(DFG).Id] = DefRRs;
|
for (NodeAddr<UseNode*> VA : DFG.getRelatedRefs(PhiA, UA)) {
|
||||||
else
|
SeenUses.insert(VA.Id);
|
||||||
DefRRs.insert(DA.Addr->getRegRef());
|
for (NodeAddr<DefNode*> DA : getAllReachingDefs(VA)) {
|
||||||
|
if (DA.Addr->getFlags() & NodeAttrs::PhiRef) {
|
||||||
|
// For all related phi uses, if they are reached by a phi def,
|
||||||
|
// all the reaching defs must belong to the same phi node.
|
||||||
|
// The only exception to that are the function entry phis, but
|
||||||
|
// are not playing any role in the subsequent propagation.
|
||||||
|
NodeId P = DA.Addr->getOwner(DFG).Id;
|
||||||
|
if (RP == 0)
|
||||||
|
RP = P;
|
||||||
|
assert(P == RP || (isEntryPhi(P) && isEntryPhi(RP)));
|
||||||
|
} else
|
||||||
|
DefRRs.insert(DA.Addr->getRegRef());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// Do not add reaching information for entry phis. The data collection
|
||||||
|
// above was done under the assumption that registers on all phis
|
||||||
|
// contain all actual data-flow (i.e. a phi for R0 will not convey
|
||||||
|
// data-flow information for D0). This is not true for entry phis.
|
||||||
|
// They are not participating in the propagation anyway, so that is
|
||||||
|
// not a problem.
|
||||||
|
if (RP && !isEntryPhi(RP))
|
||||||
|
PUM[RP] = DefRRs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Trace) {
|
if (Trace) {
|
||||||
dbgs() << "Phi-up-to-phi map:\n";
|
dbgs() << "Phi-up-to-phi map with intervening defs:\n";
|
||||||
for (auto I : PhiUp) {
|
for (auto I : PhiUp) {
|
||||||
dbgs() << "phi " << Print<NodeId>(I.first, DFG) << " -> {";
|
dbgs() << "phi " << Print<NodeId>(I.first, DFG) << " -> {";
|
||||||
for (auto R : I.second)
|
for (auto R : I.second)
|
||||||
|
@ -468,40 +506,44 @@ void Liveness::computePhiInfo() {
|
||||||
//
|
//
|
||||||
// When propagating uses up the phi chains, get the all reaching defs
|
// When propagating uses up the phi chains, get the all reaching defs
|
||||||
// for a given phi use, and traverse the list until the propagated ref
|
// for a given phi use, and traverse the list until the propagated ref
|
||||||
// is covered, or until or until reaching the final phi. Only assume
|
// is covered, or until reaching the final phi. Only assume that the
|
||||||
// that the reference reaches the phi in the latter case.
|
// reference reaches the phi in the latter case.
|
||||||
|
|
||||||
for (unsigned i = 0; i < PhiUQ.size(); ++i) {
|
for (unsigned i = 0; i < PhiUQ.size(); ++i) {
|
||||||
auto PA = DFG.addr<PhiNode*>(PhiUQ[i]);
|
auto PA = DFG.addr<PhiNode*>(PhiUQ[i]);
|
||||||
auto &RealUses = RealUseMap[PA.Id];
|
NodeList PUs = PA.Addr->members_if(DFG.IsRef<NodeAttrs::Use>, DFG);
|
||||||
for (auto U : PA.Addr->members_if(DFG.IsRef<NodeAttrs::Use>, DFG)) {
|
RefMap &RUM = RealUseMap[PA.Id];
|
||||||
|
|
||||||
|
for (auto U : PUs) {
|
||||||
NodeAddr<UseNode*> UA = U;
|
NodeAddr<UseNode*> UA = U;
|
||||||
auto &UpPhis = PhiUp[UA.Id];
|
std::map<NodeId,RegisterSet> &PUM = PhiUp[UA.Id];
|
||||||
for (auto UP : UpPhis) {
|
for (const std::pair<NodeId,RegisterSet> &P : PUM) {
|
||||||
bool Changed = false;
|
bool Changed = false;
|
||||||
auto &MidDefs = UP.second;
|
RegisterSet MidDefs = P.second;
|
||||||
|
|
||||||
// Collect the set UpReached of uses that are reached by the current
|
// Collect the set UpReached of uses that are reached by the current
|
||||||
// phi PA, and are not covered by any intervening def between PA and
|
// phi PA, and are not covered by any intervening def between PA and
|
||||||
// the upward phi UP.
|
// the upward phi P.
|
||||||
RegisterSet UpReached;
|
RegisterSet UpReached;
|
||||||
for (auto T : RealUses) {
|
for (const std::pair<RegisterRef,NodeSet> &T : RUM) {
|
||||||
if (!isRestricted(PA, UA, T.first))
|
RegisterRef R = T.first;
|
||||||
continue;
|
if (!isRestrictedToRef(PA, UA, R))
|
||||||
if (!RAI.covers(MidDefs, T.first))
|
R = getRestrictedRegRef(UA);
|
||||||
UpReached.insert(T.first);
|
if (!RAI.covers(MidDefs, R))
|
||||||
|
UpReached.insert(R);
|
||||||
}
|
}
|
||||||
if (UpReached.empty())
|
if (UpReached.empty())
|
||||||
continue;
|
continue;
|
||||||
// Update the set PRUs of real uses reached by the upward phi UP with
|
// Update the set PRUs of real uses reached by the upward phi P with
|
||||||
// the actual set of uses (UpReached) that the UP phi reaches.
|
// the actual set of uses (UpReached) that the P phi reaches.
|
||||||
auto &PRUs = RealUseMap[UP.first];
|
RefMap &PRUs = RealUseMap[P.first];
|
||||||
for (auto R : UpReached) {
|
for (auto R : UpReached) {
|
||||||
unsigned Z = PRUs[R].size();
|
unsigned Z = PRUs[R].size();
|
||||||
PRUs[R].insert(RealUses[R].begin(), RealUses[R].end());
|
PRUs[R].insert(RUM[R].begin(), RUM[R].end());
|
||||||
Changed |= (PRUs[R].size() != Z);
|
Changed |= (PRUs[R].size() != Z);
|
||||||
}
|
}
|
||||||
if (Changed)
|
if (Changed)
|
||||||
PhiUQ.push_back(UP.first);
|
PhiUQ.push_back(P.first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -603,7 +645,7 @@ void Liveness::computeLiveIns() {
|
||||||
auto &LOX = PhiLOX[PrA.Addr->getCode()];
|
auto &LOX = PhiLOX[PrA.Addr->getCode()];
|
||||||
for (auto R : RUs) {
|
for (auto R : RUs) {
|
||||||
RegisterRef RR = R.first;
|
RegisterRef RR = R.first;
|
||||||
if (!isRestricted(PA, UA, RR))
|
if (!isRestrictedToRef(PA, UA, RR))
|
||||||
RR = getRestrictedRegRef(UA);
|
RR = getRestrictedRegRef(UA);
|
||||||
// The restricted ref may be different from the ref that was
|
// The restricted ref may be different from the ref that was
|
||||||
// accessed in the "real use". This means that this phi use
|
// accessed in the "real use". This means that this phi use
|
||||||
|
@ -726,11 +768,14 @@ void Liveness::resetKills(MachineBasicBlock *B) {
|
||||||
|
|
||||||
|
|
||||||
// For shadows, determine if RR is aliased to a reaching def of any other
|
// For shadows, determine if RR is aliased to a reaching def of any other
|
||||||
// shadow associated with RA. If it is not, then RR is "restricted" to RA,
|
// shadow associated with RA. The register ref on RA will be "larger" than
|
||||||
// and so it can be considered a value specific to RA. This is important
|
// each individual reaching def, and to determine the data-flow between defs
|
||||||
// for accurately determining values associated with phi uses.
|
// and uses of RR it may be necessary to visit all shadows. If RR is not
|
||||||
|
// aliased to the reaching def of any other shadow, then visiting only RA
|
||||||
|
// is sufficient. In that sense, the data flow of RR would be restricted to
|
||||||
|
// the reference RA.
|
||||||
// For non-shadows, this function returns "true".
|
// For non-shadows, this function returns "true".
|
||||||
bool Liveness::isRestricted(NodeAddr<InstrNode*> IA, NodeAddr<RefNode*> RA,
|
bool Liveness::isRestrictedToRef(NodeAddr<InstrNode*> IA, NodeAddr<RefNode*> RA,
|
||||||
RegisterRef RR) const {
|
RegisterRef RR) const {
|
||||||
NodeId Start = RA.Id;
|
NodeId Start = RA.Id;
|
||||||
for (NodeAddr<RefNode*> TA = DFG.getNextShadow(IA, RA);
|
for (NodeAddr<RefNode*> TA = DFG.getNextShadow(IA, RA);
|
||||||
|
|
|
@ -96,7 +96,7 @@ namespace rdf {
|
||||||
// the dominator tree), create a map: block -> set of uses live on exit.
|
// the dominator tree), create a map: block -> set of uses live on exit.
|
||||||
std::map<MachineBasicBlock*,RefMap> PhiLOX;
|
std::map<MachineBasicBlock*,RefMap> PhiLOX;
|
||||||
|
|
||||||
bool isRestricted(NodeAddr<InstrNode*> IA, NodeAddr<RefNode*> RA,
|
bool isRestrictedToRef(NodeAddr<InstrNode*> IA, NodeAddr<RefNode*> RA,
|
||||||
RegisterRef RR) const;
|
RegisterRef RR) const;
|
||||||
RegisterRef getRestrictedRegRef(NodeAddr<RefNode*> RA) const;
|
RegisterRef getRestrictedRegRef(NodeAddr<RefNode*> RA) const;
|
||||||
unsigned getPhysReg(RegisterRef RR) const;
|
unsigned getPhysReg(RegisterRef RR) const;
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
; RUN: llc -march=hexagon -verify-machineinstrs < %s | FileCheck %s
|
||||||
|
; Check that we don't crash.
|
||||||
|
; CHECK: call printf
|
||||||
|
target triple = "hexagon"
|
||||||
|
|
||||||
|
%struct.1 = type { i16, i8, i32, i8*, i8*, i8*, i8*, i8*, i8*, i32* }
|
||||||
|
%struct.0 = type { i32, i32, i32, i32, i32, i32, i32, i32, i32 }
|
||||||
|
|
||||||
|
declare void @foo(%struct.1*, %struct.0* readonly) local_unnamed_addr #0
|
||||||
|
declare zeroext i8 @bar() local_unnamed_addr #0
|
||||||
|
declare i32 @printf(i8* nocapture readonly, ...) local_unnamed_addr #0
|
||||||
|
|
||||||
|
@.str = private unnamed_addr constant [5 x i8] c"blah\00", align 1
|
||||||
|
|
||||||
|
define i32 @main(i32 %argc, i8** nocapture readonly %argv) local_unnamed_addr #0 {
|
||||||
|
entry:
|
||||||
|
%t0 = alloca %struct.0, align 4
|
||||||
|
br label %do.body
|
||||||
|
|
||||||
|
do.body: ; preds = %if.end88.do.body_crit_edge, %entry
|
||||||
|
%cond = icmp eq i32 undef, 0
|
||||||
|
br i1 %cond, label %if.end49, label %if.then124
|
||||||
|
|
||||||
|
if.end49: ; preds = %do.body
|
||||||
|
br i1 undef, label %if.end55, label %if.then53
|
||||||
|
|
||||||
|
if.then53: ; preds = %if.end49
|
||||||
|
call void @foo(%struct.1* null, %struct.0* nonnull %t0)
|
||||||
|
br label %if.end55
|
||||||
|
|
||||||
|
if.end55: ; preds = %if.then53, %if.end49
|
||||||
|
%call76 = call zeroext i8 @bar() #0
|
||||||
|
switch i8 %call76, label %sw.epilog79 [
|
||||||
|
i8 0, label %sw.bb77
|
||||||
|
i8 3, label %sw.bb77
|
||||||
|
]
|
||||||
|
|
||||||
|
sw.bb77: ; preds = %if.end55, %if.end55
|
||||||
|
unreachable
|
||||||
|
|
||||||
|
sw.epilog79: ; preds = %if.end55
|
||||||
|
br i1 undef, label %if.end88, label %if.then81
|
||||||
|
|
||||||
|
if.then81: ; preds = %sw.epilog79
|
||||||
|
%div87 = fdiv float 0.000000e+00, undef
|
||||||
|
br label %if.end88
|
||||||
|
|
||||||
|
if.end88: ; preds = %if.then81, %sw.epilog79
|
||||||
|
%t1 = phi float [ undef, %sw.epilog79 ], [ %div87, %if.then81 ]
|
||||||
|
%div89 = fdiv float 1.000000e+00, %t1
|
||||||
|
%.sroa.speculated = select i1 undef, float 0.000000e+00, float undef
|
||||||
|
%conv108 = fpext float %.sroa.speculated to double
|
||||||
|
%call113 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i32 0, i32 0), double undef, double %conv108, i64 undef, i32 undef) #0
|
||||||
|
br i1 undef, label %if.end88.do.body_crit_edge, label %if.then124
|
||||||
|
|
||||||
|
if.end88.do.body_crit_edge: ; preds = %if.end88
|
||||||
|
br label %do.body
|
||||||
|
|
||||||
|
if.then124: ; preds = %if.end88, %do.body
|
||||||
|
%t2 = phi float [ undef, %do.body ], [ %t1, %if.end88 ]
|
||||||
|
ret i32 0
|
||||||
|
}
|
||||||
|
|
||||||
|
attributes #0 = { nounwind }
|
Loading…
Reference in New Issue