r206338 - Thread Safety Analysis: rewrite SSA pass to use the new SExpr and CFG

Timur Iskhodzhanov timurrrr at google.com
Wed Apr 16 01:48:34 PDT 2014


... or is it?

After fixing another compile-time error I get this:

C:\Program Files (x86)\Microsoft Visual Studio
12.0\VC\INCLUDE\xutility(829) : error C2280:
'clang::threadSafety::CopyOnWriteVector<std::pair<const
clang::ValueDecl *,clang::threadSafety::til::SExpr
*>>::CopyOnWriteVector(const
clang::threadSafety::CopyOnWriteVector<std::pair<const
clang::ValueDecl *,clang::threadSafety::til::SExpr *>> &)' :
attempting to reference a deleted function


        tools\clang\include\clang/Analysis/Analyses/ThreadSafetyUtil.h(172)
: see declaration of
'clang::threadSafety::CopyOnWriteVector<std::pair<const
clang::ValueDecl *,clang::threadSafety::til::SExpr
*>>::CopyOnWriteVector'

2014-04-16 12:22 GMT+04:00 Timur Iskhodzhanov <timurrrr at google.com>:
> Ah, sorry -- the build is broken due to a different reason now.
>
> 2014-04-16 12:16 GMT+04:00 Timur Iskhodzhanov <timurrrr at google.com>:
>> Request timeout -- I'm going to revert the change.
>>
>> 2014-04-16 7:24 GMT+04:00 Renato Golin <renato.golin at linaro.org>:
>>> Hi DeLesley,
>>>
>>> Have you seen this error?
>>>
>>> http://lab.llvm.org:8011/builders/clang-native-arm-lnt/builds/5991/steps/compile/logs/stdio
>>>
>>> /external/buildbot/clang-native-arm-lnt/llvm.src/tools/clang/lib/Analysis/../../include/clang/Analysis/Analyses/ThreadSafetyUtil.h:105:16:
>>> error: ‘Sz’ was not declared in this scope
>>>      assert(i < Sz && "Array index out of bounds.");
>>>
>>> cheers,
>>> --renato
>>>
>>> On 15 April 2014 20:23, DeLesley Hutchins <delesley at google.com> wrote:
>>>> Author: delesley
>>>> Date: Tue Apr 15 18:23:19 2014
>>>> New Revision: 206338
>>>>
>>>> URL: http://llvm.org/viewvc/llvm-project?rev=206338&view=rev
>>>> Log:
>>>> Thread Safety Analysis: rewrite SSA pass to use the new SExpr and CFG
>>>> traversal system.  The new pass is still undergoing testing; no change in
>>>> functionality.
>>>>
>>>> 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=206338&r1=206337&r2=206338&view=diff
>>>> ==============================================================================
>>>> --- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h (original)
>>>> +++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h Tue Apr 15 18:23:19 2014
>>>> @@ -33,32 +33,53 @@
>>>>  namespace clang {
>>>>  namespace threadSafety {
>>>>
>>>> -// CFG traversal uses templates instead of virtual function dispatch. Visitors
>>>> -// must implement the following functions:
>>>> -//
>>>> -// Enter the CFG for Decl D, and perform any initial setup operations.
>>>> -// void enterCFG(CFG *Cfg, const NamedDecl *D, const CFGBlock *First) {}
>>>> -//
>>>> -// Enter a CFGBlock.
>>>> -// void enterCFGBlock(const CFGBlock *B) {}
>>>> -//
>>>> -// Process an ordinary statement.
>>>> -// void handleStatement(const Stmt *S) {}
>>>> -//
>>>> -// Process a destructor call
>>>> -// void handleDestructorCall(const VarDecl *VD, const CXXDestructorDecl *DD) {}
>>>> -//
>>>> -// Process a successor edge.
>>>> -// void handleSuccessor(const CFGBlock *Succ) {}
>>>> -//
>>>> -// Process a successor back edge to a previously visited block.
>>>> -// void handleSuccessorBackEdge(const CFGBlock *Succ) {}
>>>> -//
>>>> -// Leave a CFGBlock.
>>>> -// void exitCFGBlock(const CFGBlock *B) {}
>>>> -//
>>>> -// Leave the CFG, and perform any final cleanup operations.
>>>> -// void exitCFG(const CFGBlock *Last) {}
>>>> +// This class defines the interface of a clang CFG Visitor.
>>>> +// CFGWalker will invoke the following methods.
>>>> +// Note that methods are not virtual; the visitor is templatized.
>>>> +class CFGVisitor {
>>>> +  // Enter the CFG for Decl D, and perform any initial setup operations.
>>>> +  void enterCFG(CFG *Cfg, const NamedDecl *D, const CFGBlock *First) {}
>>>> +
>>>> +  // Enter a CFGBlock.
>>>> +  void enterCFGBlock(const CFGBlock *B) {}
>>>> +
>>>> +  // Returns true if this visitor implements handlePredecessor
>>>> +  bool visitPredecessors() { return true; }
>>>> +
>>>> +  // Process a predecessor edge.
>>>> +  void handlePredecessor(const CFGBlock *Pred) {}
>>>> +
>>>> +  // Process a successor back edge to a previously visited block.
>>>> +  void handlePredecessorBackEdge(const CFGBlock *Pred) {}
>>>> +
>>>> +  // Called just before processing statements.
>>>> +  void enterCFGBlockBody(const CFGBlock *B) {}
>>>> +
>>>> +  // Process an ordinary statement.
>>>> +  void handleStatement(const Stmt *S) {}
>>>> +
>>>> +  // Process a destructor call
>>>> +  void handleDestructorCall(const VarDecl *VD, const CXXDestructorDecl *DD) {}
>>>> +
>>>> +  // Called after all statements have been handled.
>>>> +  void exitCFGBlockBody(const CFGBlock *B) {}
>>>> +
>>>> +  // Return true
>>>> +  bool visitSuccessors() { return true; }
>>>> +
>>>> +  // Process a successor edge.
>>>> +  void handleSuccessor(const CFGBlock *Succ) {}
>>>> +
>>>> +  // Process a successor back edge to a previously visited block.
>>>> +  void handleSuccessorBackEdge(const CFGBlock *Succ) {}
>>>> +
>>>> +  // Leave a CFGBlock.
>>>> +  void exitCFGBlock(const CFGBlock *B) {}
>>>> +
>>>> +  // Leave the CFG, and perform any final cleanup operations.
>>>> +  void exitCFG(const CFGBlock *Last) {}
>>>> +};
>>>> +
>>>>
>>>>  // Walks the clang CFG, and invokes methods on a given CFGVisitor.
>>>>  class CFGWalker {
>>>> @@ -97,6 +118,25 @@ public:
>>>>
>>>>        V.enterCFGBlock(CurrBlock);
>>>>
>>>> +      // Process predecessors
>>>> +      if (V.visitPredecessors()) {
>>>> +        // Process successors
>>>> +        for (CFGBlock::const_pred_iterator SI = CurrBlock->pred_begin(),
>>>> +                                           SE = CurrBlock->pred_end();
>>>> +             SI != SE; ++SI) {
>>>> +          if (*SI == nullptr)
>>>> +            continue;
>>>> +
>>>> +          if (!VisitedBlocks.alreadySet(*SI)) {
>>>> +            V.handlePredecessorBackEdge(*SI);
>>>> +            continue;
>>>> +          }
>>>> +          V.handlePredecessor(*SI);
>>>> +        }
>>>> +      }
>>>> +
>>>> +      V.enterCFGBlockBody(CurrBlock);
>>>> +
>>>>        // Process statements
>>>>        for (const auto &BI : *CurrBlock) {
>>>>          switch (BI.getKind()) {
>>>> @@ -117,18 +157,23 @@ public:
>>>>          }
>>>>        }
>>>>
>>>> +      V.exitCFGBlockBody(CurrBlock);
>>>> +
>>>>        // Process successors
>>>> -      for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
>>>> -                                         SE = CurrBlock->succ_end();
>>>> -           SI != SE; ++SI) {
>>>> -        if (*SI == nullptr)
>>>> -          continue;
>>>> -
>>>> -        if (VisitedBlocks.alreadySet(*SI)) {
>>>> -          V.handleSuccessorBackEdge(*SI);
>>>> -          continue;
>>>> +      if (V.visitSuccessors()) {
>>>> +        // Process successors
>>>> +        for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
>>>> +                                           SE = CurrBlock->succ_end();
>>>> +             SI != SE; ++SI) {
>>>> +          if (*SI == nullptr)
>>>> +            continue;
>>>> +
>>>> +          if (VisitedBlocks.alreadySet(*SI)) {
>>>> +            V.handleSuccessorBackEdge(*SI);
>>>> +            continue;
>>>> +          }
>>>> +          V.handleSuccessor(*SI);
>>>>          }
>>>> -        V.handleSuccessor(*SI);
>>>>        }
>>>>
>>>>        V.exitCFGBlock(CurrBlock);
>>>> @@ -174,15 +219,16 @@ public:
>>>>      {}
>>>>    };
>>>>
>>>> -  til::SExpr *lookupStmt(const Stmt *S);
>>>> -  void insertStmt(const Stmt *S, til::Variable *V);
>>>> -
>>>>    // Translate a clang statement or expression to a TIL expression.
>>>>    // Also performs substitution of variables; Ctx provides the context.
>>>>    // Dispatches on the type of S.
>>>>    til::SExpr *translate(const Stmt *S, CallingContext *Ctx);
>>>> +  til::SCFG  *buildCFG(CFGWalker &Walker);
>>>>
>>>> -protected:
>>>> +  til::SExpr *lookupStmt(const Stmt *S);
>>>> +  til::SCFG  *getCFG() const { return Scfg; }
>>>> +
>>>> +private:
>>>>    til::SExpr *translateDeclRefExpr(const DeclRefExpr *DRE,
>>>>                                     CallingContext *Ctx) ;
>>>>    til::SExpr *translateCXXThisExpr(const CXXThisExpr *TE, CallingContext *Ctx);
>>>> @@ -204,24 +250,86 @@ protected:
>>>>    til::SExpr *translateBinaryConditionalOperator(
>>>>        const BinaryConditionalOperator *C, CallingContext *Ctx);
>>>>
>>>> +  til::SExpr *translateDeclStmt(const DeclStmt *S, CallingContext *Ctx);
>>>> +
>>>> +private:
>>>> +  // Used for looking the index of a name.
>>>> +  typedef llvm::DenseMap<const ValueDecl*, unsigned> NameIndexMap;
>>>> +
>>>> +  // Used for looking up the current SSA variable for a name, by index.
>>>> +  typedef CopyOnWriteVector<std::pair<const ValueDecl*, til::SExpr*> >
>>>> +    NameVarMap;
>>>> +
>>>> +  struct BlockInfo {
>>>> +    NameVarMap ExitMap;
>>>> +    bool HasBackEdges = false;
>>>> +    unsigned SuccessorsToProcess = 0;
>>>> +  };
>>>> +
>>>> +  // We implement the CFGVisitor API
>>>> +  friend class CFGWalker;
>>>> +
>>>> +  void enterCFG(CFG *Cfg, const NamedDecl *D, const CFGBlock *First);
>>>> +  void enterCFGBlock(const CFGBlock *B);
>>>> +  bool visitPredecessors() { return true; }
>>>> +  void handlePredecessor(const CFGBlock *Pred);
>>>> +  void handlePredecessorBackEdge(const CFGBlock *Pred);
>>>> +  void enterCFGBlockBody(const CFGBlock *B);
>>>> +  void handleStatement(const Stmt *S);
>>>> +  void handleDestructorCall(const VarDecl *VD, const CXXDestructorDecl *DD);
>>>> +  void exitCFGBlockBody(const CFGBlock *B);
>>>> +  bool visitSuccessors() { return true; }
>>>> +  void handleSuccessor(const CFGBlock *Succ);
>>>> +  void handleSuccessorBackEdge(const CFGBlock *Succ);
>>>> +  void exitCFGBlock(const CFGBlock *B);
>>>> +  void exitCFG(const CFGBlock *Last);
>>>> +
>>>> +  void insertStmt(const Stmt *S, til::Variable *V);
>>>> +  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);
>>>>
>>>>  public:
>>>> -  SExprBuilder(til::MemRegionRef A, StatementMap *SM = nullptr)
>>>> -      : Arena(A), SMap(SM), SelfVar(nullptr), CurrentBlock(nullptr) {
>>>> +  SExprBuilder(til::MemRegionRef A)
>>>> +      : Arena(A), SelfVar(nullptr), Scfg(nullptr), CallCtx(nullptr),
>>>> +        CurrentBB(nullptr), CurrentBlockID(0), CurrentVarID(0),
>>>> +        CurrentArgIndex(0)
>>>> +  {
>>>>      // FIXME: we don't always have a self-variable.
>>>>      SelfVar = new (Arena) til::Variable(til::Variable::VK_SFun);
>>>>    }
>>>>
>>>> -protected:
>>>> +  ~SExprBuilder() {
>>>> +    if (CallCtx)
>>>> +      delete CallCtx;
>>>> +  }
>>>> +
>>>> +private:
>>>>    til::MemRegionRef Arena;
>>>> -  StatementMap *SMap;             // Map from Stmt to TIL Variables
>>>> -  til::Variable *SelfVar;         // Variable to use for 'this'.  May be null.
>>>> -  til::BasicBlock* CurrentBlock;  // Current basic block.  May be null.
>>>> +  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.
>>>> +  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;
>>>> +  til::BasicBlock *CurrentBB;
>>>> +  BlockInfo *CurrentBlockInfo;
>>>> +  unsigned CurrentBlockID;
>>>> +  unsigned CurrentVarID;
>>>> +  unsigned CurrentArgIndex;
>>>>  };
>>>>
>>>>
>>>>  // Dump an SCFG to llvm::errs().
>>>> -void printSCFG(CFGWalker &walker);
>>>> +void printSCFG(CFGWalker &Walker);
>>>>
>>>>
>>>>  } // end namespace threadSafety
>>>>
>>>> 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=206338&r1=206337&r2=206338&view=diff
>>>> ==============================================================================
>>>> --- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h (original)
>>>> +++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h Tue Apr 15 18:23:19 2014
>>>> @@ -199,7 +199,7 @@ public:
>>>>    // These are defined after SExprRef contructor, below
>>>>    inline Variable(VariableKind K, SExpr *D = nullptr,
>>>>                    const clang::ValueDecl *Cvd = nullptr);
>>>> -  inline Variable(const clang::ValueDecl *Cvd, SExpr *D = nullptr);
>>>> +  inline Variable(SExpr *D = nullptr, const clang::ValueDecl *Cvd = nullptr);
>>>>    inline Variable(const Variable &Vd, SExpr *D);
>>>>
>>>>    VariableKind kind() const { return static_cast<VariableKind>(Flags); }
>>>> @@ -220,6 +220,7 @@ public:
>>>>      BlockID = static_cast<unsigned short>(Bid);
>>>>      Id = static_cast<unsigned short>(I);
>>>>    }
>>>> +  void setClangDecl(const clang::ValueDecl *VD) { Cvdecl = VD; }
>>>>
>>>>    template <class V> typename V::R_SExpr traverse(V &Visitor) {
>>>>      // This routine is only called for variable references.
>>>> @@ -353,7 +354,7 @@ Variable::Variable(VariableKind K, SExpr
>>>>    Flags = K;
>>>>  }
>>>>
>>>> -Variable::Variable(const clang::ValueDecl *Cvd, SExpr *D)
>>>> +Variable::Variable(SExpr *D, const clang::ValueDecl *Cvd)
>>>>      : SExpr(COP_Variable), Definition(D), Cvdecl(Cvd),
>>>>        BlockID(0), Id(0),  NumUses(0) {
>>>>    Flags = VK_Let;
>>>> @@ -935,6 +936,8 @@ private:
>>>>    SExprRef Expr0;
>>>>  };
>>>>
>>>> +
>>>> +
>>>>  class BasicBlock;
>>>>
>>>>  // An SCFG is a control-flow graph.  It consists of a set of basic blocks, each
>>>> @@ -998,13 +1001,16 @@ public:
>>>>
>>>>    BasicBlock(MemRegionRef A, unsigned Nargs, unsigned Nins,
>>>>               SExpr *Term = nullptr)
>>>> -      : BlockID(0), Parent(nullptr), Args(A, Nargs), Instrs(A, Nins),
>>>> -        Terminator(Term) {}
>>>> +      : BlockID(0), Parent(nullptr), NumPredecessors(0),
>>>> +        Args(A, Nargs), Instrs(A, Nins), Terminator(Term) {}
>>>>    BasicBlock(const BasicBlock &B, VarArray &&As, VarArray &&Is, SExpr *T)
>>>> -      : BlockID(0), Parent(nullptr), Args(std::move(As)), Instrs(std::move(Is)),
>>>> -        Terminator(T) {}
>>>> +      : BlockID(0), Parent(nullptr), NumPredecessors(B.NumPredecessors),
>>>> +        Args(std::move(As)), Instrs(std::move(Is)), Terminator(T)
>>>> +  {}
>>>>
>>>>    unsigned blockID() const { return BlockID; }
>>>> +  unsigned numPredecessors() const { return NumPredecessors; }
>>>> +
>>>>    const BasicBlock *parent() const { return Parent; }
>>>>    BasicBlock *parent() { return Parent; }
>>>>
>>>> @@ -1017,8 +1023,9 @@ public:
>>>>    const SExpr *terminator() const { return Terminator.get(); }
>>>>    SExpr *terminator() { return Terminator.get(); }
>>>>
>>>> -  void setParent(BasicBlock *P) { Parent = P; }
>>>>    void setBlockID(unsigned i) { BlockID = i; }
>>>> +  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); }
>>>> @@ -1057,9 +1064,10 @@ private:
>>>>    friend class SCFG;
>>>>
>>>>    unsigned BlockID;
>>>> -  BasicBlock *Parent;   // The parent block is the enclosing lexical scope.
>>>> -                        // The parent dominates this block.
>>>> -  VarArray Args;        // Phi nodes
>>>> +  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;
>>>>  };
>>>> @@ -1100,8 +1108,8 @@ public:
>>>>      return Visitor.reducePhi(*this, Nvs);
>>>>    }
>>>>
>>>> -  template <class C> typename C::CType compare(Phi *E, C &Cmp) {
>>>> -    // TODO -- implement CFG comparisons
>>>> +  template <class C> typename C::CType compare(Phi* E, C &Cmp) {
>>>> +    // TODO: implement CFG comparisons
>>>>      return Cmp.comparePointers(this, E);
>>>>    }
>>>>
>>>> @@ -1146,17 +1154,26 @@ public:
>>>>    static bool classof(const SExpr *E) { return E->opcode() == COP_Branch; }
>>>>
>>>>    Branch(SExpr *C, BasicBlock *T, BasicBlock *E)
>>>> -      : SExpr(COP_Branch), Condition(C), ThenBlock(T), ElseBlock(E) {}
>>>> +      : SExpr(COP_Branch), Condition(C), ThenBlock(T), ElseBlock(E),
>>>> +        ThenIndex(0), ElseIndex(0)
>>>> +  {}
>>>>    Branch(const Branch &Br, SExpr *C, BasicBlock *T, BasicBlock *E)
>>>> -      : SExpr(COP_Branch), Condition(C), ThenBlock(T), ElseBlock(E) {}
>>>> +      : SExpr(COP_Branch), Condition(C), ThenBlock(T), ElseBlock(E),
>>>> +        ThenIndex(0), ElseIndex(0)
>>>> +  {}
>>>>
>>>>    const SExpr *condition() const { return Condition; }
>>>>    SExpr *condition() { return Condition; }
>>>> +
>>>>    const BasicBlock *thenBlock() const { return ThenBlock; }
>>>>    BasicBlock *thenBlock() { return ThenBlock; }
>>>> +
>>>>    const BasicBlock *elseBlock() const { return ElseBlock; }
>>>>    BasicBlock *elseBlock() { return ElseBlock; }
>>>>
>>>> +  unsigned thenIndex() const { return ThenIndex; }
>>>> +  unsigned elseIndex() const { return ElseIndex; }
>>>> +
>>>>    template <class V> typename V::R_SExpr traverse(V &Visitor) {
>>>>      typename V::R_SExpr Nc = Visitor.traverse(Condition);
>>>>      BasicBlock *Ntb = Visitor.reduceBasicBlockRef(ThenBlock);
>>>> @@ -1173,6 +1190,8 @@ private:
>>>>    SExpr *Condition;
>>>>    BasicBlock *ThenBlock;
>>>>    BasicBlock *ElseBlock;
>>>> +  unsigned ThenIndex;
>>>> +  unsigned ElseIndex;
>>>>  };
>>>>
>>>>
>>>>
>>>> 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=206338&r1=206337&r2=206338&view=diff
>>>> ==============================================================================
>>>> --- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h (original)
>>>> +++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h Tue Apr 15 18:23:19 2014
>>>> @@ -409,6 +409,15 @@ protected:
>>>>      SS << "\n";
>>>>    }
>>>>
>>>> +  void printBlockLabel(StreamType & SS, BasicBlock *BB, unsigned index) {
>>>> +    if (!BB) {
>>>> +      SS << "BB_null";
>>>> +      return;
>>>> +    }
>>>> +    SS << "BB_";
>>>> +    SS << BB->blockID();
>>>> +  }
>>>> +
>>>>    // TODO: further distinguish between binary operations.
>>>>    static const unsigned Prec_Atom = 0;
>>>>    static const unsigned Prec_Postfix = 1;
>>>> @@ -560,9 +569,11 @@ protected:
>>>>
>>>>    void printSApply(SApply *E, StreamType &SS) {
>>>>      self()->printSExpr(E->sfun(), SS, Prec_Postfix);
>>>> -    SS << "@(";
>>>> -    self()->printSExpr(E->arg(), SS, Prec_MAX);
>>>> -    SS << ")";
>>>> +    if (E->isDelegation()) {
>>>> +      SS << "@(";
>>>> +      self()->printSExpr(E->arg(), SS, Prec_MAX);
>>>> +      SS << ")";
>>>> +    }
>>>>    }
>>>>
>>>>    void printProject(Project *E, StreamType &SS) {
>>>> @@ -584,7 +595,7 @@ protected:
>>>>    }
>>>>
>>>>    void printAlloc(Alloc *E, StreamType &SS) {
>>>> -    SS << "#alloc ";
>>>> +    SS << "new ";
>>>>      self()->printSExpr(E->dataType(), SS, Prec_Other-1);
>>>>    }
>>>>
>>>> @@ -595,7 +606,7 @@ protected:
>>>>
>>>>    void printStore(Store *E, StreamType &SS) {
>>>>      self()->printSExpr(E->destination(), SS, Prec_Other-1);
>>>> -    SS << " = ";
>>>> +    SS << " := ";
>>>>      self()->printSExpr(E->source(), SS, Prec_Other-1);
>>>>    }
>>>>
>>>> @@ -628,9 +639,11 @@ protected:
>>>>          newline(SS);
>>>>        }
>>>>        for (auto I : BBI->instructions()) {
>>>> -        SS << "let ";
>>>> -        self()->printVariable(I, SS);
>>>> -        SS << " = ";
>>>> +        if (I->definition()->opcode() != COP_Store) {
>>>> +          SS << "let ";
>>>> +          self()->printVariable(I, SS);
>>>> +          SS << " = ";
>>>> +        }
>>>>          self()->printSExpr(I->definition(), SS, Prec_MAX);
>>>>          SS << ";";
>>>>          newline(SS);
>>>> @@ -648,31 +661,29 @@ protected:
>>>>    }
>>>>
>>>>    void printPhi(Phi *E, StreamType &SS) {
>>>> -    SS << "#phi(";
>>>> +    SS << "phi(";
>>>>      unsigned i = 0;
>>>>      for (auto V : E->values()) {
>>>> -      ++i;
>>>>        if (i > 0)
>>>>          SS << ", ";
>>>>        self()->printSExpr(V, SS, Prec_MAX);
>>>> +      ++i;
>>>>      }
>>>>      SS << ")";
>>>>    }
>>>>
>>>>    void printGoto(Goto *E, StreamType &SS) {
>>>> -    SS << "#goto BB_";
>>>> -    SS << E->targetBlock()->blockID();
>>>> -    SS << ":";
>>>> -    SS << E->index();
>>>> +    SS << "goto ";
>>>> +    printBlockLabel(SS, E->targetBlock(), E->index());
>>>>    }
>>>>
>>>>    void printBranch(Branch *E, StreamType &SS) {
>>>> -    SS << "#branch (";
>>>> +    SS << "branch (";
>>>>      self()->printSExpr(E->condition(), SS, Prec_MAX);
>>>> -    SS << ") BB_";
>>>> -    SS << E->thenBlock()->blockID();
>>>> -    SS << " BB_";
>>>> -    SS << E->elseBlock()->blockID();
>>>> +    SS << ") ";
>>>> +    printBlockLabel(SS, E->thenBlock(), E->thenIndex());
>>>> +    SS << " ";
>>>> +    printBlockLabel(SS, E->elseBlock(), E->elseIndex());
>>>>    }
>>>>  };
>>>>
>>>>
>>>> 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=206338&r1=206337&r2=206338&view=diff
>>>> ==============================================================================
>>>> --- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyUtil.h (original)
>>>> +++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyUtil.h Tue Apr 15 18:23:19 2014
>>>> @@ -78,7 +78,7 @@ template <class T> class SimpleArray {
>>>>  public:
>>>>    SimpleArray() : Data(nullptr), Size(0), Capacity(0) {}
>>>>    SimpleArray(T *Dat, size_t Cp, size_t Sz = 0)
>>>> -      : Data(Dat), Size(0), Capacity(Cp) {}
>>>> +      : Data(Dat), Size(Sz), Capacity(Cp) {}
>>>>    SimpleArray(MemRegionRef A, size_t Cp)
>>>>        : Data(A.allocateT<T>(Cp)), Size(0), Capacity(Cp) {}
>>>>    SimpleArray(SimpleArray<T> &&A)
>>>> @@ -101,8 +101,14 @@ public:
>>>>    size_t size() const { return Size; }
>>>>    size_t capacity() const { return Capacity; }
>>>>
>>>> -  T &operator[](unsigned I) { return Data[I]; }
>>>> -  const T &operator[](unsigned I) const { return Data[I]; }
>>>> +  T &operator[](unsigned i) {
>>>> +    assert(i < Sz && "Array index out of bounds.");
>>>> +    return Data[i];
>>>> +  }
>>>> +  const T &operator[](unsigned i) const {
>>>> +    assert(i < Size && "Array index out of bounds.");
>>>> +    return Data[i];
>>>> +  }
>>>>
>>>>    iterator begin() { return Data; }
>>>>    iterator end() { return Data + Size; }
>>>> @@ -115,6 +121,14 @@ public:
>>>>      Data[Size++] = Elem;
>>>>    }
>>>>
>>>> +  void setValues(unsigned Sz, const T& C) {
>>>> +    assert(Sz < Capacity);
>>>> +    Size = Sz;
>>>> +    for (unsigned i = 0; i < Sz; ++i) {
>>>> +      Data[i] = C;
>>>> +    }
>>>> +  }
>>>> +
>>>>    template <class Iter> unsigned append(Iter I, Iter E) {
>>>>      size_t Osz = Size;
>>>>      size_t J = Osz;
>>>> @@ -132,8 +146,135 @@ private:
>>>>    size_t Capacity;
>>>>  };
>>>>
>>>> -
>>>>  } // end namespace til
>>>> +
>>>> +
>>>> +// A copy on write vector.
>>>> +// The vector can be in one of three states:
>>>> +// * invalid -- no operations are permitted.
>>>> +// * read-only -- read operations are permitted.
>>>> +// * writable -- read and write operations are permitted.
>>>> +// The init(), destroy(), and makeWritable() methods will change state.
>>>> +template<typename T>
>>>> +class CopyOnWriteVector {
>>>> +private:
>>>> +  class VectorData {
>>>> +  public:
>>>> +    VectorData() : NumRefs(1) { }
>>>> +    VectorData(const VectorData &VD) : NumRefs(1), Vect(VD.Vect) { }
>>>> +
>>>> +    unsigned NumRefs;
>>>> +    std::vector<T> Vect;
>>>> +  };
>>>> +
>>>> +public:
>>>> +  CopyOnWriteVector() : Data(0) { }
>>>> +  CopyOnWriteVector(const CopyOnWriteVector &V) = delete;
>>>> +  CopyOnWriteVector(CopyOnWriteVector &&V) : Data(V.Data) {
>>>> +    V.Data = 0;
>>>> +  }
>>>> +  ~CopyOnWriteVector() {
>>>> +    destroy();
>>>> +  }
>>>> +
>>>> +  // Returns true if this holds a valid vector.
>>>> +  bool valid()  { return Data; }
>>>> +
>>>> +  // Returns true if this vector is writable.
>>>> +  bool writable() { return Data && Data->NumRefs == 1; }
>>>> +
>>>> +  // If this vector is not valid, initialize it to a valid vector.
>>>> +  void init() {
>>>> +    if (!Data) {
>>>> +      Data = new VectorData();
>>>> +    }
>>>> +  }
>>>> +
>>>> +  // Destroy this vector; thus making it invalid.
>>>> +  void destroy() {
>>>> +    if (!Data)
>>>> +      return;
>>>> +    if (Data->NumRefs <= 1)
>>>> +      delete Data;
>>>> +    else
>>>> +      --Data->NumRefs;
>>>> +    Data = 0;
>>>> +  }
>>>> +
>>>> +  // Make this vector writable, creating a copy if needed.
>>>> +  void makeWritable() {
>>>> +    if (!Data) {
>>>> +      Data = new VectorData();
>>>> +      return;
>>>> +    }
>>>> +    if (Data->NumRefs == 1)
>>>> +      return;   // already writeable.
>>>> +    --Data->NumRefs;
>>>> +    Data = new VectorData(*Data);
>>>> +  }
>>>> +
>>>> +  // Create a lazy copy of this vector.
>>>> +  CopyOnWriteVector clone() { return CopyOnWriteVector(Data); }
>>>> +
>>>> +  // No copy constructor or copy assignment.  Use clone() with move assignment.
>>>> +  void operator=(const CopyOnWriteVector &V) = delete;
>>>> +
>>>> +  void operator=(CopyOnWriteVector &&V) {
>>>> +    destroy();
>>>> +    Data = V.Data;
>>>> +    V.Data = 0;
>>>> +  }
>>>> +
>>>> +  typedef typename std::vector<T>::const_iterator iterator;
>>>> +
>>>> +  const std::vector<T> &elements() const { return Data->Vect; }
>>>> +
>>>> +  iterator begin() const { return elements().cbegin(); }
>>>> +  iterator end()   const { return elements().cend();   }
>>>> +
>>>> +  const T& operator[](unsigned i) const { return elements()[i]; }
>>>> +
>>>> +  unsigned size() const { return Data ? elements().size() : 0; }
>>>> +
>>>> +  // Return true if V and this vector refer to the same data.
>>>> +  bool sameAs(const CopyOnWriteVector& V) { return Data == V.Data; }
>>>> +
>>>> +  // Clear vector.  The vector must be writable.
>>>> +  void clear() {
>>>> +    assert(writable() && "Vector is not writable!");
>>>> +    Data->Vect.clear();
>>>> +  }
>>>> +
>>>> +  // Push a new element onto the end.  The vector must be writable.
>>>> +  void push_back(const T& Elem) {
>>>> +    assert(writable() && "Vector is not writable!");
>>>> +    Data->Vect.push_back(Elem);
>>>> +  }
>>>> +
>>>> +  // Gets a mutable reference to the element at index(i).
>>>> +  // The vector must be writable.
>>>> +  T& elem(unsigned i) {
>>>> +    assert(writable() && "Vector is not writable!");
>>>> +    return Data->Vect[i];
>>>> +  }
>>>> +
>>>> +  // Drops elements from the back until the vector has size i.
>>>> +  void downsize(unsigned i) {
>>>> +    assert(writable() && "Vector is not writable!");
>>>> +    Data->Vect.erase(Data->Vect.begin() + i, Data->Vect.end());
>>>> +  }
>>>> +
>>>> +private:
>>>> +  CopyOnWriteVector(VectorData *D) : Data(D) {
>>>> +    if (!Data)
>>>> +      return;
>>>> +    ++Data->NumRefs;
>>>> +  }
>>>> +
>>>> +  VectorData *Data;
>>>> +};
>>>> +
>>>> +
>>>>  } // end namespace threadSafety
>>>>  } // end namespace clang
>>>>
>>>>
>>>> Modified: cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp
>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp?rev=206338&r1=206337&r2=206338&view=diff
>>>> ==============================================================================
>>>> --- cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp (original)
>>>> +++ cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp Tue Apr 15 18:23:19 2014
>>>> @@ -28,6 +28,8 @@
>>>>  #include "llvm/ADT/SmallVector.h"
>>>>  #include "llvm/ADT/StringRef.h"
>>>>
>>>> +#include <algorithm>
>>>> +#include <climits>
>>>>  #include <vector>
>>>>
>>>>
>>>> @@ -38,16 +40,20 @@ typedef SExprBuilder::CallingContext Cal
>>>>
>>>>
>>>>  til::SExpr *SExprBuilder::lookupStmt(const Stmt *S) {
>>>> -  if (!SMap)
>>>> -    return nullptr;
>>>> -  auto It = SMap->find(S);
>>>> -  if (It != SMap->end())
>>>> +  auto It = SMap.find(S);
>>>> +  if (It != SMap.end())
>>>>      return It->second;
>>>>    return nullptr;
>>>>  }
>>>>
>>>>  void SExprBuilder::insertStmt(const Stmt *S, til::Variable *V) {
>>>> -  SMap->insert(std::make_pair(S, V));
>>>> +  SMap.insert(std::make_pair(S, V));
>>>> +}
>>>> +
>>>> +
>>>> +til::SCFG *SExprBuilder::buildCFG(CFGWalker &Walker) {
>>>> +  Walker.walk(*this);
>>>> +  return Scfg;
>>>>  }
>>>>
>>>>
>>>> @@ -55,6 +61,9 @@ void SExprBuilder::insertStmt(const Stmt
>>>>  // Also performs substitution of variables; Ctx provides the context.
>>>>  // Dispatches on the type of S.
>>>>  til::SExpr *SExprBuilder::translate(const Stmt *S, CallingContext *Ctx) {
>>>> +  if (!S)
>>>> +    return nullptr;
>>>> +
>>>>    // Check if S has already been translated and cached.
>>>>    // This handles the lookup of SSA names for DeclRefExprs here.
>>>>    if (til::SExpr *E = lookupStmt(S))
>>>> @@ -105,6 +114,9 @@ til::SExpr *SExprBuilder::translate(cons
>>>>    case Stmt::StringLiteralClass:
>>>>    case Stmt::ObjCStringLiteralClass:
>>>>      return new (Arena) til::Literal(cast<Expr>(S));
>>>> +
>>>> +  case Stmt::DeclStmtClass:
>>>> +    return translateDeclStmt(cast<DeclStmt>(S), Ctx);
>>>>    default:
>>>>      break;
>>>>    }
>>>> @@ -209,6 +221,7 @@ til::SExpr *SExprBuilder::translateUnary
>>>>    return new (Arena) til::Undefined(UO);
>>>>  }
>>>>
>>>> +
>>>>  til::SExpr *SExprBuilder::translateBinaryOperator(const BinaryOperator *BO,
>>>>                                                    CallingContext *Ctx) {
>>>>    switch (BO->getOpcode()) {
>>>> @@ -238,10 +251,17 @@ til::SExpr *SExprBuilder::translateBinar
>>>>          til::BinaryOp(BO->getOpcode(), translate(BO->getLHS(), Ctx),
>>>>                        translate(BO->getRHS(), Ctx));
>>>>
>>>> -  case BO_Assign:
>>>> -    return new (Arena)
>>>> -        til::Store(translate(BO->getLHS(), Ctx), translate(BO->getRHS(), Ctx));
>>>> -
>>>> +  case BO_Assign: {
>>>> +    const Expr *LHS = BO->getLHS();
>>>> +    if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(LHS)) {
>>>> +      const Expr *RHS = BO->getRHS();
>>>> +      til::SExpr *E1 = translate(RHS, Ctx);
>>>> +      return updateVarDecl(DRE->getDecl(), E1);
>>>> +    }
>>>> +    til::SExpr *E0 = translate(LHS, Ctx);
>>>> +    til::SExpr *E1 = translate(BO->getRHS(), Ctx);
>>>> +    return new (Arena) til::Store(E0, E1);
>>>> +  }
>>>>    case BO_MulAssign:
>>>>    case BO_DivAssign:
>>>>    case BO_RemAssign:
>>>> @@ -265,145 +285,332 @@ til::SExpr *SExprBuilder::translateBinar
>>>>
>>>>  til::SExpr *SExprBuilder::translateCastExpr(const CastExpr *CE,
>>>>                                              CallingContext *Ctx) {
>>>> -  til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);
>>>> -
>>>>    clang::CastKind K = CE->getCastKind();
>>>>    switch (K) {
>>>> -  case CK_LValueToRValue:
>>>> +  case CK_LValueToRValue: {
>>>> +    if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CE->getSubExpr())) {
>>>> +      til::SExpr *E0 = lookupVarDecl(DRE->getDecl());
>>>> +      if (E0)
>>>> +        return E0;
>>>> +    }
>>>> +    til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);
>>>>      return new (Arena) til::Load(E0);
>>>> -
>>>> +  }
>>>>    case CK_NoOp:
>>>>    case CK_DerivedToBase:
>>>>    case CK_UncheckedDerivedToBase:
>>>>    case CK_ArrayToPointerDecay:
>>>> -  case CK_FunctionToPointerDecay:
>>>> +  case CK_FunctionToPointerDecay: {
>>>> +    til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);
>>>>      return E0;
>>>> -
>>>> -  default:
>>>> +  }
>>>> +  default: {
>>>> +    til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);
>>>>      return new (Arena) til::Cast(K, E0);
>>>>    }
>>>> +  }
>>>>  }
>>>>
>>>> +
>>>>  til::SExpr *
>>>>  SExprBuilder::translateArraySubscriptExpr(const ArraySubscriptExpr *E,
>>>>                                            CallingContext *Ctx) {
>>>>    return new (Arena) til::Undefined(E);
>>>>  }
>>>>
>>>> +
>>>>  til::SExpr *
>>>>  SExprBuilder::translateConditionalOperator(const ConditionalOperator *C,
>>>>                                             CallingContext *Ctx) {
>>>>    return new (Arena) til::Undefined(C);
>>>>  }
>>>>
>>>> +
>>>>  til::SExpr *SExprBuilder::translateBinaryConditionalOperator(
>>>>      const BinaryConditionalOperator *C, CallingContext *Ctx) {
>>>>    return new (Arena) til::Undefined(C);
>>>>  }
>>>>
>>>>
>>>> +til::SExpr *
>>>> +SExprBuilder::translateDeclStmt(const DeclStmt *S, CallingContext *Ctx) {
>>>> +  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();
>>>> +      til::SExpr* SE = translate(E, Ctx);
>>>> +
>>>> +      // Add local variables with trivial type to the variable map
>>>> +      QualType T = VD->getType();
>>>> +      if (T.isTrivialType(VD->getASTContext())) {
>>>> +        return addVarDecl(VD, SE);
>>>> +      }
>>>> +      else {
>>>> +        // TODO: add alloca
>>>> +      }
>>>> +    }
>>>> +  }
>>>> +  return nullptr;
>>>> +}
>>>>
>>>> -// Build a complete SCFG from a clang CFG.
>>>> -class SCFGBuilder {
>>>> -  class BBInfo {
>>>>
>>>> -  };
>>>> +// 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.
>>>> +// If E is trivial returns E.
>>>> +til::SExpr *SExprBuilder::addStatement(til::SExpr* E, const Stmt *S,
>>>> +                                       const ValueDecl *VD) {
>>>> +  if (!E)
>>>> +    return nullptr;
>>>> +  if (til::ThreadSafetyTIL::isTrivial(E))
>>>> +    return E;
>>>>
>>>> -  void addStatement(til::SExpr* E, const Stmt *S) {
>>>> -    if (!E)
>>>> -      return;
>>>> -    if (til::ThreadSafetyTIL::isTrivial(E))
>>>> -      return;
>>>> +  til::Variable *V = new (Arena) til::Variable(E, VD);
>>>> +  V->setID(CurrentBlockID, CurrentVarID++);
>>>> +  CurrentBB->addInstr(V);
>>>> +  if (S)
>>>> +    insertStmt(S, V);
>>>> +  return V;
>>>> +}
>>>>
>>>> -    til::Variable *V = new (Arena) til::Variable(til::Variable::VK_Let, E);
>>>> -    V->setID(CurrentBlockID, CurrentVarID++);
>>>> -    CurrentBB->addInstr(V);
>>>> -    if (S)
>>>> -      BuildEx.insertStmt(S, V);
>>>> -  }
>>>>
>>>> -public:
>>>> -  // Enter the CFG for Decl D, and perform any initial setup operations.
>>>> -  void enterCFG(CFG *Cfg, const NamedDecl *D, const CFGBlock *First) {
>>>> -    Scfg = new (Arena) til::SCFG(Arena, Cfg->getNumBlockIDs());
>>>> -    CallCtx = new SExprBuilder::CallingContext(D);
>>>> -  }
>>>> +// 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;
>>>> +  return nullptr;
>>>> +}
>>>>
>>>> -  // Enter a CFGBlock.
>>>> -  void enterCFGBlock(const CFGBlock *B) {
>>>> -    CurrentBB = new (Arena) til::BasicBlock(Arena, 0, B->size());
>>>> -    CurrentBB->setBlockID(CurrentBlockID);
>>>> -    CurrentVarID = 0;
>>>> -    Scfg->add(CurrentBB);
>>>> -  }
>>>>
>>>> -  // Process an ordinary statement.
>>>> -  void handleStatement(const Stmt *S) {
>>>> -    til::SExpr *E = BuildEx.translate(S, CallCtx);
>>>> -    addStatement(E, S);
>>>> +// if E is a til::Variable, update its clangDecl.
>>>> +inline void maybeUpdateVD(til::SExpr *E, const ValueDecl *VD) {
>>>> +  if (!E)
>>>> +    return;
>>>> +  if (til::Variable *V = dyn_cast<til::Variable>(E)) {
>>>> +    if (!V->clangDecl())
>>>> +      V->setClangDecl(VD);
>>>>    }
>>>> +}
>>>> +
>>>> +// 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));
>>>> +  return E;
>>>> +}
>>>> +
>>>> +
>>>> +// 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()) {
>>>> +    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;
>>>> +  return E;
>>>> +}
>>>> +
>>>>
>>>> -  // Process a destructor call
>>>> -  void handleDestructorCall(const VarDecl *VD, const CXXDestructorDecl *DD) {
>>>> -    til::SExpr *Sf = new (Arena) til::LiteralPtr(VD);
>>>> -    til::SExpr *Dr = new (Arena) til::LiteralPtr(DD);
>>>> -    til::SExpr *Ap = new (Arena) til::Apply(Dr, Sf);
>>>> -    til::SExpr *E = new (Arena) til::Call(Ap);
>>>> -    addStatement(E, nullptr);
>>>> +// Merge values from Map into the current entry map.
>>>> +void SExprBuilder::mergeEntryMap(NameVarMap Map) {
>>>> +  assert(CurrentBlockInfo && "Not processing a block!");
>>>> +
>>>> +  if (!CurrentNameMap.valid()) {
>>>> +    // Steal Map, using copy-on-write.
>>>> +    CurrentNameMap = std::move(Map);
>>>> +    return;
>>>> +  }
>>>> +  if (CurrentNameMap.sameAs(Map))
>>>> +    return;  // Easy merge: maps from different predecessors are unchanged.
>>>> +
>>>> +  unsigned ESz = CurrentNameMap.size();
>>>> +  unsigned MSz = Map.size();
>>>> +  unsigned Sz = std::max(ESz, MSz);
>>>> +  bool W = CurrentNameMap.writable();
>>>> +  for (unsigned i=0; i<Sz; ++i) {
>>>> +    if (CurrentNameMap[i].first != Map[i].first) {
>>>> +      if (!W)
>>>> +        CurrentNameMap.makeWritable();
>>>> +      CurrentNameMap.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 (ESz > MSz) {
>>>> +    if (!W)
>>>> +      CurrentNameMap.makeWritable();
>>>> +    CurrentNameMap.downsize(Map.size());
>>>>    }
>>>> +}
>>>> +
>>>>
>>>> -  // Process a successor edge.
>>>> -  void handleSuccessor(const CFGBlock *Succ) {}
>>>>
>>>> -  // Process a successor back edge to a previously visited block.
>>>> -  void handleSuccessorBackEdge(const CFGBlock *Succ) {}
>>>> +void SExprBuilder::enterCFG(CFG *Cfg, const NamedDecl *D,
>>>> +                            const CFGBlock *First) {
>>>> +  // Perform initial setup operations.
>>>> +  unsigned NBlocks = Cfg->getNumBlockIDs();
>>>> +  Scfg = new (Arena) til::SCFG(Arena, NBlocks);
>>>>
>>>> -  // Leave a CFGBlock.
>>>> -  void exitCFGBlock(const CFGBlock *B) {
>>>> -    CurrentBlockID++;
>>>> -    CurrentBB = 0;
>>>> +  // allocate all basic blocks immediately, to handle forward references.
>>>> +  BlockMap.reserve(NBlocks);
>>>> +  BBInfo.resize(NBlocks);
>>>> +  for (auto *B : *Cfg) {
>>>> +    auto *BB = new (Arena) til::BasicBlock(Arena, 0, B->size());
>>>> +    BlockMap.push_back(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;
>>>> +
>>>> +  assert(!CurrentNameMap.valid() && "CurrentNameMap already initialized.");
>>>> +}
>>>> +
>>>> +
>>>> +void SExprBuilder::handlePredecessor(const CFGBlock *Pred) {
>>>> +  // Compute CurrentNameMap on entry from ExitMaps of predecessors
>>>> +
>>>> +  BlockInfo *PredInfo = &BBInfo[Pred->getBlockID()];
>>>> +  assert(PredInfo->SuccessorsToProcess > 0);
>>>> +
>>>> +  if (--PredInfo->SuccessorsToProcess == 0)
>>>> +    mergeEntryMap(std::move(PredInfo->ExitMap));
>>>> +  else
>>>> +    mergeEntryMap(PredInfo->ExitMap.clone());
>>>> +
>>>> +  ++CurrentArgIndex;
>>>> +}
>>>> +
>>>> +
>>>> +void SExprBuilder::handlePredecessorBackEdge(const CFGBlock *Pred) {
>>>> +  CurrentBlockInfo->HasBackEdges = true;
>>>> +}
>>>> +
>>>>
>>>> -  // Leave the CFG, and perform any final cleanup operations.
>>>> -  void exitCFG(const CFGBlock *Last) {
>>>> -    delete CallCtx;
>>>> -    CallCtx = nullptr;
>>>> +void SExprBuilder::enterCFGBlockBody(const CFGBlock *B) { }
>>>> +
>>>> +
>>>> +void SExprBuilder::handleStatement(const Stmt *S) {
>>>> +  til::SExpr *E = translate(S, CallCtx);
>>>> +  addStatement(E, S);
>>>> +}
>>>> +
>>>> +
>>>> +void SExprBuilder::handleDestructorCall(const VarDecl *VD,
>>>> +                                        const CXXDestructorDecl *DD) {
>>>> +  til::SExpr *Sf = new (Arena) til::LiteralPtr(VD);
>>>> +  til::SExpr *Dr = new (Arena) til::LiteralPtr(DD);
>>>> +  til::SExpr *Ap = new (Arena) til::Apply(Dr, Sf);
>>>> +  til::SExpr *E = new (Arena) til::Call(Ap);
>>>> +  addStatement(E, nullptr);
>>>> +}
>>>> +
>>>> +
>>>> +
>>>> +void SExprBuilder::exitCFGBlockBody(const CFGBlock *B) {
>>>> +  unsigned N = B->succ_size();
>>>> +  auto It = B->succ_begin();
>>>> +  if (N == 1) {
>>>> +    til::BasicBlock *BB = *It ? BlockMap[(*It)->getBlockID()] : 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;
>>>> +    ++It;
>>>> +    til::BasicBlock *BB2 = *It ? BlockMap[(*It)->getBlockID()] : nullptr;
>>>> +    // TODO: set conditional, set index
>>>> +    til::SExpr *Tm = new (Arena) til::Branch(C, BB1, BB2);
>>>> +    CurrentBB->setTerminator(Tm);
>>>> +  }
>>>> +}
>>>>
>>>> -  SCFGBuilder(til::MemRegionRef A)
>>>> -      : Arena(A), Scfg(nullptr), CurrentBB(nullptr), CurrentBlockID(0),
>>>> -        CurrentVarID(0), CallCtx(nullptr),
>>>> -        SMap(new SExprBuilder::StatementMap()), BuildEx(A, SMap) {}
>>>> -  ~SCFGBuilder() { delete SMap; }
>>>>
>>>> -  til::SCFG *getCFG() const { return Scfg; }
>>>> +void SExprBuilder::handleSuccessor(const CFGBlock *Succ) {
>>>> +  ++CurrentBlockInfo->SuccessorsToProcess;
>>>> +}
>>>>
>>>> -private:
>>>> -  til::MemRegionRef Arena;
>>>> -  til::SCFG *Scfg;
>>>> -  til::BasicBlock *CurrentBB;
>>>> -  unsigned CurrentBlockID;
>>>> -  unsigned CurrentVarID;
>>>>
>>>> -  SExprBuilder::CallingContext *CallCtx;
>>>> -  SExprBuilder::StatementMap *SMap;
>>>> -  SExprBuilder BuildEx;
>>>> -};
>>>> +void SExprBuilder::handleSuccessorBackEdge(const CFGBlock *Succ) {
>>>> +
>>>> +}
>>>> +
>>>> +
>>>> +void SExprBuilder::exitCFGBlock(const CFGBlock *B) {
>>>> +  CurrentBlockInfo->ExitMap = std::move(CurrentNameMap);
>>>> +  CurrentBlockID++;
>>>> +  CurrentBB = nullptr;
>>>> +  CurrentBlockInfo = nullptr;
>>>> +}
>>>> +
>>>> +
>>>> +void SExprBuilder::exitCFG(const CFGBlock *Last) {
>>>> +  CurrentBlockID = 0;
>>>> +  CurrentVarID = 0;
>>>> +  CurrentArgIndex = 0;
>>>> +}
>>>>
>>>>
>>>>
>>>> -class LLVMPrinter :
>>>> -    public til::PrettyPrinter<LLVMPrinter, llvm::raw_ostream> {
>>>> +class LLVMPrinter : public til::PrettyPrinter<LLVMPrinter, llvm::raw_ostream> {
>>>>  };
>>>>
>>>>
>>>> -void printSCFG(CFGWalker &walker) {
>>>> +void printSCFG(CFGWalker &Walker) {
>>>>    llvm::BumpPtrAllocator Bpa;
>>>>    til::MemRegionRef Arena(&Bpa);
>>>> -  SCFGBuilder builder(Arena);
>>>> -  // CFGVisitor visitor;
>>>> -  walker.walk(builder);
>>>> -  LLVMPrinter::print(builder.getCFG(), llvm::errs());
>>>> +  SExprBuilder builder(Arena);
>>>> +  til::SCFG *Cfg = builder.buildCFG(Walker);
>>>> +  LLVMPrinter::print(Cfg, llvm::errs());
>>>>  }
>>>>
>>>>
>>>>
>>>>
>>>> _______________________________________________
>>>> cfe-commits mailing list
>>>> cfe-commits at cs.uiuc.edu
>>>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>>>
>>> _______________________________________________
>>> cfe-commits mailing list
>>> cfe-commits at cs.uiuc.edu
>>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits




More information about the cfe-commits mailing list