[cfe-commits] r147670 - /cfe/trunk/lib/Analysis/ThreadSafety.cpp

DeLesley Hutchins delesley at google.com
Fri Jan 6 10:36:09 PST 2012


Author: delesley
Date: Fri Jan  6 12:36:09 2012
New Revision: 147670

URL: http://llvm.org/viewvc/llvm-project?rev=147670&view=rev
Log:
Added LocalVariableMap

Modified:
    cfe/trunk/lib/Analysis/ThreadSafety.cpp

Modified: cfe/trunk/lib/Analysis/ThreadSafety.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafety.cpp?rev=147670&r1=147669&r2=147670&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/ThreadSafety.cpp (original)
+++ cfe/trunk/lib/Analysis/ThreadSafety.cpp Fri Jan  6 12:36:09 2012
@@ -32,7 +32,9 @@
 #include "llvm/ADT/PostOrderIterator.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/Support/raw_ostream.h"
 #include <algorithm>
+#include <utility>
 #include <vector>
 
 using namespace clang;
@@ -283,6 +285,498 @@
 /// A Lockset maps each MutexID (defined above) to information about how it has
 /// been locked.
 typedef llvm::ImmutableMap<MutexID, LockData> Lockset;
+typedef llvm::ImmutableMap<NamedDecl*, unsigned> LocalVarContext;
+
+class LocalVariableMap;
+
+
+/// CFGBlockInfo is a struct which contains all the information that is
+/// maintained for each block in the CFG.  See LocalVariableMap for more
+/// information about the contexts.
+struct CFGBlockInfo {
+  Lockset EntrySet;             // Lockset held at entry to block
+  Lockset ExitSet;              // Lockset held at exit from block
+  LocalVarContext EntryContext; // Context held at entry to block
+  LocalVarContext ExitContext;  // Context held at exit from block
+  unsigned EntryIndex;          // Used to replay contexts later
+
+private:
+  CFGBlockInfo(Lockset EmptySet, LocalVarContext EmptyCtx)
+    : EntrySet(EmptySet), ExitSet(EmptySet),
+      EntryContext(EmptyCtx), ExitContext(EmptyCtx)
+  { }
+
+public:
+  static CFGBlockInfo getEmptyBlockInfo(Lockset::Factory &F,
+                                        LocalVariableMap &M);
+};
+
+
+
+// A LocalVariableMap maintains a map from local variables to their currently
+// valid definitions.  It provides SSA-like functionality when traversing the
+// CFG.  Like SSA, each definition or assignment to a variable is assigned a
+// unique name (an integer), which acts as the SSA name for that definition.
+// The total set of names is shared among all CFG basic blocks.
+// Unlike SSA, we do not rewrite expressions to replace local variables declrefs
+// with their SSA-names.  Instead, we compute a Context for each point in the
+// code, which maps local variables to the appropriate SSA-name.  This map
+// changes with each assignment.
+//
+// The map is computed in a single pass over the CFG.  Subsequent analyses can
+// then query the map to find the appropriate Context for a statement, and use
+// that Context to look up the definitions of variables.
+class LocalVariableMap {
+public:
+  typedef LocalVarContext Context;
+
+  /// A VarDefinition consists of an expression, representing the value of the
+  /// variable, along with the context in which that expression should be
+  /// interpreted.  A reference VarDefinition does not itself contain this
+  /// information, but instead contains a pointer to a previous VarDefinition.
+  struct VarDefinition {
+  public:
+    friend class LocalVariableMap;
+
+    NamedDecl *Dec;       // The original declaration for this variable.
+    Expr *Exp;            // The expression for this variable, OR
+    unsigned Ref;         // Reference to another VarDefinition
+    Context Ctx;          // The map with which Exp should be interpreted.
+
+    bool isReference() { return !Exp; }
+
+  private:
+    // Create ordinary variable definition
+    VarDefinition(NamedDecl *D, Expr *E, Context C)
+      : Dec(D), Exp(E), Ref(0), Ctx(C)
+    { }
+
+    // Create reference to previous definition
+    VarDefinition(NamedDecl *D, unsigned R, Context C)
+      : Dec(D), Exp(0), Ref(R), Ctx(C)
+    { }
+  };
+
+private:
+  Context::Factory ContextFactory;
+  std::vector<VarDefinition> VarDefinitions;
+  std::vector<unsigned> CtxIndices;
+  std::vector<std::pair<Stmt*, Context> > SavedContexts;
+
+public:
+  LocalVariableMap() {
+    // index 0 is a placeholder for undefined variables (aka phi-nodes).
+    VarDefinitions.push_back(VarDefinition(0, 0u, getEmptyContext()));
+  }
+
+  /// Look up a definition, within the given context.
+  const VarDefinition* lookup(NamedDecl *D, Context Ctx) {
+    const unsigned *i = Ctx.lookup(D);
+    if (!i)
+      return 0;
+    assert(*i < VarDefinitions.size());
+    return &VarDefinitions[*i];
+  }
+
+  /// Look up the definition for D within the given context.  Returns
+  /// NULL if the expression is not statically known.
+  Expr* lookupExpr(NamedDecl *D, Context Ctx) {
+    const unsigned *P = Ctx.lookup(D);
+    if (!P)
+      return 0;
+
+    unsigned i = *P;
+    while (i > 0) {
+      if (VarDefinitions[i].Exp)
+        return VarDefinitions[i].Exp;
+      i = VarDefinitions[i].Ref;
+    }
+    return 0;
+  }
+
+  Context getEmptyContext() { return ContextFactory.getEmptyMap(); }
+
+  /// Return the next context after processing S.  This function is used by
+  /// clients of the class to get the appropriate context when traversing the
+  /// CFG.  It must be called for every assignment or DeclStmt.
+  Context getNextContext(unsigned &CtxIndex, Stmt *S, Context C) {
+    if (SavedContexts[CtxIndex+1].first == S) {
+      CtxIndex++;
+      Context Result = SavedContexts[CtxIndex].second;
+      return Result;
+    }
+    return C;
+  }
+
+  void dumpVarDefinitionName(unsigned i) {
+    if (i == 0) {
+      llvm::errs() << "Undefined";
+      return;
+    }
+    NamedDecl *Dec = VarDefinitions[i].Dec;
+    if (!Dec) {
+      llvm::errs() << "<<NULL>>";
+      return;
+    }
+    Dec->printName(llvm::errs());
+    llvm::errs() << "." << i << " " << ((void*) Dec);
+  }
+
+  /// Dumps an ASCII representation of the variable map to llvm::errs()
+  void dump() {
+    for (unsigned i = 1, e = VarDefinitions.size(); i < e; ++i) {
+      Expr *Exp = VarDefinitions[i].Exp;
+      unsigned Ref = VarDefinitions[i].Ref;
+
+      dumpVarDefinitionName(i);
+      llvm::errs() << " = ";
+      if (Exp) Exp->dump();
+      else {
+        dumpVarDefinitionName(Ref);
+        llvm::errs() << "\n";
+      }
+    }
+  }
+
+  /// Dumps an ASCII representation of a Context to llvm::errs()
+  void dumpContext(Context C) {
+    for (Context::iterator I = C.begin(), E = C.end(); I != E; ++I) {
+      NamedDecl *D = I.getKey();
+      D->printName(llvm::errs());
+      const unsigned *i = C.lookup(D);
+      llvm::errs() << " -> ";
+      dumpVarDefinitionName(*i);
+      llvm::errs() << "\n";
+    }
+  }
+
+  /// Builds the variable map.
+  void traverseCFG(CFG *CFGraph, PostOrderCFGView *SortedGraph,
+                     std::vector<CFGBlockInfo> &BlockInfo);
+
+protected:
+  // Get the current context index
+  unsigned getContextIndex() { return SavedContexts.size()-1; }
+
+  // Save the current context for later replay
+  void saveContext(Stmt *S, Context C) {
+    SavedContexts.push_back(std::make_pair(S,C));
+  }
+
+  // Adds a new definition to the given context, and returns a new context.
+  // This method should be called when declaring a new variable.
+  Context addDefinition(NamedDecl *D, Expr *Exp, Context Ctx) {
+    assert(!Ctx.contains(D));
+    unsigned newID = VarDefinitions.size();
+    Context NewCtx = ContextFactory.add(Ctx, D, newID);
+    VarDefinitions.push_back(VarDefinition(D, Exp, Ctx));
+    return NewCtx;
+  }
+
+  // Add a new reference to an existing definition.
+  Context addReference(NamedDecl *D, unsigned i, Context Ctx) {
+    unsigned newID = VarDefinitions.size();
+    Context NewCtx = ContextFactory.add(Ctx, D, newID);
+    VarDefinitions.push_back(VarDefinition(D, i, Ctx));
+    return NewCtx;
+  }
+
+  // Updates a definition only if that definition is already in the map.
+  // This method should be called when assigning to an existing variable.
+  Context updateDefinition(NamedDecl *D, Expr *Exp, Context Ctx) {
+    if (Ctx.contains(D)) {
+      unsigned newID = VarDefinitions.size();
+      Context NewCtx = ContextFactory.remove(Ctx, D);
+      NewCtx = ContextFactory.add(NewCtx, D, newID);
+      VarDefinitions.push_back(VarDefinition(D, Exp, Ctx));
+      return NewCtx;
+    }
+    return Ctx;
+  }
+
+  // Removes a definition from the context, but keeps the variable name
+  // as a valid variable.  The index 0 is a placeholder for cleared definitions.
+  Context clearDefinition(NamedDecl *D, Context Ctx) {
+    Context NewCtx = Ctx;
+    if (NewCtx.contains(D)) {
+      NewCtx = ContextFactory.remove(NewCtx, D);
+      NewCtx = ContextFactory.add(NewCtx, D, 0);
+    }
+    return NewCtx;
+  }
+
+  // Remove a definition entirely frmo the context.
+  Context removeDefinition(NamedDecl *D, Context Ctx) {
+    Context NewCtx = Ctx;
+    if (NewCtx.contains(D)) {
+      NewCtx = ContextFactory.remove(NewCtx, D);
+    }
+    return NewCtx;
+  }
+
+  Context intersectContexts(Context C1, Context C2);
+  Context createReferenceContext(Context C);
+  void intersectBackEdge(Context C1, Context C2);
+
+  friend class VarMapBuilder;
+};
+
+
+// This has to be defined after LocalVariableMap.
+CFGBlockInfo CFGBlockInfo::getEmptyBlockInfo(Lockset::Factory &F,
+                                             LocalVariableMap &M) {
+  return CFGBlockInfo(F.getEmptyMap(), M.getEmptyContext());
+}
+
+
+/// Visitor which builds a LocalVariableMap
+class VarMapBuilder : public StmtVisitor<VarMapBuilder> {
+public:
+  LocalVariableMap* VMap;
+  LocalVariableMap::Context Ctx;
+
+  VarMapBuilder(LocalVariableMap *VM, LocalVariableMap::Context C)
+    : VMap(VM), Ctx(C) {}
+
+  void VisitDeclStmt(DeclStmt *S);
+  void VisitBinaryOperator(BinaryOperator *BO);
+};
+
+
+// Add new local variables to the variable map
+void VarMapBuilder::VisitDeclStmt(DeclStmt *S) {
+  bool modifiedCtx = false;
+  DeclGroupRef DGrp = S->getDeclGroup();
+  for (DeclGroupRef::iterator I = DGrp.begin(), E = DGrp.end(); I != E; ++I) {
+    if (VarDecl *VD = dyn_cast_or_null<VarDecl>(*I)) {
+      Expr *E = VD->getInit();
+
+      // Add local variables with trivial type to the variable map
+      QualType T = VD->getType();
+      if (T.isTrivialType(VD->getASTContext())) {
+        Ctx = VMap->addDefinition(VD, E, Ctx);
+        modifiedCtx = true;
+      }
+    }
+  }
+  if (modifiedCtx)
+    VMap->saveContext(S, Ctx);
+}
+
+// Update local variable definitions in variable map
+void VarMapBuilder::VisitBinaryOperator(BinaryOperator *BO) {
+  if (!BO->isAssignmentOp())
+    return;
+
+  Expr *LHSExp = BO->getLHS()->IgnoreParenCasts();
+
+  // Update the variable map and current context.
+  if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(LHSExp)) {
+    ValueDecl *VDec = DRE->getDecl();
+    if (Ctx.lookup(VDec)) {
+      if (BO->getOpcode() == BO_Assign)
+        Ctx = VMap->updateDefinition(VDec, BO->getRHS(), Ctx);
+      else
+        // FIXME -- handle compound assignment operators
+        Ctx = VMap->clearDefinition(VDec, Ctx);
+      VMap->saveContext(BO, Ctx);
+    }
+  }
+}
+
+
+// Computes the intersection of two contexts.  The intersection is the
+// set of variables which have the same definition in both contexts;
+// variables with different definitions are discarded.
+LocalVariableMap::Context
+LocalVariableMap::intersectContexts(Context C1, Context C2) {
+  Context Result = C1;
+  for (Context::iterator I = C1.begin(), E = C1.end(); I != E; ++I) {
+    NamedDecl *Dec = I.getKey();
+    unsigned i1 = I.getData();
+    const unsigned *i2 = C2.lookup(Dec);
+    if (!i2)             // variable doesn't exist on second path
+      Result = removeDefinition(Dec, Result);
+    else if (*i2 != i1)  // variable exists, but has different definition
+      Result = clearDefinition(Dec, Result);
+  }
+  return Result;
+}
+
+// For every variable in C, create a new variable that refers to the
+// definition in C.  Return a new context that contains these new variables.
+// (We use this for a naive implementation of SSA on loop back-edges.)
+LocalVariableMap::Context LocalVariableMap::createReferenceContext(Context C) {
+  Context Result = getEmptyContext();
+  for (Context::iterator I = C.begin(), E = C.end(); I != E; ++I) {
+    NamedDecl *Dec = I.getKey();
+    unsigned i = I.getData();
+    Result = addReference(Dec, i, Result);
+  }
+  return Result;
+}
+
+// This routine also takes the intersection of C1 and C2, but it does so by
+// altering the VarDefinitions.  C1 must be the result of an earlier call to
+// createReferenceContext.
+void LocalVariableMap::intersectBackEdge(Context C1, Context C2) {
+  for (Context::iterator I = C1.begin(), E = C1.end(); I != E; ++I) {
+    NamedDecl *Dec = I.getKey();
+    unsigned i1 = I.getData();
+    VarDefinition *VDef = &VarDefinitions[i1];
+    assert(VDef->isReference());
+
+    const unsigned *i2 = C2.lookup(Dec);
+    if (!i2 || (*i2 != i1))
+      VDef->Ref = 0;    // Mark this variable as undefined
+  }
+}
+
+
+// Traverse the CFG in topological order, so all predecessors of a block
+// (excluding back-edges) are visited before the block itself.  At
+// each point in the code, we calculate a Context, which holds the set of
+// variable definitions which are visible at that point in execution.
+// Visible variables are mapped to their definitions using an array that
+// contains all definitions.
+//
+// At join points in the CFG, the set is computed as the intersection of
+// the incoming sets along each edge, E.g.
+//
+//                       { Context                 | VarDefinitions }
+//   int x = 0;          { x -> x1                 | x1 = 0 }
+//   int y = 0;          { x -> x1, y -> y1        | y1 = 0, x1 = 0 }
+//   if (b) x = 1;       { x -> x2, y -> y1        | x2 = 1, y1 = 0, ... }
+//   else   x = 2;       { x -> x3, y -> y1        | x3 = 2, x2 = 1, ... }
+//   ...                 { y -> y1  (x is unknown) | x3 = 2, x2 = 1, ... }
+//
+// This is essentially a simpler and more naive version of the standard SSA
+// algorithm.  Those definitions that remain in the intersection are from blocks
+// that strictly dominate the current block.  We do not bother to insert proper
+// phi nodes, because they are not used in our analysis; instead, wherever
+// a phi node would be required, we simply remove that definition from the
+// context (E.g. x above).
+//
+// The initial traversal does not capture back-edges, so those need to be
+// handled on a separate pass.  Whenever the first pass encounters an
+// incoming back edge, it duplicates the context, creating new definitions
+// that refer back to the originals.  (These correspond to places where SSA
+// might have to insert a phi node.)  On the second pass, these definitions are
+// set to NULL if the the variable has changed on the back-edge (i.e. a phi
+// node was actually required.)  E.g.
+//
+//                       { Context           | VarDefinitions }
+//   int x = 0, y = 0;   { x -> x1, y -> y1  | y1 = 0, x1 = 0 }
+//   while (b)           { x -> x2, y -> y1  | [1st:] x2=x1; [2nd:] x2=NULL; }
+//     x = x+1;          { x -> x3, y -> y1  | x3 = x2 + 1, ... }
+//   ...                 { y -> y1           | x3 = 2, x2 = 1, ... }
+//
+void LocalVariableMap::traverseCFG(CFG *CFGraph,
+                                   PostOrderCFGView *SortedGraph,
+                                   std::vector<CFGBlockInfo> &BlockInfo) {
+  PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph);
+
+  CtxIndices.resize(CFGraph->getNumBlockIDs());
+
+  for (PostOrderCFGView::iterator I = SortedGraph->begin(),
+       E = SortedGraph->end(); I!= E; ++I) {
+    const CFGBlock *CurrBlock = *I;
+    int CurrBlockID = CurrBlock->getBlockID();
+    CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlockID];
+
+    VisitedBlocks.insert(CurrBlock);
+
+    // Calculate the entry context for the current block
+    bool HasBackEdges = false;
+    bool CtxInit = true;
+    for (CFGBlock::const_pred_iterator PI = CurrBlock->pred_begin(),
+         PE  = CurrBlock->pred_end(); PI != PE; ++PI) {
+      // if *PI -> CurrBlock is a back edge, so skip it
+      if (*PI == 0 || !VisitedBlocks.alreadySet(*PI)) {
+        HasBackEdges = true;
+        continue;
+      }
+
+      int PrevBlockID = (*PI)->getBlockID();
+      CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
+
+      if (CtxInit) {
+        CurrBlockInfo->EntryContext = PrevBlockInfo->ExitContext;
+        CtxInit = false;
+      }
+      else {
+        CurrBlockInfo->EntryContext =
+          intersectContexts(CurrBlockInfo->EntryContext,
+                            PrevBlockInfo->ExitContext);
+      }
+    }
+
+    // Duplicate the context if we have back-edges, so we can call
+    // intersectBackEdges later.
+    if (HasBackEdges)
+      CurrBlockInfo->EntryContext =
+        createReferenceContext(CurrBlockInfo->EntryContext);
+
+    // Create a starting context index for the current block
+    saveContext(0, CurrBlockInfo->EntryContext);
+    CurrBlockInfo->EntryIndex = getContextIndex();
+
+    // Visit all the statements in the basic block.
+    VarMapBuilder VMapBuilder(this, CurrBlockInfo->EntryContext);
+    for (CFGBlock::const_iterator BI = CurrBlock->begin(),
+         BE = CurrBlock->end(); BI != BE; ++BI) {
+      switch (BI->getKind()) {
+        case CFGElement::Statement: {
+          const CFGStmt *CS = cast<CFGStmt>(&*BI);
+          VMapBuilder.Visit(const_cast<Stmt*>(CS->getStmt()));
+          break;
+        }
+        default:
+          break;
+      }
+    }
+    CurrBlockInfo->ExitContext = VMapBuilder.Ctx;
+
+    // Mark variables on back edges as "unknown" if they've been changed.
+    for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
+         SE  = CurrBlock->succ_end(); SI != SE; ++SI) {
+      // if CurrBlock -> *SI is *not* a back edge
+      if (*SI == 0 || !VisitedBlocks.alreadySet(*SI))
+        continue;
+
+      CFGBlock *FirstLoopBlock = *SI;
+      Context LoopBegin = BlockInfo[FirstLoopBlock->getBlockID()].EntryContext;
+      Context LoopEnd   = CurrBlockInfo->ExitContext;
+      intersectBackEdge(LoopBegin, LoopEnd);
+    }
+  }
+
+  // Put an extra entry at the end of the indexed context array
+  unsigned exitID = CFGraph->getExit().getBlockID();
+  saveContext(0, BlockInfo[exitID].ExitContext);
+}
+
+
+/// \brief Class which implements the core thread safety analysis routines.
+class ThreadSafetyAnalyzer {
+  friend class BuildLockset;
+
+  ThreadSafetyHandler &Handler;
+  Lockset::Factory    LocksetFactory;
+  LocalVariableMap    LocalVarMap;
+
+public:
+  ThreadSafetyAnalyzer(ThreadSafetyHandler &H) : Handler(H) {}
+
+  Lockset intersectAndWarn(const Lockset LSet1, const Lockset LSet2,
+                           LockErrorKind LEK);
+
+  Lockset addLock(Lockset &LSet, Expr *MutexExp, const NamedDecl *D,
+                  LockKind LK, SourceLocation Loc);
+
+  void runAnalysis(AnalysisDeclContext &AC);
+};
+
 
 /// \brief We use this class to visit different types of expressions in
 /// CFGBlocks, and build up the lockset.
