r205936 - Thread Safety Analysis: reorganized SExpr header files. No change in
DeLesley Hutchins
delesley at google.com
Wed Apr 9 15:39:43 PDT 2014
Author: delesley
Date: Wed Apr 9 17:39:43 2014
New Revision: 205936
URL: http://llvm.org/viewvc/llvm-project?rev=205936&view=rev
Log:
Thread Safety Analysis: reorganized SExpr header files. No change in
functionality.
Added:
cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h
cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyUtil.h
Modified:
cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h
cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h
cfe/trunk/lib/Analysis/ThreadSafety.cpp
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=205936&r1=205935&r2=205936&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h Wed Apr 9 17:39:43 2014
@@ -26,6 +26,7 @@
#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Basic/OperatorKinds.h"
+
#include <vector>
@@ -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.
};
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=205936&r1=205935&r2=205936&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h Wed Apr 9 17:39:43 2014
@@ -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 <cassert>
#include <cstddef>
#include <utility>
-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<AlignmentType>::Alignment);
- }
-
- template <typename T> T *allocateT() { return Allocator->Allocate<T>(); }
-
- template <typename T> T *allocateT(size_t NumElems) {
- return Allocator->Allocate<T>(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 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) {}
- SimpleArray(MemRegionRef A, size_t Cp)
- : Data(A.allocateT<T>(Cp)), Size(0), Capacity(Cp) {}
- SimpleArray(SimpleArray<T> &&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<T>(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 <class Iter> 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<T> &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 Self, class R> class Traversal : public R {
-public:
- Self *self() { return reinterpret_cast<Self *>(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<X>(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 T> 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<T> 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<BasicBlock *> &Bbs) {
- return new (Arena) SCFG(Orig, std::move(Bbs.Elems));
- }
- R_SExpr reducePhi(Phi &Orig, Container<R_SExpr> &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<Variable *> &As,
- Container<Variable *> &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<SExprCopier, CopyReducer> {
-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 T> 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<BasicBlock *> Bbs) {
- return Bbs.Success;
- }
- R_SExpr reducePhi(Phi &Orig, Container<R_SExpr> &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<Variable *> &As,
- Container<Variable *> &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 Self>
-class SExprVisitor : public Traversal<Self, VisitReducer> {
-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 <typename Self>
-class Comparator {
-protected:
- Self *self() { return reinterpret_cast<Self *>(this); }
-
-public:
- bool compareByCase(SExpr *E1, SExpr* E2) {
- switch (E1->opcode()) {
-#define TIL_OPCODE_DEF(X) \
- case COP_##X: \
- return cast<X>(E1)->compare(cast<X>(E2), *self());
-#include "clang/Analysis/Analyses/ThreadSafetyOps.def"
-#undef TIL_OPCODE_DEF
- case COP_MAX:
- return false;
- }
- }
-};
-
-
-class EqualsComparator : public Comparator<EqualsComparator> {
-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 <typename Self, typename StreamType>
-class PrettyPrinter {
-public:
- static void print(SExpr *E, StreamType &SS) {
- Self printer;
- printer.printSExpr(E, SS, Prec_MAX);
- }
-
-protected:
- Self *self() { return reinterpret_cast<Self *>(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<X>(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<Function>(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<Apply>(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<Apply>(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
Added: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h?rev=205936&view=auto
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h (added)
+++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h Wed Apr 9 17:39:43 2014
@@ -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 Self, class R> class Traversal : public R {
+public:
+ Self *self() { return reinterpret_cast<Self *>(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<X>(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 T> 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<T> 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<BasicBlock *> &Bbs) {
+ return new (Arena) SCFG(Orig, std::move(Bbs.Elems));
+ }
+ R_SExpr reducePhi(Phi &Orig, Container<R_SExpr> &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<Variable *> &As,
+ Container<Variable *> &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<SExprCopier, CopyReducer> {
+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 T> 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<BasicBlock *> Bbs) {
+ return Bbs.Success;
+ }
+ R_SExpr reducePhi(Phi &Orig, Container<R_SExpr> &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<Variable *> &As,
+ Container<Variable *> &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 Self>
+class SExprVisitor : public Traversal<Self, VisitReducer> {
+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 <typename Self>
+class Comparator {
+protected:
+ Self *self() { return reinterpret_cast<Self *>(this); }
+
+public:
+ bool compareByCase(SExpr *E1, SExpr* E2) {
+ switch (E1->opcode()) {
+#define TIL_OPCODE_DEF(X) \
+ case COP_##X: \
+ return cast<X>(E1)->compare(cast<X>(E2), *self());
+#include "clang/Analysis/Analyses/ThreadSafetyOps.def"
+#undef TIL_OPCODE_DEF
+ case COP_MAX:
+ return false;
+ }
+ }
+};
+
+
+class EqualsComparator : public Comparator<EqualsComparator> {
+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 <typename Self, typename StreamType>
+class PrettyPrinter {
+public:
+ static void print(SExpr *E, StreamType &SS) {
+ Self printer;
+ printer.printSExpr(E, SS, Prec_MAX);
+ }
+
+protected:
+ Self *self() { return reinterpret_cast<Self *>(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<X>(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<Function>(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<Apply>(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<Apply>(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
Added: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyUtil.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyUtil.h?rev=205936&view=auto
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyUtil.h (added)
+++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyUtil.h Wed Apr 9 17:39:43 2014
@@ -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 <cassert>
+#include <cstddef>
+#include <utility>
+
+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<AlignmentType>::Alignment);
+ }
+
+ template <typename T> T *allocateT() { return Allocator->Allocate<T>(); }
+
+ template <typename T> T *allocateT(size_t NumElems) {
+ return Allocator->Allocate<T>(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 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) {}
+ SimpleArray(MemRegionRef A, size_t Cp)
+ : Data(A.allocateT<T>(Cp)), Size(0), Capacity(Cp) {}
+ SimpleArray(SimpleArray<T> &&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<T>(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 <class Iter> 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<T> &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
Modified: cfe/trunk/lib/Analysis/ThreadSafety.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafety.cpp?rev=205936&r1=205935&r2=205936&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/ThreadSafety.cpp (original)
+++ cfe/trunk/lib/Analysis/ThreadSafety.cpp Wed Apr 9 17:39:43 2014
@@ -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"
Modified: cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp?rev=205936&r1=205935&r2=205936&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp (original)
+++ cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp Wed Apr 9 17:39:43 2014
@@ -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 <vector>
@@ -299,8 +301,14 @@ til::SExpr *SExprBuilder::translateBinar
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;
More information about the cfe-commits
mailing list