[llvm] r280855 - [RDF] Fix liveness analysis for phi nodes with shadow uses

Krzysztof Parzyszek via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 7 13:37:06 PDT 2016


Author: kparzysz
Date: Wed Sep  7 15:37:05 2016
New Revision: 280855

URL: http://llvm.org/viewvc/llvm-project?rev=280855&view=rev
Log:
[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.

Added:
    llvm/trunk/test/CodeGen/Hexagon/rdf-phi-shadows.ll
Modified:
    llvm/trunk/lib/Target/Hexagon/RDFLiveness.cpp
    llvm/trunk/lib/Target/Hexagon/RDFLiveness.h

Modified: llvm/trunk/lib/Target/Hexagon/RDFLiveness.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Hexagon/RDFLiveness.cpp?rev=280855&r1=280854&r2=280855&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Hexagon/RDFLiveness.cpp (original)
+++ llvm/trunk/lib/Target/Hexagon/RDFLiveness.cpp Wed Sep  7 15:37:05 2016
@@ -336,6 +336,13 @@ void Liveness::computePhiInfo() {
   std::map<NodeId,std::map<NodeId,RegisterSet>> PhiUp;
   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.
   for (NodeAddr<PhiNode*> PhiA : Phis) {
     // 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);
       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) {
       NodeAddr<DefNode*> DA = DFG.addr<DefNode*>(DefQ[i]);
+      // Visit all reached uses.
       NodeId UN = DA.Addr->getReachedUse();
       while (UN != 0) {
         NodeAddr<UseNode*> A = DFG.addr<UseNode*>(UN);
@@ -363,6 +377,9 @@ void Liveness::computePhiInfo() {
           RealUses[getRestrictedRegRef(A)].insert(A.Id);
         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();
       while (DN != 0) {
         NodeAddr<DefNode*> A = DFG.addr<DefNode*>(DN);
@@ -389,7 +406,7 @@ void Liveness::computePhiInfo() {
     //      = R1:0     u6     Not reached by d1 (covered collectively
     //                        by d3 and d5), but following reached
     //                        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);
     };
     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,
       // i.e. check if the set of its reaching uses intersects the set of
       // this phi's defs.
-      auto &Uses = UI->second;
+      NodeSet &Uses = UI->second;
       for (auto I = Uses.begin(), E = Uses.end(); I != E; ) {
         auto UA = DFG.addr<UseNode*>(*I);
         NodeList RDs = getAllReachingDefs(UI->first, UA);
-        if (any_of(RDs, HasDef))
+        if (any_of(RDs, InPhiDefs))
           ++I;
         else
           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.
     // Collect the phis that are among the reaching defs of these uses.
-    // While traversing the list of reaching defs for each phi use, collect
-    // the set of registers defined between this phi (Phi) and the owner phi
+    // While traversing the list of reaching defs for each phi use, accumulate
+    // the set of registers defined between this phi (PhiA) and the owner phi
     // of the reaching def.
+    NodeSet SeenUses;
     for (auto I : PhiRefs) {
-      if (!DFG.IsRef<NodeAttrs::Use>(I))
+      if (!DFG.IsRef<NodeAttrs::Use>(I) || SeenUses.count(I.Id))
         continue;
       NodeAddr<UseNode*> UA = I;
-      auto &UpMap = PhiUp[UA.Id];
+      std::map<NodeId,RegisterSet> &PUM = PhiUp[UA.Id];
       RegisterSet DefRRs;
-      for (NodeAddr<DefNode*> DA : getAllReachingDefs(UA)) {
-        if (DA.Addr->getFlags() & NodeAttrs::PhiRef)
-          UpMap[DA.Addr->getOwner(DFG).Id] = DefRRs;
-        else
-          DefRRs.insert(DA.Addr->getRegRef());
+      NodeId RP = 0;  // Phi node reached upwards.
+
+      for (NodeAddr<UseNode*> VA : DFG.getRelatedRefs(PhiA, UA)) {
+        SeenUses.insert(VA.Id);
+        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) {
-    dbgs() << "Phi-up-to-phi map:\n";
+    dbgs() << "Phi-up-to-phi map with intervening defs:\n";
     for (auto I : PhiUp) {
       dbgs() << "phi " << Print<NodeId>(I.first, DFG) << " -> {";
       for (auto R : I.second)
@@ -468,40 +506,44 @@ void Liveness::computePhiInfo() {
   //
   // 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
-  // is covered, or until or until reaching the final phi. Only assume
-  // that the reference reaches the phi in the latter case.
+  // is covered, or until reaching the final phi. Only assume that the
+  // reference reaches the phi in the latter case.
 
   for (unsigned i = 0; i < PhiUQ.size(); ++i) {
     auto PA = DFG.addr<PhiNode*>(PhiUQ[i]);
-    auto &RealUses = RealUseMap[PA.Id];
-    for (auto U : PA.Addr->members_if(DFG.IsRef<NodeAttrs::Use>, DFG)) {
+    NodeList PUs = PA.Addr->members_if(DFG.IsRef<NodeAttrs::Use>, DFG);
+    RefMap &RUM = RealUseMap[PA.Id];
+
+    for (auto U : PUs) {
       NodeAddr<UseNode*> UA = U;
-      auto &UpPhis = PhiUp[UA.Id];
-      for (auto UP : UpPhis) {
+      std::map<NodeId,RegisterSet> &PUM = PhiUp[UA.Id];
+      for (const std::pair<NodeId,RegisterSet> &P : PUM) {
         bool Changed = false;
-        auto &MidDefs = UP.second;
+        RegisterSet MidDefs = P.second;
+
         // 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
-        // the upward phi UP.
+        // the upward phi P.
         RegisterSet UpReached;
-        for (auto T : RealUses) {
-          if (!isRestricted(PA, UA, T.first))
-            continue;
-          if (!RAI.covers(MidDefs, T.first))
-            UpReached.insert(T.first);
+        for (const std::pair<RegisterRef,NodeSet> &T : RUM) {
+          RegisterRef R = T.first;
+          if (!isRestrictedToRef(PA, UA, R))
+            R = getRestrictedRegRef(UA);
+          if (!RAI.covers(MidDefs, R))
+            UpReached.insert(R);
         }
         if (UpReached.empty())
           continue;
-        // Update the set PRUs of real uses reached by the upward phi UP with
-        // the actual set of uses (UpReached) that the UP phi reaches.
-        auto &PRUs = RealUseMap[UP.first];
+        // Update the set PRUs of real uses reached by the upward phi P with
+        // the actual set of uses (UpReached) that the P phi reaches.
+        RefMap &PRUs = RealUseMap[P.first];
         for (auto R : UpReached) {
           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);
         }
         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()];
         for (auto R : RUs) {
           RegisterRef RR = R.first;
-          if (!isRestricted(PA, UA, RR))
+          if (!isRestrictedToRef(PA, UA, RR))
             RR = getRestrictedRegRef(UA);
           // The restricted ref may be different from the ref that was
           // accessed in the "real use". This means that this phi use
@@ -726,11 +768,14 @@ void Liveness::resetKills(MachineBasicBl
 
 
 // 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,
-// and so it can be considered a value specific to RA. This is important
-// for accurately determining values associated with phi uses.
+// shadow associated with RA. The register ref on RA will be "larger" than
+// each individual reaching def, and to determine the data-flow between defs
+// 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".
-bool Liveness::isRestricted(NodeAddr<InstrNode*> IA, NodeAddr<RefNode*> RA,
+bool Liveness::isRestrictedToRef(NodeAddr<InstrNode*> IA, NodeAddr<RefNode*> RA,
       RegisterRef RR) const {
   NodeId Start = RA.Id;
   for (NodeAddr<RefNode*> TA = DFG.getNextShadow(IA, RA);

Modified: llvm/trunk/lib/Target/Hexagon/RDFLiveness.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Hexagon/RDFLiveness.h?rev=280855&r1=280854&r2=280855&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Hexagon/RDFLiveness.h (original)
+++ llvm/trunk/lib/Target/Hexagon/RDFLiveness.h Wed Sep  7 15:37:05 2016
@@ -96,7 +96,7 @@ namespace rdf {
     // the dominator tree), create a map: block -> set of uses live on exit.
     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 getRestrictedRegRef(NodeAddr<RefNode*> RA) const;
     unsigned getPhysReg(RegisterRef RR) const;

Added: llvm/trunk/test/CodeGen/Hexagon/rdf-phi-shadows.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Hexagon/rdf-phi-shadows.ll?rev=280855&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Hexagon/rdf-phi-shadows.ll (added)
+++ llvm/trunk/test/CodeGen/Hexagon/rdf-phi-shadows.ll Wed Sep  7 15:37:05 2016
@@ -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
+
+ at .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 }




More information about the llvm-commits mailing list