r206676 - Thread Safety Analysis: Update SSA pass to handle loops.

DeLesley Hutchins delesley at google.com
Fri Apr 18 17:35:54 PDT 2014


Author: delesley
Date: Fri Apr 18 19:35:54 2014
New Revision: 206676

URL: http://llvm.org/viewvc/llvm-project?rev=206676&view=rev
Log:
Thread Safety Analysis:  Update SSA pass to handle loops.

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/include/clang/Analysis/Analyses/ThreadSafetyUtil.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=206676&r1=206675&r2=206676&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h Fri Apr 18 19:35:54 2014
@@ -117,8 +117,9 @@ public:
 
       V.enterCFGBlock(CurrBlock);
 
-      // Process predecessors
+      // Process predecessors, handling back edges last
       if (V.visitPredecessors()) {
+        SmallVector<CFGBlock*, 4> BackEdges;
         // Process successors
         for (CFGBlock::const_pred_iterator SI = CurrBlock->pred_begin(),
                                            SE = CurrBlock->pred_end();
@@ -127,11 +128,14 @@ public:
             continue;
 
           if (!VisitedBlocks.alreadySet(*SI)) {
-            V.handlePredecessorBackEdge(*SI);
+            BackEdges.push_back(*SI);
             continue;
           }
           V.handlePredecessor(*SI);
         }
+
+        for (auto *Blk : BackEdges)
+          V.handlePredecessorBackEdge(Blk);
       }
 
       V.enterCFGBlockBody(CurrBlock);
@@ -158,8 +162,10 @@ public:
 
       V.exitCFGBlockBody(CurrBlock);
 
-      // Process successors
+      // Process successors, handling back edges first.
       if (V.visitSuccessors()) {
+        SmallVector<CFGBlock*, 8> ForwardEdges;
+
         // Process successors
         for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
                                            SE = CurrBlock->succ_end();
@@ -167,12 +173,15 @@ public:
           if (*SI == nullptr)
             continue;
 
-          if (VisitedBlocks.alreadySet(*SI)) {
-            V.handleSuccessorBackEdge(*SI);
+          if (!VisitedBlocks.alreadySet(*SI)) {
+            ForwardEdges.push_back(*SI);
             continue;
           }
-          V.handleSuccessor(*SI);
+          V.handleSuccessorBackEdge(*SI);
         }
+
+        for (auto *Blk : ForwardEdges)
+          V.handleSuccessor(Blk);
       }
 
       V.exitCFGBlock(CurrBlock);
