r206681 - Thread Safety Analysis: Convert to minimal SSA.

DeLesley Hutchins delesley at google.com
Fri Apr 18 20:54:41 PDT 2014


Author: delesley
Date: Fri Apr 18 22:54:41 2014
New Revision: 206681

URL: http://llvm.org/viewvc/llvm-project?rev=206681&view=rev
Log:
Thread Safety Analysis:  Convert to minimal SSA.

Modified:
    cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h
    cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h
    cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h
    cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp

Modified: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h?rev=206681&r1=206680&r2=206681&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h Fri Apr 18 22:54:41 2014
@@ -365,6 +365,7 @@ private:
   LVarDefinitionMap CurrentLVarMap;
   std::vector<til::Variable*> CurrentArguments;
   std::vector<til::Variable*> CurrentInstructions;
+  std::vector<til::Variable*> IncompleteArgs;
   til::BasicBlock *CurrentBB;
   BlockInfo *CurrentBlockInfo;
 };

Modified: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h?rev=206681&r1=206680&r2=206681&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h Fri Apr 18 22:54:41 2014
@@ -162,7 +162,7 @@ private:
 
 // Contains various helper functions for SExprs.
 namespace ThreadSafetyTIL {
-  inline bool isTrivial(SExpr *E) {
+  inline bool isTrivial(const SExpr *E) {
     unsigned Op = E->opcode();
     return Op == COP_Variable || Op == COP_Literal || Op == COP_LiteralPtr;
   }
@@ -209,6 +209,7 @@ public:
 
   // Returns the definition (for let vars) or type (for parameter & self vars)
   SExpr *definition() { return Definition.get(); }
+  const SExpr *definition() const { return Definition.get(); }
 
   void attachVar() const { ++NumUses; }
   void detachVar() const { assert(NumUses > 0); --NumUses; }
@@ -1107,6 +1108,15 @@ public:
   // TODO: change to SExprRef
   typedef SimpleArray<SExpr *> ValArray;
 
+  // In minimal SSA form, all Phi nodes are MultiVal.
+  // During conversion to SSA, incomplete Phi nodes may be introduced, which
+  // are later determined to be SingleVal.
+  enum Status {
+    PH_MultiVal = 0, // Phi node has multiple distinct values.  (Normal)
+    PH_SingleVal,    // Phi node has one distinct value, and can be eliminated
+    PH_Incomplete    // Phi node is incomplete
+  };
+
   static bool classof(const SExpr *E) { return E->opcode() == COP_Phi; }
 
   Phi(MemRegionRef A, unsigned Nvals) : SExpr(COP_Phi), Values(A, Nvals) {}
@@ -1116,14 +1126,8 @@ public:
   const ValArray &values() const { return Values; }
   ValArray &values() { return Values; }
 
-  // Incomplete phi nodes are constructed during SSA conversion, and
-  // may not be necessary.
-  bool incomplete() const { return Flags == 1; }
-
-  void setIncomplete(bool b) {
-    if (b) Flags = 1;
-    else Flags = 0;
-  }
+  Status status() const { return static_cast<Status>(Flags); }
+  void setStatus(Status s) { Flags = s; }
 
   template <class V> typename V::R_SExpr traverse(V &Visitor) {
     typename V::template Container<typename V::R_SExpr> Nvs(Visitor,
@@ -1222,6 +1226,12 @@ private:
 };
 
 
+SExpr *getCanonicalVal(SExpr *E);
+void simplifyIncompleteArg(Variable *V, til::Phi *Ph);
+
+
+
+
 } // end namespace til
 } // end namespace threadSafety
 } // end namespace clang

