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

Delesley Hutchins delesley at google.com
Wed Apr 16 07:55:08 PDT 2014


My apologies for the errors.  I should have caught the assert: I don't
know why my debug build didn't flag it.  I don't have a way to test
with MSVC, but I'll try to learn from you guys what not to do.  :-)

  -DeLesley


On Wed, Apr 16, 2014 at 4:22 AM, Timur Iskhodzhanov <timurrrr at google.com> wrote:
> Cool, thanks!
>
> 2014-04-16 15:17 GMT+04:00 Aaron Ballman <aaron at aaronballman.com>:
>> I resolved in r206374 -- BlockInfo needed a move constructor because
>> MSVC won't synthesize one automatically.
>>
>> ~Aaron
>>
>> On Wed, Apr 16, 2014 at 4:48 AM, Timur Iskhodzhanov <timurrrr at google.com> wrote:
>>> ... 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
>>>
>>> _______________________________________________
>>> cfe-commits mailing list
>>> cfe-commits at cs.uiuc.edu
>>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits



-- 
DeLesley Hutchins | Software Engineer | delesley at google.com | 505-206-0315




More information about the cfe-commits mailing list