@@ -293,8 +787,12 @@
   friend class ThreadSafetyAnalyzer;
 
   ThreadSafetyHandler &Handler;
-  Lockset LSet;
   Lockset::Factory &LocksetFactory;
+  LocalVariableMap &LocalVarMap;
+
+  Lockset LSet;
+  LocalVariableMap::Context LVarCtx;
+  unsigned CtxIndex;
 
   // Helper functions
   void addLock(const MutexID &Mutex, const LockData &LDat);
@@ -342,13 +840,15 @@
   }
 
 public:
-  BuildLockset(ThreadSafetyHandler &Handler, Lockset LS, Lockset::Factory &F)
-    : StmtVisitor<BuildLockset>(), Handler(Handler), LSet(LS),
-      LocksetFactory(F) {}
-
-  Lockset getLockset() {
-    return LSet;
-  }
+  BuildLockset(ThreadSafetyAnalyzer *analyzer, CFGBlockInfo &Info)
+    : StmtVisitor<BuildLockset>(),
+      Handler(analyzer->Handler),
+      LocksetFactory(analyzer->LocksetFactory),
+      LocalVarMap(analyzer->LocalVarMap),
+      LSet(Info.EntrySet),
+      LVarCtx(Info.EntryContext),
+      CtxIndex(Info.EntryIndex)
+  {}
 
   void VisitUnaryOperator(UnaryOperator *UO);
   void VisitBinaryOperator(BinaryOperator *BO);
