Thread Safety Analysis: reorganized SExpr header files. No change in

functionality.

llvm-svn: 205936
This commit is contained in:
DeLesley Hutchins 2014-04-09 22:39:43 +00:00
parent b49fee0b41
commit 7e615c2f65
6 changed files with 842 additions and 768 deletions

View File

@ -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.
};

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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::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;