r206338 - Thread Safety Analysis: rewrite SSA pass to use the new SExpr and CFG
Timur Iskhodzhanov
timurrrr at google.com
Wed Apr 16 04:22:40 PDT 2014
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
More information about the cfe-commits
mailing list