@@ -633,6 +1133,10 @@
 void BuildLockset::VisitBinaryOperator(BinaryOperator *BO) {
   if (!BO->isAssignmentOp())
     return;
+
+  // adjust the context
+  LVarCtx = LocalVarMap.getNextContext(CtxIndex, BO, LVarCtx);
+
   Expr *LHSExp = BO->getLHS()->IgnoreParenCasts();
   checkAccess(LHSExp, AK_Written);
   checkDereference(LHSExp, AK_Written);
@@ -662,6 +1166,9 @@
 }
 
 void BuildLockset::VisitDeclStmt(DeclStmt *S) {
+  // adjust the context
+  LVarCtx = LocalVarMap.getNextContext(CtxIndex, S, LVarCtx);
+
   DeclGroupRef DGrp = S->getDeclGroup();
   for (DeclGroupRef::iterator I = DGrp.begin(), E = DGrp.end(); I != E; ++I) {
     Decl *D = *I;
@@ -678,23 +1185,6 @@
 }
 
 
-/// \brief Class which implements the core thread safety analysis routines.
-class ThreadSafetyAnalyzer {
-  ThreadSafetyHandler &Handler;
-  Lockset::Factory    LocksetFactory;
-
-public:
-  ThreadSafetyAnalyzer(ThreadSafetyHandler &H) : Handler(H) {}
-
-  Lockset intersectAndWarn(const Lockset LSet1, const Lockset LSet2,
-                           LockErrorKind LEK);
-
-  Lockset addLock(Lockset &LSet, Expr *MutexExp, const NamedDecl *D,
-                  LockKind LK, SourceLocation Loc);
-
-  void runAnalysis(AnalysisDeclContext &AC);
-};
-
 /// \brief Compute the intersection of two locksets and issue warnings for any
 /// locks in the symmetric difference.
 ///
@@ -764,11 +1254,8 @@
   if (D->getAttr<NoThreadSafetyAnalysisAttr>())
     return;
 
-  // FIXME: Switch to SmallVector? Otherwise improve performance impact?
-  std::vector<Lockset> EntryLocksets(CFGraph->getNumBlockIDs(),
-                                     LocksetFactory.getEmptyMap());
-  std::vector<Lockset> ExitLocksets(CFGraph->getNumBlockIDs(),
-                                    LocksetFactory.getEmptyMap());
+  std::vector<CFGBlockInfo> BlockInfo(CFGraph->getNumBlockIDs(),
+    CFGBlockInfo::getEmptyBlockInfo(LocksetFactory, LocalVarMap));
 
   // We need to explore the CFG via a "topological" ordering.
   // That way, we will be guaranteed to have information about required
@@ -776,11 +1263,14 @@
   PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
   PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph);
 