Modified: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h?rev=206681&r1=206680&r2=206681&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h Fri Apr 18 22:54:41 2014
@@ -505,16 +505,42 @@ protected:
   }
 
   void printLiteral(Literal *E, StreamType &SS) {
-    // TODO: actually pretty print the literal.
-    SS << "#lit";
+    const clang::Expr *CE = E->clangExpr();
+    switch (CE->getStmtClass()) {
+      case Stmt::IntegerLiteralClass:
+        SS << cast<IntegerLiteral>(CE)->getValue().toString(10, true);
+        return;
+      case Stmt::StringLiteralClass:
+        SS << "\"" << cast<StringLiteral>(CE)->getString() << "\"";
+        return;
+      case Stmt::CharacterLiteralClass:
+      case Stmt::CXXNullPtrLiteralExprClass:
+      case Stmt::GNUNullExprClass:
+      case Stmt::CXXBoolLiteralExprClass:
+      case Stmt::FloatingLiteralClass:
+      case Stmt::ImaginaryLiteralClass:
+      case Stmt::ObjCStringLiteralClass:
+      default:
+        SS << "#lit";
+        return;
+    }
   }
 
   void printLiteralPtr(LiteralPtr *E, StreamType &SS) {
     SS << E->clangDecl()->getNameAsString();
   }
 
