From: DeLesley Hutchins Date: Wed, 9 Apr 2014 22:39:43 +0000 (+0000) Subject: Thread Safety Analysis: reorganized SExpr header files. No change in X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b622f9d0763274d70cb0af1b68b4d2dbe6f77cf7;p=clang Thread Safety Analysis: reorganized SExpr header files. No change in functionality. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@205936 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Analysis/Analyses/ThreadSafetyCommon.h b/include/clang/Analysis/Analyses/ThreadSafetyCommon.h index 641992a835..5e0f40ea84 100644 --- a/include/clang/Analysis/Analyses/ThreadSafetyCommon.h +++ b/include/clang/Analysis/Analyses/ThreadSafetyCommon.h @@ -26,6 +26,7 @@ #include "clang/Analysis/Analyses/ThreadSafetyTIL.h" #include "clang/Analysis/AnalysisContext.h" #include "clang/Basic/OperatorKinds.h" + #include @@ -206,15 +207,16 @@ protected: public: SExprBuilder(til::MemRegionRef A, StatementMap *SM = nullptr) - : Arena(A), SMap(SM), SelfVar(nullptr) { + : Arena(A), SMap(SM), SelfVar(nullptr), CurrentBlock(nullptr) { // FIXME: we don't always have a self-variable. SelfVar = new (Arena) til::Variable(til::Variable::VK_SFun); } protected: til::MemRegionRef Arena; - StatementMap *SMap; // Map from Stmt to TIL Variables - til::Variable *SelfVar; // Variable to use for 'this' + 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. }; diff --git a/include/clang/Analysis/Analyses/ThreadSafetyTIL.h b/include/clang/Analysis/Analyses/ThreadSafetyTIL.h index 506adb104e..2cb85e3ec6 100644 --- a/include/clang/Analysis/Analyses/ThreadSafetyTIL.h +++ b/include/clang/Analysis/Analyses/ThreadSafetyTIL.h @@ -43,125 +43,21 @@ #ifndef LLVM_CLANG_THREAD_SAFETY_TIL_H #define LLVM_CLANG_THREAD_SAFETY_TIL_H +#include "clang/Analysis/Analyses/ThreadSafetyUtil.h" #include "clang/AST/ExprCXX.h" -#include "llvm/Support/AlignOf.h" -#include "llvm/Support/Allocator.h" +#include "llvm/ADT/StringRef.h" #include #include #include -namespace clang { -namespace threadSafety { -namespace til { - - -// Simple wrapper class to abstract away from the details of memory management. -// SExprs are allocated in pools, and deallocated all at once. -class MemRegionRef { -private: - union AlignmentType { - double d; - void *p; - long double dd; - long long ii; - }; - -public: - MemRegionRef() : Allocator(nullptr) {} - MemRegionRef(llvm::BumpPtrAllocator *A) : Allocator(A) {} - - void *allocate(size_t Sz) { - return Allocator->Allocate(Sz, llvm::AlignOf::Alignment); - } - - template T *allocateT() { return Allocator->Allocate(); } - - template T *allocateT(size_t NumElems) { - return Allocator->Allocate(NumElems); - } - -private: - llvm::BumpPtrAllocator *Allocator; -}; - - -} // end namespace til -} // end namespace threadSafety -} // end namespace clang - - -inline void *operator new(size_t Sz, - clang::threadSafety::til::MemRegionRef &R) { - return R.allocate(Sz); -} - namespace clang { namespace threadSafety { namespace til { using llvm::StringRef; - -// A simple fixed size array class that does not manage its own memory, -// suitable for use with bump pointer allocation. -template 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) {} - SimpleArray(MemRegionRef A, size_t Cp) - : Data(A.allocateT(Cp)), Size(0), Capacity(Cp) {} - SimpleArray(SimpleArray &&A) - : Data(A.Data), Size(A.Size), Capacity(A.Capacity) { - A.Data = nullptr; - A.Size = 0; - A.Capacity = 0; - } - - T *resize(size_t Ncp, MemRegionRef A) { - T *Odata = Data; - Data = A.allocateT(Ncp); - memcpy(Data, Odata, sizeof(T) * Size); - return Odata; - } - - typedef T *iterator; - typedef const T *const_iterator; - - 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]; } - - iterator begin() { return Data; } - iterator end() { return Data + Size; } - - const_iterator cbegin() const { return Data; } - const_iterator cend() const { return Data + Size; } - - void push_back(const T &Elem) { - assert(Size < Capacity); - Data[Size++] = Elem; - } - - template unsigned append(Iter I, Iter E) { - size_t Osz = Size; - size_t J = Osz; - for (; J < Capacity && I != E; ++J, ++I) - Data[J] = *I; - Size = J; - return J - Osz; - } - -private: - SimpleArray(const SimpleArray &A) { } - - T *Data; - size_t Size; - size_t Capacity; -}; +using clang::SourceLocation; enum TIL_Opcode { @@ -1302,665 +1198,8 @@ private: }; - -// Defines an interface used to traverse SExprs. Traversals have been made as -// generic as possible, and are intended to handle any kind of pass over the -// AST, e.g. visiters, copying, non-destructive rewriting, destructive -// (in-place) rewriting, hashing, typing, etc. -// -// Traversals implement the functional notion of a "fold" operation on SExprs. -// Each SExpr class provides a traverse method, which does the following: -// * e->traverse(v): -// // compute a result r_i for each subexpression e_i -// for (i = 1..n) r_i = v.traverse(e_i); -// // combine results into a result for e, where X is the class of e -// return v.reduceX(*e, r_1, .. r_n). -// -// A visitor can control the traversal by overriding the following methods: -// * v.traverse(e): -// return v.traverseByCase(e), which returns v.traverseX(e) -// * v.traverseX(e): (X is the class of e) -// return e->traverse(v). -// * v.reduceX(*e, r_1, .. r_n): -// compute a result for a node of type X -// -// The reduceX methods control the kind of traversal (visitor, copy, etc.). -// These are separated into a separate class R for the purpose of code reuse. -// The full reducer interface also has methods to handle scopes -template class Traversal : public R { -public: - Self *self() { return reinterpret_cast(this); } - - // Traverse an expression -- returning a result of type R_SExpr. - // Override this method to do something for every expression, regardless - // of which kind it is. TraversalKind indicates the context in which - // the expression occurs, and can be: - // TRV_Normal - // TRV_Lazy -- e may need to be traversed lazily, using a Future. - // TRV_Tail -- e occurs in a tail position - typename R::R_SExpr traverse(SExprRef &E, TraversalKind K = TRV_Normal) { - return traverse(E.get(), K); - } - - typename R::R_SExpr traverse(SExpr *E, TraversalKind K = TRV_Normal) { - return traverseByCase(E); - } - - // Helper method to call traverseX(e) on the appropriate type. - typename R::R_SExpr traverseByCase(SExpr *E) { - switch (E->opcode()) { -#define TIL_OPCODE_DEF(X) \ - case COP_##X: \ - return self()->traverse##X(cast(E)); -#include "clang/Analysis/Analyses/ThreadSafetyOps.def" -#undef TIL_OPCODE_DEF - case COP_MAX: - return self()->reduceNull(); - } - } - -// Traverse e, by static dispatch on the type "X" of e. -// Override these methods to do something for a particular kind of term. -#define TIL_OPCODE_DEF(X) \ - typename R::R_SExpr traverse##X(X *e) { return e->traverse(*self()); } -#include "clang/Analysis/Analyses/ThreadSafetyOps.def" -#undef TIL_OPCODE_DEF -}; - - -// Implements a Reducer that makes a deep copy of an SExpr. -// The default behavior of reduce##X(...) is to create a copy of the original. -// Subclasses can override reduce##X to implement non-destructive rewriting -// passes. -class CopyReducer { -public: - CopyReducer() {} - - void setArena(MemRegionRef A) { Arena = A; } - - // R_SExpr is the result type for a traversal. - // A copy or non-destructive rewrite returns a newly allocated term. - typedef SExpr *R_SExpr; - - // Container is a minimal interface used to store results when traversing - // SExprs of variable arity, such as Phi, Goto, and SCFG. - template class Container { - public: - // Allocate a new container with a capacity for n elements. - Container(CopyReducer &R, unsigned N) : Elems(R.Arena, N) {} - - // Push a new element onto the container. - void push_back(T E) { Elems.push_back(E); } - - private: - friend class CopyReducer; - SimpleArray Elems; - }; - -public: - R_SExpr reduceNull() { - return nullptr; - } - // R_SExpr reduceFuture(...) is never used. - - R_SExpr reduceUndefined(Undefined &Orig) { - return new (Arena) Undefined(Orig); - } - R_SExpr reduceWildcard(Wildcard &Orig) { - return new (Arena) Wildcard(Orig); - } - - R_SExpr reduceLiteral(Literal &Orig) { - return new (Arena) Literal(Orig); - } - R_SExpr reduceLiteralPtr(LiteralPtr &Orig) { - return new (Arena) LiteralPtr(Orig); - } - - R_SExpr reduceFunction(Function &Orig, Variable *Nvd, R_SExpr E0) { - return new (Arena) Function(Orig, Nvd, E0); - } - R_SExpr reduceSFunction(SFunction &Orig, Variable *Nvd, R_SExpr E0) { - return new (Arena) SFunction(Orig, Nvd, E0); - } - R_SExpr reduceCode(Code &Orig, R_SExpr E0, R_SExpr E1) { - return new (Arena) Code(Orig, E0, E1); - } - - R_SExpr reduceApply(Apply &Orig, R_SExpr E0, R_SExpr E1) { - return new (Arena) Apply(Orig, E0, E1); - } - R_SExpr reduceSApply(SApply &Orig, R_SExpr E0, R_SExpr E1) { - return new (Arena) SApply(Orig, E0, E1); - } - R_SExpr reduceProject(Project &Orig, R_SExpr E0) { - return new (Arena) Project(Orig, E0); - } - R_SExpr reduceCall(Call &Orig, R_SExpr E0) { - return new (Arena) Call(Orig, E0); - } - - R_SExpr reduceAlloc(Alloc &Orig, R_SExpr E0) { - return new (Arena) Alloc(Orig, E0); - } - R_SExpr reduceLoad(Load &Orig, R_SExpr E0) { - return new (Arena) Load(Orig, E0); - } - R_SExpr reduceStore(Store &Orig, R_SExpr E0, R_SExpr E1) { - return new (Arena) Store(Orig, E0, E1); - } - R_SExpr reduceUnaryOp(UnaryOp &Orig, R_SExpr E0) { - return new (Arena) UnaryOp(Orig, E0); - } - R_SExpr reduceBinaryOp(BinaryOp &Orig, R_SExpr E0, R_SExpr E1) { - return new (Arena) BinaryOp(Orig, E0, E1); - } - R_SExpr reduceCast(Cast &Orig, R_SExpr E0) { - return new (Arena) Cast(Orig, E0); - } - - R_SExpr reduceSCFG(SCFG &Orig, Container &Bbs) { - return new (Arena) SCFG(Orig, std::move(Bbs.Elems)); - } - R_SExpr reducePhi(Phi &Orig, Container &As) { - return new (Arena) Phi(Orig, std::move(As.Elems)); - } - R_SExpr reduceGoto(Goto &Orig, BasicBlock *B, unsigned Index) { - return new (Arena) Goto(Orig, B, Index); - } - R_SExpr reduceBranch(Branch &O, R_SExpr C, BasicBlock *B0, BasicBlock *B1) { - return new (Arena) Branch(O, C, B0, B1); - } - - BasicBlock *reduceBasicBlock(BasicBlock &Orig, Container &As, - Container &Is, R_SExpr T) { - return new (Arena) BasicBlock(Orig, std::move(As.Elems), - std::move(Is.Elems), T); - } - - // Create a new variable from orig, and push it onto the lexical scope. - Variable *enterScope(Variable &Orig, R_SExpr E0) { - return new (Arena) Variable(Orig, E0); - } - // Exit the lexical scope of orig. - void exitScope(const Variable &Orig) {} - - void enterCFG(SCFG &Cfg) {} - void exitCFG(SCFG &Cfg) {} - - // Map Variable references to their rewritten definitions. - Variable *reduceVariableRef(Variable *Ovd) { return Ovd; } - - // Map BasicBlock references to their rewritten defs. - BasicBlock *reduceBasicBlockRef(BasicBlock *Obb) { return Obb; } - -private: - MemRegionRef Arena; -}; - - -class SExprCopier : public Traversal { -public: - SExprCopier(MemRegionRef A) { setArena(A); } - - // Create a copy of e in region a. - static SExpr *copy(SExpr *E, MemRegionRef A) { - SExprCopier Copier(A); - return Copier.traverse(E); - } -}; - - -// Implements a Reducer that visits each subexpression, and returns either -// true or false. -class VisitReducer { -public: - VisitReducer() {} - - // A visitor returns a bool, representing success or failure. - typedef bool R_SExpr; - - // A visitor "container" is a single bool, which accumulates success. - template class Container { - public: - Container(VisitReducer &R, unsigned N) : Success(true) {} - void push_back(bool E) { Success = Success && E; } - - private: - friend class VisitReducer; - bool Success; - }; - -public: - R_SExpr reduceNull() { return true; } - R_SExpr reduceUndefined(Undefined &Orig) { return true; } - R_SExpr reduceWildcard(Wildcard &Orig) { return true; } - - R_SExpr reduceLiteral(Literal &Orig) { return true; } - R_SExpr reduceLiteralPtr(Literal &Orig) { return true; } - - R_SExpr reduceFunction(Function &Orig, Variable *Nvd, R_SExpr E0) { - return Nvd && E0; - } - R_SExpr reduceSFunction(SFunction &Orig, Variable *Nvd, R_SExpr E0) { - return Nvd && E0; - } - R_SExpr reduceCode(Code &Orig, R_SExpr E0, R_SExpr E1) { - return E0 && E1; - } - R_SExpr reduceApply(Apply &Orig, R_SExpr E0, R_SExpr E1) { - return E0 && E1; - } - R_SExpr reduceSApply(SApply &Orig, R_SExpr E0, R_SExpr E1) { - return E0 && E1; - } - R_SExpr reduceProject(Project &Orig, R_SExpr E0) { return E0; } - R_SExpr reduceCall(Call &Orig, R_SExpr E0) { return E0; } - R_SExpr reduceAlloc(Alloc &Orig, R_SExpr E0) { return E0; } - R_SExpr reduceLoad(Load &Orig, R_SExpr E0) { return E0; } - R_SExpr reduceStore(Store &Orig, R_SExpr E0, R_SExpr E1) { return E0 && E1; } - R_SExpr reduceUnaryOp(UnaryOp &Orig, R_SExpr E0) { return E0; } - R_SExpr reduceBinaryOp(BinaryOp &Orig, R_SExpr E0, R_SExpr E1) { - return E0 && E1; - } - R_SExpr reduceCast(Cast &Orig, R_SExpr E0) { return E0; } - - R_SExpr reduceSCFG(SCFG &Orig, Container Bbs) { - return Bbs.Success; - } - R_SExpr reducePhi(Phi &Orig, Container &As) { - return As.Success; - } - R_SExpr reduceGoto(Goto &Orig, BasicBlock *B, unsigned Index) { - return true; - } - R_SExpr reduceBranch(Branch &O, R_SExpr C, BasicBlock *B0, BasicBlock *B1) { - return C; - } - - BasicBlock *reduceBasicBlock(BasicBlock &Orig, Container &As, - Container &Is, R_SExpr T) { - return (As.Success && Is.Success && T) ? &Orig : nullptr; - } - - Variable *enterScope(Variable &Orig, R_SExpr E0) { - return E0 ? &Orig : nullptr; - } - void exitScope(const Variable &Orig) {} - - void enterCFG(SCFG &Cfg) {} - void exitCFG(SCFG &Cfg) {} - - Variable *reduceVariableRef(Variable *Ovd) { return Ovd; } - - BasicBlock *reduceBasicBlockRef(BasicBlock *Obb) { return Obb; } -}; - - -// A visitor will visit each node, and halt if any reducer returns false. -template -class SExprVisitor : public Traversal { -public: - SExprVisitor() : Success(true) {} - - bool traverse(SExpr *E, TraversalKind K = TRV_Normal) { - Success = Success && this->traverseByCase(E); - return Success; - } - - static bool visit(SExpr *E) { - SExprVisitor Visitor; - return Visitor.traverse(E); - } - -private: - bool Success; -}; - - -// Basic class for comparison operations over expressions. -template -class Comparator { -protected: - Self *self() { return reinterpret_cast(this); } - -public: - bool compareByCase(SExpr *E1, SExpr* E2) { - switch (E1->opcode()) { -#define TIL_OPCODE_DEF(X) \ - case COP_##X: \ - return cast(E1)->compare(cast(E2), *self()); -#include "clang/Analysis/Analyses/ThreadSafetyOps.def" -#undef TIL_OPCODE_DEF - case COP_MAX: - return false; - } - } -}; - - -class EqualsComparator : public Comparator { -public: - // Result type for the comparison, e.g. bool for simple equality, - // or int for lexigraphic comparison (-1, 0, 1). Must have one value which - // denotes "true". - typedef bool CType; - - CType trueResult() { return true; } - bool notTrue(CType ct) { return !ct; } - - bool compareIntegers(unsigned i, unsigned j) { return i == j; } - bool comparePointers(const void* P, const void* Q) { return P == Q; } - - bool compare(SExpr *E1, SExpr* E2) { - if (E1->opcode() != E2->opcode()) - return false; - return compareByCase(E1, E2); - } - - // TODO -- handle alpha-renaming of variables - void enterScope(Variable* V1, Variable* V2) { } - void leaveScope() { } - - bool compareVariableRefs(Variable* V1, Variable* V2) { - return V1 == V2; - } - - static bool compareExprs(SExpr *E1, SExpr* E2) { - EqualsComparator Eq; - return Eq.compare(E1, E2); - } -}; - - -// Pretty printer for TIL expressions -template -class PrettyPrinter { -public: - static void print(SExpr *E, StreamType &SS) { - Self printer; - printer.printSExpr(E, SS, Prec_MAX); - } - -protected: - Self *self() { return reinterpret_cast(this); } - - void newline(StreamType &SS) { - SS << "\n"; - } - - // TODO: further distinguish between binary operations. - static const unsigned Prec_Atom = 0; - static const unsigned Prec_Postfix = 1; - static const unsigned Prec_Unary = 2; - static const unsigned Prec_Binary = 3; - static const unsigned Prec_Other = 4; - static const unsigned Prec_Decl = 5; - static const unsigned Prec_MAX = 6; - - // Return the precedence of a given node, for use in pretty printing. - unsigned precedence(SExpr *E) { - switch (E->opcode()) { - case COP_Future: return Prec_Atom; - case COP_Undefined: return Prec_Atom; - case COP_Wildcard: return Prec_Atom; - - case COP_Literal: return Prec_Atom; - case COP_LiteralPtr: return Prec_Atom; - case COP_Variable: return Prec_Atom; - case COP_Function: return Prec_Decl; - case COP_SFunction: return Prec_Decl; - case COP_Code: return Prec_Decl; - - case COP_Apply: return Prec_Postfix; - case COP_SApply: return Prec_Postfix; - case COP_Project: return Prec_Postfix; - - case COP_Call: return Prec_Postfix; - case COP_Alloc: return Prec_Other; - case COP_Load: return Prec_Postfix; - case COP_Store: return Prec_Other; - - case COP_UnaryOp: return Prec_Unary; - case COP_BinaryOp: return Prec_Binary; - case COP_Cast: return Prec_Unary; - - case COP_SCFG: return Prec_Decl; - case COP_Phi: return Prec_Atom; - case COP_Goto: return Prec_Atom; - case COP_Branch: return Prec_Atom; - case COP_MAX: return Prec_MAX; - } - return Prec_MAX; - } - - void printSExpr(SExpr *E, StreamType &SS, unsigned P) { - if (!E) { - self()->printNull(SS); - return; - } - if (self()->precedence(E) > P) { - // Wrap expr in () if necessary. - SS << "("; - self()->printSExpr(E, SS, Prec_MAX); - SS << ")"; - return; - } - - switch (E->opcode()) { -#define TIL_OPCODE_DEF(X) \ - case COP_##X: \ - self()->print##X(cast(E), SS); \ - return; -#include "clang/Analysis/Analyses/ThreadSafetyOps.def" -#undef TIL_OPCODE_DEF - case COP_MAX: - return; - } - } - - void printNull(StreamType &SS) { - SS << "#null"; - } - - void printFuture(Future *E, StreamType &SS) { - self()->printSExpr(E->maybeGetResult(), SS, Prec_Atom); - } - - void printUndefined(Undefined *E, StreamType &SS) { - SS << "#undefined"; - } - - void printWildcard(Wildcard *E, StreamType &SS) { - SS << "_"; - } - - void printLiteral(Literal *E, StreamType &SS) { - // TODO: actually pretty print the literal. - SS << "#lit"; - } - - void printLiteralPtr(LiteralPtr *E, StreamType &SS) { - SS << E->clangDecl()->getName(); - } - - void printVariable(Variable *E, StreamType &SS) { - SS << E->name() << E->getBlockID() << "_" << E->getID(); - } - - void printFunction(Function *E, StreamType &SS, unsigned sugared = 0) { - switch (sugared) { - default: - SS << "\\("; // Lambda - case 1: - SS << "("; // Slot declarations - break; - case 2: - SS << ", "; // Curried functions - break; - } - self()->printVariable(E->variableDecl(), SS); - SS << ": "; - self()->printSExpr(E->variableDecl()->definition(), SS, Prec_MAX); - - SExpr *B = E->body(); - if (B && B->opcode() == COP_Function) - self()->printFunction(cast(B), SS, 2); - else - self()->printSExpr(B, SS, Prec_Decl); - } - - void printSFunction(SFunction *E, StreamType &SS) { - SS << "@"; - self()->printVariable(E->variableDecl(), SS); - SS << " "; - self()->printSExpr(E->body(), SS, Prec_Decl); - } - - void printCode(Code *E, StreamType &SS) { - SS << ": "; - self()->printSExpr(E->returnType(), SS, Prec_Decl-1); - SS << " = "; - self()->printSExpr(E->body(), SS, Prec_Decl); - } - - void printApply(Apply *E, StreamType &SS, bool sugared = false) { - SExpr *F = E->fun(); - if (F->opcode() == COP_Apply) { - printApply(cast(F), SS, true); - SS << ", "; - } else { - self()->printSExpr(F, SS, Prec_Postfix); - SS << "("; - } - self()->printSExpr(E->arg(), SS, Prec_MAX); - if (!sugared) - SS << ")$"; - } - - void printSApply(SApply *E, StreamType &SS) { - self()->printSExpr(E->sfun(), SS, Prec_Postfix); - SS << "@("; - self()->printSExpr(E->arg(), SS, Prec_MAX); - SS << ")"; - } - - void printProject(Project *E, StreamType &SS) { - self()->printSExpr(E->record(), SS, Prec_Postfix); - SS << "."; - SS << E->slotName(); - } - - void printCall(Call *E, StreamType &SS) { - SExpr *T = E->target(); - if (T->opcode() == COP_Apply) { - self()->printApply(cast(T), SS, true); - SS << ")"; - } - else { - self()->printSExpr(T, SS, Prec_Postfix); - SS << "()"; - } - } - - void printAlloc(Alloc *E, StreamType &SS) { - SS << "#alloc "; - self()->printSExpr(E->dataType(), SS, Prec_Other-1); - } - - void printLoad(Load *E, StreamType &SS) { - self()->printSExpr(E->pointer(), SS, Prec_Postfix); - SS << "^"; - } - - void printStore(Store *E, StreamType &SS) { - self()->printSExpr(E->destination(), SS, Prec_Other-1); - SS << " = "; - self()->printSExpr(E->source(), SS, Prec_Other-1); - } - - void printUnaryOp(UnaryOp *E, StreamType &SS) { - self()->printSExpr(E->expr(), SS, Prec_Unary); - } - - void printBinaryOp(BinaryOp *E, StreamType &SS) { - self()->printSExpr(E->expr0(), SS, Prec_Binary-1); - SS << " " << clang::BinaryOperator::getOpcodeStr(E->binaryOpcode()) << " "; - self()->printSExpr(E->expr1(), SS, Prec_Binary-1); - } - - void printCast(Cast *E, StreamType &SS) { - SS << "~"; - self()->printSExpr(E->expr(), SS, Prec_Unary); - } - - void printSCFG(SCFG *E, StreamType &SS) { - SS << "#CFG {\n"; - for (auto BBI : *E) { - SS << "BB_" << BBI->blockID() << ":"; - newline(SS); - for (auto A : BBI->arguments()) { - SS << "let "; - self()->printVariable(A, SS); - SS << " = "; - self()->printSExpr(A->definition(), SS, Prec_MAX); - SS << ";"; - newline(SS); - } - for (auto I : BBI->instructions()) { - SS << "let "; - self()->printVariable(I, SS); - SS << " = "; - self()->printSExpr(I->definition(), SS, Prec_MAX); - SS << ";"; - newline(SS); - } - SExpr *T = BBI->terminator(); - if (T) { - self()->printSExpr(T, SS, Prec_MAX); - SS << ";"; - newline(SS); - } - newline(SS); - } - SS << "}"; - newline(SS); - } - - void printPhi(Phi *E, StreamType &SS) { - SS << "#phi("; - unsigned i = 0; - for (auto V : E->values()) { - ++i; - if (i > 0) - SS << ", "; - self()->printSExpr(V, SS, Prec_MAX); - } - SS << ")"; - } - - void printGoto(Goto *E, StreamType &SS) { - SS << "#goto BB_"; - SS << E->targetBlock()->blockID(); - SS << ":"; - SS << E->index(); - } - - void printBranch(Branch *E, StreamType &SS) { - SS << "#branch ("; - self()->printSExpr(E->condition(), SS, Prec_MAX); - SS << ") BB_"; - SS << E->thenBlock()->blockID(); - SS << " BB_"; - SS << E->elseBlock()->blockID(); - } -}; - } // end namespace til - - - } // end namespace threadSafety } // end namespace clang -#endif // THREAD_SAFETY_TIL_H +#endif // LLVM_CLANG_THREAD_SAFETY_TIL_H diff --git a/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h b/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h new file mode 100644 index 0000000000..8b13af75ef --- /dev/null +++ b/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h @@ -0,0 +1,684 @@ +//===- ThreadSafetyTraverse.h ----------------------------------*- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a framework for doing generic traversals and rewriting +// operations over the Thread Safety TIL. +// +// UNDER CONSTRUCTION. USE AT YOUR OWN RISK. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_THREAD_SAFETY_TRAVERSE_H +#define LLVM_CLANG_THREAD_SAFETY_TRAVERSE_H + +#include "clang/Analysis/Analyses/ThreadSafetyTIL.h" + +namespace clang { +namespace threadSafety { +namespace til { + +// Defines an interface used to traverse SExprs. Traversals have been made as +// generic as possible, and are intended to handle any kind of pass over the +// AST, e.g. visiters, copying, non-destructive rewriting, destructive +// (in-place) rewriting, hashing, typing, etc. +// +// Traversals implement the functional notion of a "fold" operation on SExprs. +// Each SExpr class provides a traverse method, which does the following: +// * e->traverse(v): +// // compute a result r_i for each subexpression e_i +// for (i = 1..n) r_i = v.traverse(e_i); +// // combine results into a result for e, where X is the class of e +// return v.reduceX(*e, r_1, .. r_n). +// +// A visitor can control the traversal by overriding the following methods: +// * v.traverse(e): +// return v.traverseByCase(e), which returns v.traverseX(e) +// * v.traverseX(e): (X is the class of e) +// return e->traverse(v). +// * v.reduceX(*e, r_1, .. r_n): +// compute a result for a node of type X +// +// The reduceX methods control the kind of traversal (visitor, copy, etc.). +// These are separated into a separate class R for the purpose of code reuse. +// The full reducer interface also has methods to handle scopes +template class Traversal : public R { +public: + Self *self() { return reinterpret_cast(this); } + + // Traverse an expression -- returning a result of type R_SExpr. + // Override this method to do something for every expression, regardless + // of which kind it is. TraversalKind indicates the context in which + // the expression occurs, and can be: + // TRV_Normal + // TRV_Lazy -- e may need to be traversed lazily, using a Future. + // TRV_Tail -- e occurs in a tail position + typename R::R_SExpr traverse(SExprRef &E, TraversalKind K = TRV_Normal) { + return traverse(E.get(), K); + } + + typename R::R_SExpr traverse(SExpr *E, TraversalKind K = TRV_Normal) { + return traverseByCase(E); + } + + // Helper method to call traverseX(e) on the appropriate type. + typename R::R_SExpr traverseByCase(SExpr *E) { + switch (E->opcode()) { +#define TIL_OPCODE_DEF(X) \ + case COP_##X: \ + return self()->traverse##X(cast(E)); +#include "clang/Analysis/Analyses/ThreadSafetyOps.def" +#undef TIL_OPCODE_DEF + case COP_MAX: + return self()->reduceNull(); + } + } + +// Traverse e, by static dispatch on the type "X" of e. +// Override these methods to do something for a particular kind of term. +#define TIL_OPCODE_DEF(X) \ + typename R::R_SExpr traverse##X(X *e) { return e->traverse(*self()); } +#include "clang/Analysis/Analyses/ThreadSafetyOps.def" +#undef TIL_OPCODE_DEF +}; + + +// Implements a Reducer that makes a deep copy of an SExpr. +// The default behavior of reduce##X(...) is to create a copy of the original. +// Subclasses can override reduce##X to implement non-destructive rewriting +// passes. +class CopyReducer { +public: + CopyReducer() {} + + void setArena(MemRegionRef A) { Arena = A; } + + // R_SExpr is the result type for a traversal. + // A copy or non-destructive rewrite returns a newly allocated term. + typedef SExpr *R_SExpr; + + // Container is a minimal interface used to store results when traversing + // SExprs of variable arity, such as Phi, Goto, and SCFG. + template class Container { + public: + // Allocate a new container with a capacity for n elements. + Container(CopyReducer &R, unsigned N) : Elems(R.Arena, N) {} + + // Push a new element onto the container. + void push_back(T E) { Elems.push_back(E); } + + private: + friend class CopyReducer; + SimpleArray Elems; + }; + +public: + R_SExpr reduceNull() { + return nullptr; + } + // R_SExpr reduceFuture(...) is never used. + + R_SExpr reduceUndefined(Undefined &Orig) { + return new (Arena) Undefined(Orig); + } + R_SExpr reduceWildcard(Wildcard &Orig) { + return new (Arena) Wildcard(Orig); + } + + R_SExpr reduceLiteral(Literal &Orig) { + return new (Arena) Literal(Orig); + } + R_SExpr reduceLiteralPtr(LiteralPtr &Orig) { + return new (Arena) LiteralPtr(Orig); + } + + R_SExpr reduceFunction(Function &Orig, Variable *Nvd, R_SExpr E0) { + return new (Arena) Function(Orig, Nvd, E0); + } + R_SExpr reduceSFunction(SFunction &Orig, Variable *Nvd, R_SExpr E0) { + return new (Arena) SFunction(Orig, Nvd, E0); + } + R_SExpr reduceCode(Code &Orig, R_SExpr E0, R_SExpr E1) { + return new (Arena) Code(Orig, E0, E1); + } + + R_SExpr reduceApply(Apply &Orig, R_SExpr E0, R_SExpr E1) { + return new (Arena) Apply(Orig, E0, E1); + } + R_SExpr reduceSApply(SApply &Orig, R_SExpr E0, R_SExpr E1) { + return new (Arena) SApply(Orig, E0, E1); + } + R_SExpr reduceProject(Project &Orig, R_SExpr E0) { + return new (Arena) Project(Orig, E0); + } + R_SExpr reduceCall(Call &Orig, R_SExpr E0) { + return new (Arena) Call(Orig, E0); + } + + R_SExpr reduceAlloc(Alloc &Orig, R_SExpr E0) { + return new (Arena) Alloc(Orig, E0); + } + R_SExpr reduceLoad(Load &Orig, R_SExpr E0) { + return new (Arena) Load(Orig, E0); + } + R_SExpr reduceStore(Store &Orig, R_SExpr E0, R_SExpr E1) { + return new (Arena) Store(Orig, E0, E1); + } + R_SExpr reduceUnaryOp(UnaryOp &Orig, R_SExpr E0) { + return new (Arena) UnaryOp(Orig, E0); + } + R_SExpr reduceBinaryOp(BinaryOp &Orig, R_SExpr E0, R_SExpr E1) { + return new (Arena) BinaryOp(Orig, E0, E1); + } + R_SExpr reduceCast(Cast &Orig, R_SExpr E0) { + return new (Arena) Cast(Orig, E0); + } + + R_SExpr reduceSCFG(SCFG &Orig, Container &Bbs) { + return new (Arena) SCFG(Orig, std::move(Bbs.Elems)); + } + R_SExpr reducePhi(Phi &Orig, Container &As) { + return new (Arena) Phi(Orig, std::move(As.Elems)); + } + R_SExpr reduceGoto(Goto &Orig, BasicBlock *B, unsigned Index) { + return new (Arena) Goto(Orig, B, Index); + } + R_SExpr reduceBranch(Branch &O, R_SExpr C, BasicBlock *B0, BasicBlock *B1) { + return new (Arena) Branch(O, C, B0, B1); + } + + BasicBlock *reduceBasicBlock(BasicBlock &Orig, Container &As, + Container &Is, R_SExpr T) { + return new (Arena) BasicBlock(Orig, std::move(As.Elems), + std::move(Is.Elems), T); + } + + // Create a new variable from orig, and push it onto the lexical scope. + Variable *enterScope(Variable &Orig, R_SExpr E0) { + return new (Arena) Variable(Orig, E0); + } + // Exit the lexical scope of orig. + void exitScope(const Variable &Orig) {} + + void enterCFG(SCFG &Cfg) {} + void exitCFG(SCFG &Cfg) {} + + // Map Variable references to their rewritten definitions. + Variable *reduceVariableRef(Variable *Ovd) { return Ovd; } + + // Map BasicBlock references to their rewritten defs. + BasicBlock *reduceBasicBlockRef(BasicBlock *Obb) { return Obb; } + +private: + MemRegionRef Arena; +}; + + +class SExprCopier : public Traversal { +public: + SExprCopier(MemRegionRef A) { setArena(A); } + + // Create a copy of e in region a. + static SExpr *copy(SExpr *E, MemRegionRef A) { + SExprCopier Copier(A); + return Copier.traverse(E); + } +}; + + +// Implements a Reducer that visits each subexpression, and returns either +// true or false. +class VisitReducer { +public: + VisitReducer() {} + + // A visitor returns a bool, representing success or failure. + typedef bool R_SExpr; + + // A visitor "container" is a single bool, which accumulates success. + template class Container { + public: + Container(VisitReducer &R, unsigned N) : Success(true) {} + void push_back(bool E) { Success = Success && E; } + + private: + friend class VisitReducer; + bool Success; + }; + +public: + R_SExpr reduceNull() { return true; } + R_SExpr reduceUndefined(Undefined &Orig) { return true; } + R_SExpr reduceWildcard(Wildcard &Orig) { return true; } + + R_SExpr reduceLiteral(Literal &Orig) { return true; } + R_SExpr reduceLiteralPtr(Literal &Orig) { return true; } + + R_SExpr reduceFunction(Function &Orig, Variable *Nvd, R_SExpr E0) { + return Nvd && E0; + } + R_SExpr reduceSFunction(SFunction &Orig, Variable *Nvd, R_SExpr E0) { + return Nvd && E0; + } + R_SExpr reduceCode(Code &Orig, R_SExpr E0, R_SExpr E1) { + return E0 && E1; + } + R_SExpr reduceApply(Apply &Orig, R_SExpr E0, R_SExpr E1) { + return E0 && E1; + } + R_SExpr reduceSApply(SApply &Orig, R_SExpr E0, R_SExpr E1) { + return E0 && E1; + } + R_SExpr reduceProject(Project &Orig, R_SExpr E0) { return E0; } + R_SExpr reduceCall(Call &Orig, R_SExpr E0) { return E0; } + R_SExpr reduceAlloc(Alloc &Orig, R_SExpr E0) { return E0; } + R_SExpr reduceLoad(Load &Orig, R_SExpr E0) { return E0; } + R_SExpr reduceStore(Store &Orig, R_SExpr E0, R_SExpr E1) { return E0 && E1; } + R_SExpr reduceUnaryOp(UnaryOp &Orig, R_SExpr E0) { return E0; } + R_SExpr reduceBinaryOp(BinaryOp &Orig, R_SExpr E0, R_SExpr E1) { + return E0 && E1; + } + R_SExpr reduceCast(Cast &Orig, R_SExpr E0) { return E0; } + + R_SExpr reduceSCFG(SCFG &Orig, Container Bbs) { + return Bbs.Success; + } + R_SExpr reducePhi(Phi &Orig, Container &As) { + return As.Success; + } + R_SExpr reduceGoto(Goto &Orig, BasicBlock *B, unsigned Index) { + return true; + } + R_SExpr reduceBranch(Branch &O, R_SExpr C, BasicBlock *B0, BasicBlock *B1) { + return C; + } + + BasicBlock *reduceBasicBlock(BasicBlock &Orig, Container &As, + Container &Is, R_SExpr T) { + return (As.Success && Is.Success && T) ? &Orig : nullptr; + } + + Variable *enterScope(Variable &Orig, R_SExpr E0) { + return E0 ? &Orig : nullptr; + } + void exitScope(const Variable &Orig) {} + + void enterCFG(SCFG &Cfg) {} + void exitCFG(SCFG &Cfg) {} + + Variable *reduceVariableRef(Variable *Ovd) { return Ovd; } + + BasicBlock *reduceBasicBlockRef(BasicBlock *Obb) { return Obb; } +}; + + +// A visitor will visit each node, and halt if any reducer returns false. +template +class SExprVisitor : public Traversal { +public: + SExprVisitor() : Success(true) {} + + bool traverse(SExpr *E, TraversalKind K = TRV_Normal) { + Success = Success && this->traverseByCase(E); + return Success; + } + + static bool visit(SExpr *E) { + SExprVisitor Visitor; + return Visitor.traverse(E); + } + +private: + bool Success; +}; + + +// Basic class for comparison operations over expressions. +template +class Comparator { +protected: + Self *self() { return reinterpret_cast(this); } + +public: + bool compareByCase(SExpr *E1, SExpr* E2) { + switch (E1->opcode()) { +#define TIL_OPCODE_DEF(X) \ + case COP_##X: \ + return cast(E1)->compare(cast(E2), *self()); +#include "clang/Analysis/Analyses/ThreadSafetyOps.def" +#undef TIL_OPCODE_DEF + case COP_MAX: + return false; + } + } +}; + + +class EqualsComparator : public Comparator { +public: + // Result type for the comparison, e.g. bool for simple equality, + // or int for lexigraphic comparison (-1, 0, 1). Must have one value which + // denotes "true". + typedef bool CType; + + CType trueResult() { return true; } + bool notTrue(CType ct) { return !ct; } + + bool compareIntegers(unsigned i, unsigned j) { return i == j; } + bool comparePointers(const void* P, const void* Q) { return P == Q; } + + bool compare(SExpr *E1, SExpr* E2) { + if (E1->opcode() != E2->opcode()) + return false; + return compareByCase(E1, E2); + } + + // TODO -- handle alpha-renaming of variables + void enterScope(Variable* V1, Variable* V2) { } + void leaveScope() { } + + bool compareVariableRefs(Variable* V1, Variable* V2) { + return V1 == V2; + } + + static bool compareExprs(SExpr *E1, SExpr* E2) { + EqualsComparator Eq; + return Eq.compare(E1, E2); + } +}; + + +// Pretty printer for TIL expressions +template +class PrettyPrinter { +public: + static void print(SExpr *E, StreamType &SS) { + Self printer; + printer.printSExpr(E, SS, Prec_MAX); + } + +protected: + Self *self() { return reinterpret_cast(this); } + + void newline(StreamType &SS) { + SS << "\n"; + } + + // TODO: further distinguish between binary operations. + static const unsigned Prec_Atom = 0; + static const unsigned Prec_Postfix = 1; + static const unsigned Prec_Unary = 2; + static const unsigned Prec_Binary = 3; + static const unsigned Prec_Other = 4; + static const unsigned Prec_Decl = 5; + static const unsigned Prec_MAX = 6; + + // Return the precedence of a given node, for use in pretty printing. + unsigned precedence(SExpr *E) { + switch (E->opcode()) { + case COP_Future: return Prec_Atom; + case COP_Undefined: return Prec_Atom; + case COP_Wildcard: return Prec_Atom; + + case COP_Literal: return Prec_Atom; + case COP_LiteralPtr: return Prec_Atom; + case COP_Variable: return Prec_Atom; + case COP_Function: return Prec_Decl; + case COP_SFunction: return Prec_Decl; + case COP_Code: return Prec_Decl; + + case COP_Apply: return Prec_Postfix; + case COP_SApply: return Prec_Postfix; + case COP_Project: return Prec_Postfix; + + case COP_Call: return Prec_Postfix; + case COP_Alloc: return Prec_Other; + case COP_Load: return Prec_Postfix; + case COP_Store: return Prec_Other; + + case COP_UnaryOp: return Prec_Unary; + case COP_BinaryOp: return Prec_Binary; + case COP_Cast: return Prec_Unary; + + case COP_SCFG: return Prec_Decl; + case COP_Phi: return Prec_Atom; + case COP_Goto: return Prec_Atom; + case COP_Branch: return Prec_Atom; + case COP_MAX: return Prec_MAX; + } + return Prec_MAX; + } + + void printSExpr(SExpr *E, StreamType &SS, unsigned P) { + if (!E) { + self()->printNull(SS); + return; + } + if (self()->precedence(E) > P) { + // Wrap expr in () if necessary. + SS << "("; + self()->printSExpr(E, SS, Prec_MAX); + SS << ")"; + return; + } + + switch (E->opcode()) { +#define TIL_OPCODE_DEF(X) \ + case COP_##X: \ + self()->print##X(cast(E), SS); \ + return; +#include "clang/Analysis/Analyses/ThreadSafetyOps.def" +#undef TIL_OPCODE_DEF + case COP_MAX: + return; + } + } + + void printNull(StreamType &SS) { + SS << "#null"; + } + + void printFuture(Future *E, StreamType &SS) { + self()->printSExpr(E->maybeGetResult(), SS, Prec_Atom); + } + + void printUndefined(Undefined *E, StreamType &SS) { + SS << "#undefined"; + } + + void printWildcard(Wildcard *E, StreamType &SS) { + SS << "_"; + } + + void printLiteral(Literal *E, StreamType &SS) { + // TODO: actually pretty print the literal. + SS << "#lit"; + } + + void printLiteralPtr(LiteralPtr *E, StreamType &SS) { + SS << E->clangDecl()->getName(); + } + + void printVariable(Variable *E, StreamType &SS) { + SS << E->name() << E->getBlockID() << "_" << E->getID(); + } + + void printFunction(Function *E, StreamType &SS, unsigned sugared = 0) { + switch (sugared) { + default: + SS << "\\("; // Lambda + case 1: + SS << "("; // Slot declarations + break; + case 2: + SS << ", "; // Curried functions + break; + } + self()->printVariable(E->variableDecl(), SS); + SS << ": "; + self()->printSExpr(E->variableDecl()->definition(), SS, Prec_MAX); + + SExpr *B = E->body(); + if (B && B->opcode() == COP_Function) + self()->printFunction(cast(B), SS, 2); + else + self()->printSExpr(B, SS, Prec_Decl); + } + + void printSFunction(SFunction *E, StreamType &SS) { + SS << "@"; + self()->printVariable(E->variableDecl(), SS); + SS << " "; + self()->printSExpr(E->body(), SS, Prec_Decl); + } + + void printCode(Code *E, StreamType &SS) { + SS << ": "; + self()->printSExpr(E->returnType(), SS, Prec_Decl-1); + SS << " = "; + self()->printSExpr(E->body(), SS, Prec_Decl); + } + + void printApply(Apply *E, StreamType &SS, bool sugared = false) { + SExpr *F = E->fun(); + if (F->opcode() == COP_Apply) { + printApply(cast(F), SS, true); + SS << ", "; + } else { + self()->printSExpr(F, SS, Prec_Postfix); + SS << "("; + } + self()->printSExpr(E->arg(), SS, Prec_MAX); + if (!sugared) + SS << ")$"; + } + + void printSApply(SApply *E, StreamType &SS) { + self()->printSExpr(E->sfun(), SS, Prec_Postfix); + SS << "@("; + self()->printSExpr(E->arg(), SS, Prec_MAX); + SS << ")"; + } + + void printProject(Project *E, StreamType &SS) { + self()->printSExpr(E->record(), SS, Prec_Postfix); + SS << "."; + SS << E->slotName(); + } + + void printCall(Call *E, StreamType &SS) { + SExpr *T = E->target(); + if (T->opcode() == COP_Apply) { + self()->printApply(cast(T), SS, true); + SS << ")"; + } + else { + self()->printSExpr(T, SS, Prec_Postfix); + SS << "()"; + } + } + + void printAlloc(Alloc *E, StreamType &SS) { + SS << "#alloc "; + self()->printSExpr(E->dataType(), SS, Prec_Other-1); + } + + void printLoad(Load *E, StreamType &SS) { + self()->printSExpr(E->pointer(), SS, Prec_Postfix); + SS << "^"; + } + + void printStore(Store *E, StreamType &SS) { + self()->printSExpr(E->destination(), SS, Prec_Other-1); + SS << " = "; + self()->printSExpr(E->source(), SS, Prec_Other-1); + } + + void printUnaryOp(UnaryOp *E, StreamType &SS) { + self()->printSExpr(E->expr(), SS, Prec_Unary); + } + + void printBinaryOp(BinaryOp *E, StreamType &SS) { + self()->printSExpr(E->expr0(), SS, Prec_Binary-1); + SS << " " << clang::BinaryOperator::getOpcodeStr(E->binaryOpcode()) << " "; + self()->printSExpr(E->expr1(), SS, Prec_Binary-1); + } + + void printCast(Cast *E, StreamType &SS) { + SS << "~"; + self()->printSExpr(E->expr(), SS, Prec_Unary); + } + + void printSCFG(SCFG *E, StreamType &SS) { + SS << "#CFG {\n"; + for (auto BBI : *E) { + SS << "BB_" << BBI->blockID() << ":"; + newline(SS); + for (auto A : BBI->arguments()) { + SS << "let "; + self()->printVariable(A, SS); + SS << " = "; + self()->printSExpr(A->definition(), SS, Prec_MAX); + SS << ";"; + newline(SS); + } + for (auto I : BBI->instructions()) { + SS << "let "; + self()->printVariable(I, SS); + SS << " = "; + self()->printSExpr(I->definition(), SS, Prec_MAX); + SS << ";"; + newline(SS); + } + SExpr *T = BBI->terminator(); + if (T) { + self()->printSExpr(T, SS, Prec_MAX); + SS << ";"; + newline(SS); + } + newline(SS); + } + SS << "}"; + newline(SS); + } + + void printPhi(Phi *E, StreamType &SS) { + SS << "#phi("; + unsigned i = 0; + for (auto V : E->values()) { + ++i; + if (i > 0) + SS << ", "; + self()->printSExpr(V, SS, Prec_MAX); + } + SS << ")"; + } + + void printGoto(Goto *E, StreamType &SS) { + SS << "#goto BB_"; + SS << E->targetBlock()->blockID(); + SS << ":"; + SS << E->index(); + } + + void printBranch(Branch *E, StreamType &SS) { + SS << "#branch ("; + self()->printSExpr(E->condition(), SS, Prec_MAX); + SS << ") BB_"; + SS << E->thenBlock()->blockID(); + SS << " BB_"; + SS << E->elseBlock()->blockID(); + } +}; + + +} // end namespace til +} // end namespace threadSafety +} // end namespace clang + +#endif // LLVM_CLANG_THREAD_SAFETY_TRAVERSE_H diff --git a/include/clang/Analysis/Analyses/ThreadSafetyUtil.h b/include/clang/Analysis/Analyses/ThreadSafetyUtil.h new file mode 100644 index 0000000000..f565ece8d6 --- /dev/null +++ b/include/clang/Analysis/Analyses/ThreadSafetyUtil.h @@ -0,0 +1,140 @@ +//===- ThreadSafetyUtil.h --------------------------------------*- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines some basic utility classes for use by ThreadSafetyTIL.h +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_THREAD_SAFETY_UTIL_H +#define LLVM_CLANG_THREAD_SAFETY_UTIL_H + +#include "llvm/Support/AlignOf.h" +#include "llvm/Support/Allocator.h" + +#include +#include +#include + +namespace clang { +namespace threadSafety { +namespace til { + +// Simple wrapper class to abstract away from the details of memory management. +// SExprs are allocated in pools, and deallocated all at once. +class MemRegionRef { +private: + union AlignmentType { + double d; + void *p; + long double dd; + long long ii; + }; + +public: + MemRegionRef() : Allocator(nullptr) {} + MemRegionRef(llvm::BumpPtrAllocator *A) : Allocator(A) {} + + void *allocate(size_t Sz) { + return Allocator->Allocate(Sz, llvm::AlignOf::Alignment); + } + + template T *allocateT() { return Allocator->Allocate(); } + + template T *allocateT(size_t NumElems) { + return Allocator->Allocate(NumElems); + } + +private: + llvm::BumpPtrAllocator *Allocator; +}; + + +} // end namespace til +} // end namespace threadSafety +} // end namespace clang + + +inline void *operator new(size_t Sz, + clang::threadSafety::til::MemRegionRef &R) { + return R.allocate(Sz); +} + + +namespace clang { +namespace threadSafety { +namespace til { + +using llvm::StringRef; + +// A simple fixed size array class that does not manage its own memory, +// suitable for use with bump pointer allocation. +template 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) {} + SimpleArray(MemRegionRef A, size_t Cp) + : Data(A.allocateT(Cp)), Size(0), Capacity(Cp) {} + SimpleArray(SimpleArray &&A) + : Data(A.Data), Size(A.Size), Capacity(A.Capacity) { + A.Data = nullptr; + A.Size = 0; + A.Capacity = 0; + } + + T *resize(size_t Ncp, MemRegionRef A) { + T *Odata = Data; + Data = A.allocateT(Ncp); + memcpy(Data, Odata, sizeof(T) * Size); + return Odata; + } + + typedef T *iterator; + typedef const T *const_iterator; + + 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]; } + + iterator begin() { return Data; } + iterator end() { return Data + Size; } + + const_iterator cbegin() const { return Data; } + const_iterator cend() const { return Data + Size; } + + void push_back(const T &Elem) { + assert(Size < Capacity); + Data[Size++] = Elem; + } + + template unsigned append(Iter I, Iter E) { + size_t Osz = Size; + size_t J = Osz; + for (; J < Capacity && I != E; ++J, ++I) + Data[J] = *I; + Size = J; + return J - Osz; + } + +private: + SimpleArray(const SimpleArray &A) { } + + T *Data; + size_t Size; + size_t Capacity; +}; + + +} // end namespace til +} // end namespace threadSafety +} // end namespace clang + +#endif // LLVM_CLANG_THREAD_SAFETY_UTIL_H diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp index 9cc2a55f0a..b6a73bd2d8 100644 --- a/lib/Analysis/ThreadSafety.cpp +++ b/lib/Analysis/ThreadSafety.cpp @@ -23,6 +23,7 @@ #include "clang/Analysis/Analyses/PostOrderCFGView.h" #include "clang/Analysis/Analyses/ThreadSafety.h" #include "clang/Analysis/Analyses/ThreadSafetyTIL.h" +#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h" #include "clang/Analysis/Analyses/ThreadSafetyCommon.h" #include "clang/Analysis/AnalysisContext.h" #include "clang/Analysis/CFG.h" diff --git a/lib/Analysis/ThreadSafetyCommon.cpp b/lib/Analysis/ThreadSafetyCommon.cpp index b916c75db9..7413a3373c 100644 --- a/lib/Analysis/ThreadSafetyCommon.cpp +++ b/lib/Analysis/ThreadSafetyCommon.cpp @@ -18,6 +18,7 @@ #include "clang/AST/StmtCXX.h" #include "clang/Analysis/Analyses/PostOrderCFGView.h" #include "clang/Analysis/Analyses/ThreadSafetyTIL.h" +#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h" #include "clang/Analysis/AnalysisContext.h" #include "clang/Analysis/CFG.h" #include "clang/Basic/OperatorKinds.h" @@ -26,6 +27,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" + #include @@ -299,8 +301,14 @@ til::SExpr *SExprBuilder::translateBinaryConditionalOperator( return new (Arena) til::Undefined(C); } + + // Build a complete SCFG from a clang CFG. class SCFGBuilder { + class BBInfo { + + }; + void addStatement(til::SExpr* E, const Stmt *S) { if (!E) return;