+  // Compute SSA names for local variables
+  LocalVarMap.traverseCFG(CFGraph, SortedGraph, BlockInfo);
+
   // Add locks from exclusive_locks_required and shared_locks_required
   // to initial lockset.
   if (!SortedGraph->empty() && D->hasAttrs()) {
     const CFGBlock *FirstBlock = *SortedGraph->begin();
-    Lockset &InitialLockset = EntryLocksets[FirstBlock->getBlockID()];
+    Lockset &InitialLockset = BlockInfo[FirstBlock->getBlockID()].EntrySet;
     const AttrVec &ArgAttrs = D->getAttrs();
     for(unsigned i = 0; i < ArgAttrs.size(); ++i) {
       Attr *Attr = ArgAttrs[i];
@@ -809,12 +1299,10 @@
        E = SortedGraph->end(); I!= E; ++I) {
     const CFGBlock *CurrBlock = *I;
     int CurrBlockID = CurrBlock->getBlockID();
-
-    VisitedBlocks.insert(CurrBlock);
+    CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlockID];
 
     // Use the default initial lockset in case there are no predecessors.
-    Lockset &Entryset = EntryLocksets[CurrBlockID];
-    Lockset &Exitset = ExitLocksets[CurrBlockID];
+    VisitedBlocks.insert(CurrBlock);
 
     // Iterate through the predecessor blocks and warn if the lockset for all
     // predecessors is not the same. We take the entry lockset of the current
@@ -838,16 +1326,20 @@
         continue;
 
       int PrevBlockID = (*PI)->getBlockID();
+      CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
+
       if (!LocksetInitialized) {
-        Entryset = ExitLocksets[PrevBlockID];
+        CurrBlockInfo->EntrySet = PrevBlockInfo->ExitSet;
         LocksetInitialized = true;
       } else {
-        Entryset = intersectAndWarn(Entryset, ExitLocksets[PrevBlockID],
-                                    LEK_LockedSomePredecessors);
+        CurrBlockInfo->EntrySet =
+          intersectAndWarn(CurrBlockInfo->EntrySet, PrevBlockInfo->ExitSet,
+                           LEK_LockedSomePredecessors);
       }
     }
 
