r206338 - Thread Safety Analysis: rewrite SSA pass to use the new SExpr and CFG
DeLesley Hutchins
delesley at google.com
Tue Apr 15 16:23:19 PDT 2014
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());
}
More information about the cfe-commits
mailing list