-  void printVariable(Variable *E, StreamType &SS) {
+  void printVariable(Variable *E, StreamType &SS, bool IsVarDecl = false) {
     SS << E->name() << E->getBlockID() << "_" << E->getID();
+    if (IsVarDecl)
+      return;
+
+    SExpr *V = getCanonicalVal(E);
+    if (V != E) {
+      SS << "{";
+      printSExpr(V, SS, Prec_MAX);
+      SS << "}";
+    }
   }
 
   void printFunction(Function *E, StreamType &SS, unsigned sugared = 0) {
@@ -528,7 +554,7 @@ protected:
         SS << ", ";    // Curried functions
         break;
     }
-    self()->printVariable(E->variableDecl(), SS);
+    self()->printVariable(E->variableDecl(), SS, true);
     SS << ": ";
     self()->printSExpr(E->variableDecl()->definition(), SS, Prec_MAX);
 
@@ -541,7 +567,7 @@ protected:
 
   void printSFunction(SFunction *E, StreamType &SS) {
     SS << "@";
-    self()->printVariable(E->variableDecl(), SS);
+    self()->printVariable(E->variableDecl(), SS, true);
     SS << " ";
     self()->printSExpr(E->body(), SS, Prec_Decl);
   }
@@ -632,7 +658,7 @@ protected:
       newline(SS);
       for (auto A : BBI->arguments()) {
         SS << "let ";
-        self()->printVariable(A, SS);
+        self()->printVariable(A, SS, true);
         SS << " = ";
         self()->printSExpr(A->definition(), SS, Prec_MAX);
         SS << ";";
@@ -641,7 +667,7 @@ protected:
       for (auto I : BBI->instructions()) {
         if (I->definition()->opcode() != COP_Store) {
           SS << "let ";
-          self()->printVariable(I, SS);
+          self()->printVariable(I, SS, true);
           SS << " = ";
         }
         self()->printSExpr(I->definition(), SS, Prec_MAX);
@@ -663,11 +689,16 @@ protected:
   void printPhi(Phi *E, StreamType &SS) {
     SS << "phi(";
     unsigned i = 0;
-    for (auto V : E->values()) {
-      if (i > 0)
-        SS << ", ";
-      self()->printSExpr(V, SS, Prec_MAX);
-      ++i;
+    if (E->status() == Phi::PH_SingleVal) {
+      self()->printSExpr(E->values()[0], SS, Prec_MAX);
+    }
+    else {
+      for (auto V : E->values()) {
+        if (i > 0)
+          SS << ", ";
+        self()->printSExpr(V, SS, Prec_MAX);
+        ++i;
+      }
     }
     SS << ")";
   }

Modified: cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp?rev=206681&r1=206680&r2=206681&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp (original)
+++ cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp Fri Apr 18 22:54:41 2014
@@ -36,6 +36,65 @@
 namespace clang {
 namespace threadSafety {
 
+namespace til {
+
+// If E is a variable, then trace back through any aliases or redundant
+// Phi nodes to find the canonical definition.
+SExpr *getCanonicalVal(SExpr *E) {
+  while (auto *V = dyn_cast<Variable>(E)) {
+    SExpr *D;
+    do {
+      if (V->kind() != Variable::VK_Let)
+        return V;
+      D = V->definition();
+      if (auto *V2 = dyn_cast<Variable>(D)) {
+        V = V2;
+        continue;
+      }
+    } while(false);
+
+    if (ThreadSafetyTIL::isTrivial(D))
+      return D;
+
+    if (Phi *Ph = dyn_cast<Phi>(D)) {
+      if (Ph->status() == Phi::PH_Incomplete)
+        simplifyIncompleteArg(V, Ph);
+
+      if (Ph->status() == Phi::PH_SingleVal) {
+        E = Ph->values()[0];
+        continue;
+      }
+    }
+    return V;
+  }
+  return E;
+}
+
+
+// Trace the arguments of an incomplete Phi node to see if they have the same
+// canonical definition.  If so, mark the Phi node as redundant.
+// getCanonicalVal() will recursively call simplifyIncompletePhi().
+void simplifyIncompleteArg(Variable *V, til::Phi *Ph) {
+  assert(!Ph && Ph->status() == Phi::PH_Incomplete);
+
+  // eliminate infinite recursion -- assume that this node is not redundant.
+  Ph->setStatus(Phi::PH_MultiVal);
+
+  SExpr *E0 = getCanonicalVal(Ph->values()[0]);
+  for (unsigned i=1, n=Ph->values().size(); i<n; ++i) {
+    SExpr *Ei = getCanonicalVal(Ph->values()[i]);
+    if (Ei == V)
+      continue;  // Recursive reference to itself.  Don't count.
+    if (Ei != E0) {
+      return;    // Status is already set to MultiVal.
+    }
+  }
+  Ph->setStatus(Phi::PH_SingleVal);
+}
+
+}  // end namespace til
+
+
 typedef SExprBuilder::CallingContext CallingContext;
 
 
@@ -416,19 +475,6 @@ til::SExpr *SExprBuilder::updateVarDecl(
 }
 
 
-// Return true if the given expression represents a possibly unnecessary
-// variable: i.e. a variable that references a Phi node that may be removed.
-inline bool isIncompleteVar(til::SExpr *E) {
-  if (!E)
-    return true;  // Null values are used on unknown backedges.
-  if (til::Variable *V = dyn_cast<til::Variable>(E)) {
-    if (til::Phi *Ph = dyn_cast<til::Phi>(V->definition()))
-      return Ph->incomplete();
-  }
-  return false;
-}
-
-
 // Make a Phi node in the current block for the i^th variable in CurrentVarMap.
 // If E != null, sets Phi[CurrentBlockInfo->ArgIndex] = E.
 // If E == null, this is a backedge and will be set later.
@@ -444,8 +490,6 @@ void SExprBuilder::makePhiNodeVar(unsign
     assert(Ph && "Expecting Phi node.");
     if (E)
       Ph->values()[ArgIndex] = E;
-    if (!Ph->incomplete() && isIncompleteVar(E))
-      Ph->setIncomplete(true);
     return;
   }
 
@@ -457,12 +501,16 @@ void SExprBuilder::makePhiNodeVar(unsign
     Ph->values()[PIdx] = CurrentLVarMap[i].second;
   if (E)
     Ph->values()[ArgIndex] = E;
-  if (isIncompleteVar(E))
-    Ph->setIncomplete(true);
+  if (!E) {
+    // This is a non-minimal SSA node, which may be removed later.
+    Ph->setStatus(til::Phi::PH_Incomplete);
+  }
 
   // Add Phi node to current block, and update CurrentLVarMap[i]
   auto *Var = new (Arena) til::Variable(Ph, CurrentLVarMap[i].first);
   CurrentArguments.push_back(Var);
+  if (Ph->status() == til::Phi::PH_Incomplete)
+    IncompleteArgs.push_back(Var);
 
   CurrentLVarMap.makeWritable();
   CurrentLVarMap.elem(i).second = Var;
@@ -680,8 +728,15 @@ void SExprBuilder::exitCFGBlock(const CF
 
 
 void SExprBuilder::exitCFG(const CFGBlock *Last) {
+  for (auto *V : IncompleteArgs) {
+    til::Phi *Ph = dyn_cast<til::Phi>(V->definition());
+    if (Ph && Ph->status() == til::Phi::PH_Incomplete)
+      simplifyIncompleteArg(V, Ph);
+  }
+
   CurrentArguments.clear();
   CurrentInstructions.clear();
+  IncompleteArgs.clear();
 }
 
 





More information about the cfe-commits mailing list