@@ -197,8 +206,6 @@ private:
 // Translate clang::Expr to til::SExpr.
 class SExprBuilder {
 public:
-  typedef llvm::DenseMap<const Stmt*, til::Variable*> StatementMap;
-
   /// \brief Encapsulates the lexical context of a function call.  The lexical
   /// context includes the arguments to the call, including the implicit object
   /// argument.  When an attribute containing a mutex expression is attached to
@@ -226,10 +233,9 @@ public:
 
   SExprBuilder(til::MemRegionRef A)
     : Arena(A), SelfVar(nullptr), Scfg(nullptr), CallCtx(nullptr),
-    CurrentBB(nullptr), CurrentBlockID(0), CurrentVarID(0),
-    CurrentArgIndex(0) {
+      CurrentBB(nullptr), CurrentBlockInfo(nullptr) {
     // FIXME: we don't always have a self-variable.
-    SelfVar = new (Arena)til::Variable(til::Variable::VK_SFun);
+    SelfVar = new (Arena) til::Variable(til::Variable::VK_SFun);
   }
 
   // Translate a clang statement or expression to a TIL expression.
@@ -239,6 +245,11 @@ public:
   til::SCFG  *buildCFG(CFGWalker &Walker);
 
   til::SExpr *lookupStmt(const Stmt *S);
+
+  til::BasicBlock *lookupBlock(const CFGBlock *B) {
+    return BlockMap[B->getBlockID()];
+  }
+
   const til::SCFG *getCFG() const { return Scfg; }
   til::SCFG *getCFF() { return Scfg; }
 
@@ -266,30 +277,41 @@ private:
 
   til::SExpr *translateDeclStmt(const DeclStmt *S, CallingContext *Ctx);
 
-  // Used for looking the index of a name.
-  typedef llvm::DenseMap<const ValueDecl *, unsigned> NameIndexMap;
+  // Map from statements in the clang CFG to SExprs in the til::SCFG.
+  typedef llvm::DenseMap<const Stmt*, til::SExpr*> StatementMap;
+
+  // Map from clang local variables to indices in a LVarDefinitionMap.
+  typedef llvm::DenseMap<const ValueDecl *, unsigned> LVarIndexMap;
 
-  // Used for looking up the current SSA variable for a name, by index.
-  typedef CopyOnWriteVector<std::pair<const ValueDecl *, til::SExpr *>>
-    NameVarMap;
+  // Map from local variable indices to SSA variables (or constants).
+  typedef std::pair<const ValueDecl *, til::SExpr *> NameVarPair;
+  typedef CopyOnWriteVector<NameVarPair> LVarDefinitionMap;
 
   struct BlockInfo {
-    NameVarMap ExitMap;
+    LVarDefinitionMap ExitMap;
     bool HasBackEdges;
-    unsigned SuccessorsToProcess;
-    BlockInfo() : HasBackEdges(false), SuccessorsToProcess(0) {}
+    unsigned UnprocessedSuccessors;   // Successors yet to be processed
+    unsigned ProcessedPredecessors;   // Predecessors already processed
+
+    BlockInfo()
+        : HasBackEdges(false), UnprocessedSuccessors(0),
+          ProcessedPredecessors(0) {}
     BlockInfo(BlockInfo &&RHS)
-        : ExitMap(std::move(RHS.ExitMap)), HasBackEdges(RHS.HasBackEdges),
-          SuccessorsToProcess(RHS.SuccessorsToProcess) {}
+        : ExitMap(std::move(RHS.ExitMap)),
+          HasBackEdges(RHS.HasBackEdges),
+          UnprocessedSuccessors(RHS.UnprocessedSuccessors),
+          ProcessedPredecessors(RHS.ProcessedPredecessors) {}
 
     BlockInfo &operator=(BlockInfo &&RHS) {
       if (this != &RHS) {
         ExitMap = std::move(RHS.ExitMap);
         HasBackEdges = RHS.HasBackEdges;
-        SuccessorsToProcess = RHS.SuccessorsToProcess;
+        UnprocessedSuccessors = RHS.UnprocessedSuccessors;
+        ProcessedPredecessors = RHS.ProcessedPredecessors;
       }
       return *this;
     }
+
   private:
     BlockInfo(const BlockInfo &) LLVM_DELETED_FUNCTION;
     void operator=(const BlockInfo &) LLVM_DELETED_FUNCTION;
@@ -313,31 +335,38 @@ private:
   void exitCFGBlock(const CFGBlock *B);
   void exitCFG(const CFGBlock *Last);
 
-  void insertStmt(const Stmt *S, til::Variable *V);
+  void insertStmt(const Stmt *S, til::SExpr *E) {
+    SMap.insert(std::make_pair(S, E));
+  }
+  til::SExpr *getCurrentLVarDefinition(const ValueDecl *VD);
+
   til::SExpr *addStatement(til::SExpr *E, const Stmt *S, const ValueDecl *VD=0);
   til::SExpr *lookupVarDecl(const ValueDecl *VD);
   til::SExpr *addVarDecl(const ValueDecl *VD, til::SExpr *E);
   til::SExpr *updateVarDecl(const ValueDecl *VD, til::SExpr *E);
 
-  void mergeEntryMap(NameVarMap Map);
+  void makePhiNodeVar(unsigned i, unsigned NPreds, til::SExpr *E);
+  void mergeEntryMap(LVarDefinitionMap Map);
+  void mergeEntryMapBackEdge();
+  void mergePhiNodesBackEdge(const CFGBlock *Blk);
 
+private:
   til::MemRegionRef Arena;
   til::Variable *SelfVar;       // Variable to use for 'this'.  May be null.
   til::SCFG *Scfg;
 
   StatementMap SMap;                       // Map from Stmt to TIL Variables
-  NameIndexMap IdxMap;                     // Indices of clang local vars.
+  LVarIndexMap LVarIdxMap;                 // Indices of clang local vars.
   std::vector<til::BasicBlock *> BlockMap; // Map from clang to til BBs.
   std::vector<BlockInfo> BBInfo;           // Extra information per BB.
                                            // Indexed by clang BlockID.
   SExprBuilder::CallingContext *CallCtx;   // Root calling context
 
-  NameVarMap CurrentNameMap;
+  LVarDefinitionMap CurrentLVarMap;
+  std::vector<til::Variable*> CurrentArguments;
+  std::vector<til::Variable*> CurrentInstructions;
   til::BasicBlock *CurrentBB;
   BlockInfo *CurrentBlockInfo;
-  unsigned CurrentBlockID;
-  unsigned CurrentVarID;
-  unsigned CurrentArgIndex;
 };
 
 

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=206676&r1=206675&r2=206676&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h Fri Apr 18 19:35:54 2014
@@ -952,7 +952,8 @@ public:
   static bool classof(const SExpr *E) { return E->opcode() == COP_SCFG; }
 
   SCFG(MemRegionRef A, unsigned Nblocks)
-      : SExpr(COP_SCFG), Blocks(A, Nblocks), Entry(nullptr), Exit(nullptr) {}
+      : SExpr(COP_SCFG), Blocks(A, Nblocks),
+        Entry(nullptr), Exit(nullptr) {}
   SCFG(const SCFG &Cfg, BlockArray &&Ba) // steals memory from Ba
       : SExpr(COP_SCFG), Blocks(std::move(Ba)), Entry(nullptr), Exit(nullptr) {
     // TODO: set entry and exit!
@@ -972,7 +973,7 @@ public:
   const BasicBlock *exit() const { return Exit; }
   BasicBlock *exit() { return Exit; }
 
-  void add(BasicBlock *BB) { Blocks.push_back(BB); }
+  void add(BasicBlock *BB);
   void setEntry(BasicBlock *BB) { Entry = BB; }
   void setExit(BasicBlock *BB) { Exit = BB; }
 
@@ -1001,12 +1002,12 @@ public:
 
   BasicBlock(MemRegionRef A, unsigned Nargs, unsigned Nins,
              SExpr *Term = nullptr)
-      : BlockID(0), Parent(nullptr), NumPredecessors(0),
+      : BlockID(0), NumVars(0), NumPredecessors(0), Parent(nullptr),
         Args(A, Nargs), Instrs(A, Nins), Terminator(Term) {}
   BasicBlock(const BasicBlock &B, VarArray &&As, VarArray &&Is, SExpr *T)
-      : BlockID(0), Parent(nullptr), NumPredecessors(B.NumPredecessors),
-        Args(std::move(As)), Instrs(std::move(Is)), Terminator(T)
-  {}
+      : BlockID(0),  NumVars(B.NumVars), NumPredecessors(B.NumPredecessors),
+        Parent(nullptr), Args(std::move(As)), Instrs(std::move(Is)),
+        Terminator(T) {}
 
   unsigned blockID() const { return BlockID; }
   unsigned numPredecessors() const { return NumPredecessors; }
@@ -1027,8 +1028,15 @@ public:
   void setParent(BasicBlock *P) { Parent = P; }
   void setNumPredecessors(unsigned NP) { NumPredecessors = NP; }
   void setTerminator(SExpr *E) { Terminator.reset(E); }
-  void addArgument(Variable *V) { Args.push_back(V); }
-  void addInstr(Variable *V) { Args.push_back(V); }
+
+  void addArgument(Variable *V) {
+    V->setID(BlockID, NumVars++);
+    Args.push_back(V);
+  }
+  void addInstruction(Variable *V) {
+    V->setID(BlockID, NumVars++);
+    Instrs.push_back(V);
+  }
 
   template <class V> BasicBlock *traverse(V &Visitor) {
     typename V::template Container<Variable*> Nas(Visitor, Args.size());
@@ -1064,14 +1072,23 @@ private:
   friend class SCFG;
 
   unsigned BlockID;
+  unsigned NumVars;
+  unsigned NumPredecessors; // Number of blocks which jump to this one.
+
   BasicBlock *Parent;       // The parent block is the enclosing lexical scope.
                             // The parent dominates this block.
-  unsigned NumPredecessors; // Number of blocks which jump to this one.
   VarArray Args;            // Phi nodes.  One argument per predecessor.
   VarArray Instrs;
   SExprRef Terminator;
 };
 
+
+inline void SCFG::add(BasicBlock *BB) {
+  BB->setBlockID(Blocks.size());
+  Blocks.push_back(BB);
+}
+
+
 template <class V>
 typename V::R_SExpr SCFG::traverse(V &Visitor) {
   Visitor.enterCFG(*this);
@@ -1084,6 +1101,7 @@ typename V::R_SExpr SCFG::traverse(V &Vi
   return Visitor.reduceSCFG(*this, Bbs);
 }
 
+
 class Phi : public SExpr {
 public:
   // TODO: change to SExprRef
@@ -1098,6 +1116,15 @@ 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;
+  }
+
   template <class V> typename V::R_SExpr traverse(V &Visitor) {
     typename V::template Container<typename V::R_SExpr> Nvs(Visitor,
                                                             Values.size());

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=206676&r1=206675&r2=206676&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h Fri Apr 18 19:35:54 2014
@@ -510,7 +510,7 @@ protected:
   }
 
   void printLiteralPtr(LiteralPtr *E, StreamType &SS) {
-    SS << E->clangDecl()->getName();
+    SS << E->clangDecl()->getNameAsString();
   }
 
   void printVariable(Variable *E, StreamType &SS) {

Modified: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyUtil.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyUtil.h?rev=206676&r1=206675&r2=206676&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyUtil.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyUtil.h Fri Apr 18 19:35:54 2014
@@ -80,7 +80,7 @@ public:
   SimpleArray(T *Dat, size_t Cp, size_t Sz = 0)
       : Data(Dat), Size(Sz), Capacity(Cp) {}
   SimpleArray(MemRegionRef A, size_t Cp)
-      : Data(A.allocateT<T>(Cp)), Size(0), Capacity(Cp) {}
+      : Data(Cp == 0 ? nullptr : A.allocateT<T>(Cp)), Size(0), Capacity(Cp) {}
   SimpleArray(SimpleArray<T> &&A)
       : Data(A.Data), Size(A.Size), Capacity(A.Capacity) {
     A.Data = nullptr;
@@ -100,11 +100,14 @@ public:
     return *this;
   }
 
-  T *resize(size_t Ncp, MemRegionRef A) {
+  void reserve(size_t Ncp, MemRegionRef A) {
+    if (Ncp < Capacity)
+      return;
     T *Odata = Data;
     Data = A.allocateT<T>(Ncp);
+    Capacity = Ncp;
     memcpy(Data, Odata, sizeof(T) * Size);
-    return Odata;
+    return;
   }
 
   typedef T *iterator;
@@ -134,7 +137,7 @@ public:
   }
 
   void setValues(unsigned Sz, const T& C) {
-    assert(Sz < Capacity);
+    assert(Sz <= Capacity);
     Size = Sz;
     for (unsigned i = 0; i < Sz; ++i) {
       Data[i] = C;

Modified: cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp?rev=206676&r1=206675&r2=206676&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp (original)
+++ cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp Fri Apr 18 19:35:54 2014
@@ -46,10 +46,6 @@ til::SExpr *SExprBuilder::lookupStmt(con
   return nullptr;
 }
 
-void SExprBuilder::insertStmt(const Stmt *S, til::Variable *V) {
-  SMap.insert(std::make_pair(S, V));
-}
-
 
 til::SCFG *SExprBuilder::buildCFG(CFGWalker &Walker) {
   Walker.walk(*this);
@@ -354,6 +350,7 @@ SExprBuilder::translateDeclStmt(const De
 }
 
 
+
 // If (E) is non-trivial, then add it to the current basic block, and
 // update the statement map so that S refers to E.  Returns a new variable
 // that refers to E.
@@ -366,8 +363,7 @@ til::SExpr *SExprBuilder::addStatement(t
     return E;
 
   til::Variable *V = new (Arena) til::Variable(E, VD);
-  V->setID(CurrentBlockID, CurrentVarID++);
-  CurrentBB->addInstr(V);
+  CurrentInstructions.push_back(V);
   if (S)
     insertStmt(S, V);
   return V;
@@ -376,9 +372,11 @@ til::SExpr *SExprBuilder::addStatement(t
 
 // Returns the current value of VD, if known, and nullptr otherwise.
 til::SExpr *SExprBuilder::lookupVarDecl(const ValueDecl *VD) {
-  auto It = IdxMap.find(VD);
-  if (It != IdxMap.end())
-    return CurrentNameMap[It->second].second;
+  auto It = LVarIdxMap.find(VD);
+  if (It != LVarIdxMap.end()) {
+    assert(CurrentLVarMap[It->second].first == VD);
+    return CurrentLVarMap[It->second].second;
+  }
   return nullptr;
 }
 
@@ -396,9 +394,9 @@ inline void maybeUpdateVD(til::SExpr *E,
 // Adds a new variable declaration.
 til::SExpr *SExprBuilder::addVarDecl(const ValueDecl *VD, til::SExpr *E) {
   maybeUpdateVD(E, VD);
-  IdxMap.insert(std::make_pair(VD, CurrentNameMap.size()));
-  CurrentNameMap.makeWritable();
-  CurrentNameMap.push_back(std::make_pair(VD, E));
+  LVarIdxMap.insert(std::make_pair(VD, CurrentLVarMap.size()));
+  CurrentLVarMap.makeWritable();
+  CurrentLVarMap.push_back(std::make_pair(VD, E));
   return E;
 }
 
@@ -406,76 +404,151 @@ til::SExpr *SExprBuilder::addVarDecl(con
 // Updates a current variable declaration.  (E.g. by assignment)
 til::SExpr *SExprBuilder::updateVarDecl(const ValueDecl *VD, til::SExpr *E) {
   maybeUpdateVD(E, VD);
-  auto It = IdxMap.find(VD);
-  if (It == IdxMap.end()) {
+  auto It = LVarIdxMap.find(VD);
+  if (It == LVarIdxMap.end()) {
     til::SExpr *Ptr = new (Arena) til::LiteralPtr(VD);
     til::SExpr *St  = new (Arena) til::Store(Ptr, E);
     return St;
   }
-  CurrentNameMap.makeWritable();
-  CurrentNameMap.elem(It->second).second = E;
+  CurrentLVarMap.makeWritable();
+  CurrentLVarMap.elem(It->second).second = E;
   return E;
 }
 
 
-// Merge values from Map into the current entry map.
-void SExprBuilder::mergeEntryMap(NameVarMap Map) {
+// 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.
+void SExprBuilder::makePhiNodeVar(unsigned i, unsigned NPreds, til::SExpr *E) {
+  unsigned ArgIndex = CurrentBlockInfo->ProcessedPredecessors;
+  assert(ArgIndex > 0 && ArgIndex < NPreds);
+
+  til::Variable *V = dyn_cast<til::Variable>(CurrentLVarMap[i].second);
+  if (V && V->getBlockID() == CurrentBB->blockID()) {
+    // We already have a Phi node in the current block,
+    // so just add the new variable to the Phi node.
+    til::Phi *Ph = dyn_cast<til::Phi>(V->definition());
+    assert(Ph && "Expecting Phi node.");
+    if (E)
+      Ph->values()[ArgIndex] = E;
+    if (!Ph->incomplete() && isIncompleteVar(E))
+      Ph->setIncomplete(true);
+    return;
+  }
+
+  // Make a new phi node: phi(..., E)
+  // All phi args up to the current index are set to the current value.
+  til::Phi *Ph = new (Arena) til::Phi(Arena, NPreds);
+  Ph->values().setValues(NPreds, nullptr);
+  for (unsigned PIdx = 0; PIdx < ArgIndex; ++PIdx)
+    Ph->values()[PIdx] = CurrentLVarMap[i].second;
+  if (E)
+    Ph->values()[ArgIndex] = E;
+  if (isIncompleteVar(E))
+    Ph->setIncomplete(true);
+
+  // Add Phi node to current block, and update CurrentLVarMap[i]
+  auto *Var = new (Arena) til::Variable(Ph, CurrentLVarMap[i].first);
+  CurrentArguments.push_back(Var);
+
+  CurrentLVarMap.makeWritable();
+  CurrentLVarMap.elem(i).second = Var;
+}
+
+
+// Merge values from Map into the current variable map.
+// This will construct Phi nodes in the current basic block as necessary.
+void SExprBuilder::mergeEntryMap(LVarDefinitionMap Map) {
   assert(CurrentBlockInfo && "Not processing a block!");
 
-  if (!CurrentNameMap.valid()) {
+  if (!CurrentLVarMap.valid()) {
     // Steal Map, using copy-on-write.
-    CurrentNameMap = std::move(Map);
+    CurrentLVarMap = std::move(Map);
     return;
   }
-  if (CurrentNameMap.sameAs(Map))
+  if (CurrentLVarMap.sameAs(Map))
     return;  // Easy merge: maps from different predecessors are unchanged.
 
-  unsigned ESz = CurrentNameMap.size();
+  unsigned NPreds = CurrentBB->numPredecessors();
+  unsigned ESz = CurrentLVarMap.size();
   unsigned MSz = Map.size();
-  unsigned Sz = std::max(ESz, MSz);
-  bool W = CurrentNameMap.writable();
+  unsigned Sz  = std::min(ESz, MSz);
+
   for (unsigned i=0; i<Sz; ++i) {
-    if (CurrentNameMap[i].first != Map[i].first) {
-      if (!W)
-        CurrentNameMap.makeWritable();
-      CurrentNameMap.downsize(i);
+    if (CurrentLVarMap[i].first != Map[i].first) {
+      // We've reached the end of variables in common.
+      CurrentLVarMap.makeWritable();
+      CurrentLVarMap.downsize(i);
       break;
     }
-    if (CurrentNameMap[i].second != Map[i].second) {
-      til::Variable *V =
-        dyn_cast<til::Variable>(CurrentNameMap[i].second);
-      if (V && V->getBlockID() == CurrentBB->blockID()) {
-        // We already have a Phi node, so add the new variable.
-        til::Phi *Ph = dyn_cast<til::Phi>(V->definition());
-        assert(Ph && "Expecting Phi node.");
-        Ph->values()[CurrentArgIndex] = Map[i].second;
-      }
-      else {
-        if (!W)
-          CurrentNameMap.makeWritable();
-        unsigned NPreds = CurrentBB->numPredecessors();
-        assert(CurrentArgIndex > 0 && CurrentArgIndex < NPreds);
-
-        // Make a new phi node.  All phi args up to the current index must
-        // be the same, and equal to the current NameMap value.
-        auto *Ph = new (Arena) til::Phi(Arena, NPreds);
-        Ph->values().setValues(NPreds, nullptr);
-        for (unsigned PIdx = 0; PIdx < CurrentArgIndex; ++PIdx)
-          Ph->values()[PIdx] = CurrentNameMap[i].second;
-        Ph->values()[CurrentArgIndex] = Map[i].second;
-
-        // Add phi node to current basic block.
-        auto *Var = new (Arena) til::Variable(Ph, CurrentNameMap[i].first);
-        Var->setID(CurrentBlockID, CurrentVarID++);
-        CurrentBB->addArgument(Var);
-        CurrentNameMap.elem(i).second = Var;
-      }
-    }
+    if (CurrentLVarMap[i].second != Map[i].second)
+      makePhiNodeVar(i, NPreds, Map[i].second);
   }
   if (ESz > MSz) {
-    if (!W)
-      CurrentNameMap.makeWritable();
-    CurrentNameMap.downsize(Map.size());
+    CurrentLVarMap.makeWritable();
+    CurrentLVarMap.downsize(Map.size());
+  }
+}
+
+
+// Merge a back edge into the current variable map.
+// This will create phi nodes for all variables in the variable map.
+void SExprBuilder::mergeEntryMapBackEdge() {
+  // We don't have definitions for variables on the backedge, because we
+  // haven't gotten that far in the CFG.  Thus, when encountering a back edge,
+  // we conservatively create Phi nodes for all variables.  Unnecessary Phi
+  // nodes will be marked as incomplete, and stripped out at the end.
+  //
+  // An Phi node is unnecessary if it only refers to itself and one other
+  // variable, e.g. x = Phi(y, y, x)  can be reduced to x = y.
+
+  assert(CurrentBlockInfo && "Not processing a block!");
+
+  if (CurrentBlockInfo->HasBackEdges)
+    return;
+  CurrentBlockInfo->HasBackEdges = true;
+
+  CurrentLVarMap.makeWritable();
+  unsigned Sz = CurrentLVarMap.size();
+  unsigned NPreds = CurrentBB->numPredecessors();
+
+  for (unsigned i=0; i < Sz; ++i) {
+    makePhiNodeVar(i, NPreds, nullptr);
+  }
+}
+
+
+// Update the phi nodes that were initially created for a back edge
+// once the variable definitions have been computed.
+// I.e., merge the current variable map into the phi nodes for Blk.
+void SExprBuilder::mergePhiNodesBackEdge(const CFGBlock *Blk) {
+  til::BasicBlock *BB = lookupBlock(Blk);
+  unsigned ArgIndex = BBInfo[Blk->getBlockID()].ProcessedPredecessors;
+  assert(ArgIndex > 0 && ArgIndex < BB->numPredecessors());
+
+  for (til::Variable *V : BB->arguments()) {
+    til::Phi *Ph = dyn_cast_or_null<til::Phi>(V->definition());
+    assert(Ph && "Expecting Phi Node.");
+    assert(Ph->values()[ArgIndex] == nullptr && "Wrong index for back edge.");
+    assert(V->clangDecl() && "No local variable for Phi node.");
+
+    til::SExpr *E = lookupVarDecl(V->clangDecl());
+    assert(E && "Couldn't find local variable for Phi node.");
+
+    Ph->values()[ArgIndex] = E;
   }
 }
 
@@ -488,53 +561,60 @@ void SExprBuilder::enterCFG(CFG *Cfg, co
   Scfg = new (Arena) til::SCFG(Arena, NBlocks);
 
   // allocate all basic blocks immediately, to handle forward references.
-  BlockMap.reserve(NBlocks);
   BBInfo.resize(NBlocks);
+  BlockMap.resize(NBlocks, nullptr);
+  // create map from clang blockID to til::BasicBlocks
   for (auto *B : *Cfg) {
     auto *BB = new (Arena) til::BasicBlock(Arena, 0, B->size());
-    BlockMap.push_back(BB);
+    BlockMap[B->getBlockID()] = BB;
   }
   CallCtx = new SExprBuilder::CallingContext(D);
 }
 
 
-
 void SExprBuilder::enterCFGBlock(const CFGBlock *B) {
   // Intialize TIL basic block and add it to the CFG.
   CurrentBB = BlockMap[B->getBlockID()];
-  CurrentBB->setBlockID(CurrentBlockID);
   CurrentBB->setNumPredecessors(B->pred_size());
   Scfg->add(CurrentBB);
 
   CurrentBlockInfo = &BBInfo[B->getBlockID()];
-  CurrentVarID = 0;
-  CurrentArgIndex = 0;
+  CurrentArguments.clear();
+  CurrentInstructions.clear();
 
-  assert(!CurrentNameMap.valid() && "CurrentNameMap already initialized.");
+  // CurrentLVarMap is moved to ExitMap on block exit.
+  assert(!CurrentLVarMap.valid() && "CurrentLVarMap already initialized.");
 }
 
 
 void SExprBuilder::handlePredecessor(const CFGBlock *Pred) {
-  // Compute CurrentNameMap on entry from ExitMaps of predecessors
+  // Compute CurrentLVarMap on entry from ExitMaps of predecessors
 
   BlockInfo *PredInfo = &BBInfo[Pred->getBlockID()];
-  assert(PredInfo->SuccessorsToProcess > 0);
+  assert(PredInfo->UnprocessedSuccessors > 0);
 
-  if (--PredInfo->SuccessorsToProcess == 0)
+  if (--PredInfo->UnprocessedSuccessors == 0)
     mergeEntryMap(std::move(PredInfo->ExitMap));
   else
     mergeEntryMap(PredInfo->ExitMap.clone());
 
-  ++CurrentArgIndex;
+  ++CurrentBlockInfo->ProcessedPredecessors;
 }
 
 
 void SExprBuilder::handlePredecessorBackEdge(const CFGBlock *Pred) {
-  CurrentBlockInfo->HasBackEdges = true;
+  mergeEntryMapBackEdge();
 }
 
 
-void SExprBuilder::enterCFGBlockBody(const CFGBlock *B) { }
+void SExprBuilder::enterCFGBlockBody(const CFGBlock *B) {
+  // The merge*() methods have created arguments.
+  // Push those arguments onto the basic block.
+  CurrentBB->arguments().reserve(
+    static_cast<unsigned>(CurrentArguments.size()), Arena);
+  for (auto *V : CurrentArguments)
+    CurrentBB->addArgument(V);
+}
 
 
 void SExprBuilder::handleStatement(const Stmt *S) {
@@ -555,19 +635,25 @@ void SExprBuilder::handleDestructorCall(
 
 
 void SExprBuilder::exitCFGBlockBody(const CFGBlock *B) {
+  CurrentBB->instructions().reserve(
+    static_cast<unsigned>(CurrentInstructions.size()), Arena);
+  for (auto *V : CurrentInstructions)
+    CurrentBB->addInstruction(V);
+
+  // Create an appropriate terminator
   unsigned N = B->succ_size();
   auto It = B->succ_begin();
   if (N == 1) {
-    til::BasicBlock *BB = *It ? BlockMap[(*It)->getBlockID()] : nullptr;
+    til::BasicBlock *BB = *It ? lookupBlock(*It) : nullptr;
     // TODO: set index
     til::SExpr *Tm = new (Arena) til::Goto(BB, 0);
     CurrentBB->setTerminator(Tm);
   }
   else if (N == 2) {
     til::SExpr *C = translate(B->getTerminatorCondition(true), CallCtx);
-    til::BasicBlock *BB1 = *It ? BlockMap[(*It)->getBlockID()] : nullptr;
+    til::BasicBlock *BB1 = *It ? lookupBlock(*It) : nullptr;
     ++It;
-    til::BasicBlock *BB2 = *It ? BlockMap[(*It)->getBlockID()] : nullptr;
+    til::BasicBlock *BB2 = *It ? lookupBlock(*It) : nullptr;
     // TODO: set conditional, set index
     til::SExpr *Tm = new (Arena) til::Branch(C, BB1, BB2);
     CurrentBB->setTerminator(Tm);
@@ -576,28 +662,26 @@ void SExprBuilder::exitCFGBlockBody(cons
 
 
 void SExprBuilder::handleSuccessor(const CFGBlock *Succ) {
-  ++CurrentBlockInfo->SuccessorsToProcess;
+  ++CurrentBlockInfo->UnprocessedSuccessors;
 }
 
 
 void SExprBuilder::handleSuccessorBackEdge(const CFGBlock *Succ) {
-
+  mergePhiNodesBackEdge(Succ);
+  ++BBInfo[Succ->getBlockID()].ProcessedPredecessors;
 }
 
 
 void SExprBuilder::exitCFGBlock(const CFGBlock *B) {
-  CurrentBlockInfo->ExitMap = std::move(CurrentNameMap);
-  CurrentBlockID++;
+  CurrentBlockInfo->ExitMap = std::move(CurrentLVarMap);
   CurrentBB = nullptr;
   CurrentBlockInfo = nullptr;
 }
 
 
 void SExprBuilder::exitCFG(const CFGBlock *Last) {
-  CurrentBlockID = 0;
-  CurrentVarID = 0;
-  CurrentArgIndex = 0;
-  delete CallCtx;
+  CurrentArguments.clear();
+  CurrentInstructions.clear();
 }
 
 





More information about the cfe-commits mailing list