-    BuildLockset LocksetBuilder(Handler, Entryset, LocksetFactory);
+    BuildLockset LocksetBuilder(this, *CurrBlockInfo);
+    // Visit all the statements in the basic block.
     for (CFGBlock::const_iterator BI = CurrBlock->begin(),
          BE = CurrBlock->end(); BI != BE; ++BI) {
       switch (BI->getKind()) {
@@ -875,7 +1367,7 @@
           break;
       }
     }
-    Exitset = LocksetBuilder.getLockset();
+    CurrBlockInfo->ExitSet = LocksetBuilder.LSet;
 
     // For every back edge from CurrBlock (the end of the loop) to another block
     // (FirstLoopBlock) we need to check that the Lockset of Block is equal to
@@ -889,14 +1381,14 @@
         continue;
 
       CFGBlock *FirstLoopBlock = *SI;
-      Lockset PreLoop = EntryLocksets[FirstLoopBlock->getBlockID()];
-      Lockset LoopEnd = ExitLocksets[CurrBlockID];
+      Lockset PreLoop = BlockInfo[FirstLoopBlock->getBlockID()].EntrySet;
+      Lockset LoopEnd = BlockInfo[CurrBlockID].ExitSet;
       intersectAndWarn(LoopEnd, PreLoop, LEK_LockedSomeLoopIterations);
     }
   }
 
-  Lockset InitialLockset = EntryLocksets[CFGraph->getEntry().getBlockID()];
-  Lockset FinalLockset = ExitLocksets[CFGraph->getExit().getBlockID()];
+  Lockset InitialLockset = BlockInfo[CFGraph->getEntry().getBlockID()].EntrySet;
+  Lockset FinalLockset = BlockInfo[CFGraph->getExit().getBlockID()].ExitSet;
 
   // FIXME: Should we call this function for all blocks which exit the function?
   intersectAndWarn(InitialLockset, FinalLockset, LEK_LockedAtEndOfFunction);





More information about the cfe-commits mailing list