r205728 - Thread Safety Analysis: update to internal SExpr handling.

Aaron Ballman aaron at aaronballman.com
Mon Apr 7 14:50:31 PDT 2014


Since you're already worrying about const-correctness, I'll leave
those comments out for now. Also, since this is new code, clang-format
would be appropriate since there's a fair number of formatting issues.
Other comments below.

On Mon, Apr 7, 2014 at 2:09 PM, DeLesley Hutchins <delesley at google.com> wrote:
> Author: delesley
> Date: Mon Apr  7 13:09:54 2014
> New Revision: 205728
>
> URL: http://llvm.org/viewvc/llvm-project?rev=205728&view=rev
> Log:
> Thread Safety Analysis: update to internal SExpr handling.
> This patch is the first part of a significant refactoring that seeks to restore
> sanity to way thread safety analysis deals with capability expressions.  The
> current patch merely provides an outline of the structure of the new system.
> It's not yet connected to the actual analysis, so there's no change in
> functionality.
>
> Added:
>     cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h
>     cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyOps.def
>     cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h
>     cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp
> Modified:
>     cfe/trunk/lib/Analysis/CMakeLists.txt
>     cfe/trunk/lib/Analysis/ThreadSafety.cpp
>
> Added: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h?rev=205728&view=auto
> ==============================================================================
> --- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h (added)
> +++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h Mon Apr  7 13:09:54 2014
> @@ -0,0 +1,244 @@
> +//===- ThreadSafetyCommon.h ------------------------------------*- C++ --*-===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// Parts of thread safety analysis that are not specific to thread safety
> +// itself have been factored into classes here, where they can be potentially
> +// used by other analyses.  Currently these include:
> +//
> +// * Generalize clang CFG visitors.
> +// * Conversion of the clang CFG to SSA form.
> +// * Translation of clang Exprs to TIL SExprs
> +//
> +// UNDER CONSTRUCTION.  USE AT YOUR OWN RISK.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "clang/AST/Attr.h"
> +#include "clang/AST/DeclCXX.h"
> +#include "clang/AST/ExprCXX.h"
> +#include "clang/AST/StmtCXX.h"
> +#include "clang/AST/StmtVisitor.h"
> +#include "clang/Analysis/Analyses/PostOrderCFGView.h"
> +#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
> +#include "clang/Analysis/AnalysisContext.h"
> +#include "clang/Analysis/CFG.h"
> +#include "clang/Analysis/CFGStmtMap.h"
> +#include "clang/Basic/OperatorKinds.h"
> +#include "clang/Basic/SourceLocation.h"
> +#include "clang/Basic/SourceManager.h"
> +#include "llvm/ADT/BitVector.h"
> +#include "llvm/ADT/DenseMap.h"
> +#include "llvm/ADT/FoldingSet.h"
> +#include "llvm/ADT/ImmutableMap.h"
> +#include "llvm/ADT/PostOrderIterator.h"
> +#include "llvm/ADT/SmallVector.h"
> +#include "llvm/ADT/StringRef.h"
> +#include <vector>

It seems like a whole lot of these could be forward declares.

> +
> +
> +namespace clang {
> +namespace threadSafety {
> +
> +
> +// Simple Visitor class for traversing a clang CFG.
> +class CFGVisitor {
> +public:
> +  // Enter the CFG for Decl D, and perform any initial setup operations.
> +  void enterCFG(CFG *Cfg, const NamedDecl *D, const CFGBlock *First) {}
> +
> +  // Enter a CFGBlock.
> +  void enterCFGBlock(const CFGBlock *B) {}
> +
> +  // Process an ordinary statement.
> +  void handleStatement(const Stmt *S) {}
> +
> +  // Process a destructor call
> +  void handleDestructorCall(const VarDecl *VD, const CXXDestructorDecl *DD) {}
> +
> +  // Process a successor edge.
> +  void handleSuccessor(const CFGBlock *Succ) {}
> +
> +  // Process a successor back edge to a previously visited block.
> +  void handleSuccessorBackEdge(const CFGBlock *Succ) {}
> +
> +  // Leave a CFGBlock.
> +  void exitCFGBlock(const CFGBlock *B) {}
> +
> +  // Leave the CFG, and perform any final cleanup operations.
> +  void exitCFG(const CFGBlock *Last) {}
> +};

These all look very much like they should be virtual methods.

> +
> +
> +// Walks the clang CFG, and invokes methods on a given CFGVisitor.
> +class CFGWalker {
> +public:
> +  CFGWalker() : CFGraph(0), FDecl(0), ACtx(0), SortedGraph(0) {}

nullptr instead of 0?

> +
> +  ~CFGWalker() { }

Why is this required?

> +
> +  // Initialize the CFGWalker.  This setup only needs to be done once, even
> +  // if there are multiple passes over the CFG.
> +  bool init(AnalysisDeclContext &AC) {

Why is this not a constructor when it only needs to be done once?

> +    ACtx = &AC;

It smells a bit like ACtx should be a reference member, otherwise the
pointer may wind up dangling a bit more easily.

> +    CFGraph = AC.getCFG();
> +    if (!CFGraph)
> +      return false;
> +
> +    FDecl = dyn_cast_or_null<NamedDecl>(AC.getDecl());
> +    if (!FDecl) // ignore anonymous functions
> +      return false;
> +
> +    SortedGraph = AC.getAnalysis<PostOrderCFGView>();
> +    if (!SortedGraph)
> +      return false;
> +
> +    return true;
> +  }


> +
> +  // Traverse the CFG, calling methods on V as appropriate.
> +  template <class Visitor>
> +  void walk(Visitor &V) {
> +    PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph);
> +
> +    V.enterCFG(CFGraph, FDecl, &CFGraph->getEntry());
> +
> +    for (const CFGBlock* CurrBlock : *SortedGraph) {
> +      VisitedBlocks.insert(CurrBlock);
> +
> +      V.enterCFGBlock(CurrBlock);
> +
> +      // Process statements
> +      for (CFGBlock::const_iterator BI = CurrBlock->begin(),
> +                                    BE = CurrBlock->end();
> +           BI != BE; ++BI) {

Range-based for loop?

> +        switch (BI->getKind()) {
> +        case CFGElement::Statement: {
> +          V.handleStatement(BI->castAs<CFGStmt>().getStmt());
> +          break;
> +        }
> +        case CFGElement::AutomaticObjectDtor: {
> +          CFGAutomaticObjDtor AD = BI->castAs<CFGAutomaticObjDtor>();
> +          CXXDestructorDecl *DD = const_cast<CXXDestructorDecl*>(
> +              AD.getDestructorDecl(ACtx->getASTContext()));
> +          VarDecl *VD = const_cast<VarDecl*>(AD.getVarDecl());

Getting rid of these const_casts would be wonderful, if possible.

> +          V.handleDestructorCall(VD, DD);
> +          break;
> +        }
> +        default:
> +          break;
> +        }
> +      }
> +
> +      // Process successors
> +      for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
> +                                         SE = CurrBlock->succ_end();
> +           SI != SE; ++SI) {
> +        if (*SI == 0)
> +          continue;
> +
> +        if (VisitedBlocks.alreadySet(*SI)) {
> +          V.handleSuccessorBackEdge(*SI);
> +          continue;
> +        }
> +        V.handleSuccessor(*SI);
> +      }
> +
> +      V.exitCFGBlock(CurrBlock);
> +    }
> +    V.exitCFG(&CFGraph->getExit());
> +  }
> +
> +public:
> +  CFG *CFGraph;
> +  const NamedDecl *FDecl;
> +  AnalysisDeclContext *ACtx;
> +  PostOrderCFGView *SortedGraph;

Why are these all public?

> +};
> +
> +
> +// Translate clang::Expr to til::SExpr.
> +class SExprBuilder {
> +public:
> +  typedef llvm::DenseMap<const Stmt*, til::Variable*> StatementMap;
> +
> +  /// \brief Encapsulates the lexical context of a function call.  The lexical
> +  /// context includes the arguments to the call, including the implicit object
> +  /// argument.  When an attribute containing a mutex expression is attached to
> +  /// a method, the expression may refer to formal parameters of the method.
> +  /// Actual arguments must be substituted for formal parameters to derive
> +  /// the appropriate mutex expression in the lexical context where the function
> +  /// is called.  PrevCtx holds the context in which the arguments themselves
> +  /// should be evaluated; multiple calling contexts can be chained together
> +  /// by the lock_returned attribute.
> +  struct CallingContext {
> +    const NamedDecl *AttrDecl;  // The decl to which the attr is attached.
> +    const Expr *SelfArg;        // Implicit object argument -- e.g. 'this'
> +    unsigned NumArgs;           // Number of funArgs
> +    const Expr *const *FunArgs; // Function arguments
> +    CallingContext *Prev;       // The previous context; or 0 if none.
> +    bool SelfArrow;             // is Self referred to with -> or .?
> +
> +    CallingContext(const NamedDecl *D = 0, const Expr *S = 0, unsigned N = 0,
> +                   const Expr *const *A = 0, CallingContext *P = 0)
> +        : AttrDecl(D), SelfArg(S), NumArgs(N), FunArgs(A), Prev(P),
> +          SelfArrow(false)
> +    {}
> +  };
> +
> +  til::SExpr *lookupStmt(const Stmt *S);
> +  void insertStmt(const Stmt *S, til::Variable *V);
> +
> +  // Translate a clang statement or expression to a TIL expression.
> +  // Also performs substitution of variables; Ctx provides the context.
> +  // Dispatches on the type of S.
> +  til::SExpr *translate(const Stmt *S, CallingContext *Ctx);
> +
> +
> +  til::SExpr *translateDeclRefExpr(const DeclRefExpr *DRE,
> +                                   CallingContext *Ctx) ;
> +  til::SExpr *translateCXXThisExpr(const CXXThisExpr *TE, CallingContext *Ctx);
> +  til::SExpr *translateMemberExpr(const MemberExpr *ME, CallingContext *Ctx);
> +  til::SExpr *translateCallExpr(const CallExpr *CE, CallingContext *Ctx);
> +  til::SExpr *translateCXXMemberCallExpr(const CXXMemberCallExpr *ME,
> +                                         CallingContext *Ctx);
> +  til::SExpr *translateCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE,
> +                                           CallingContext *Ctx);
> +  til::SExpr *translateUnaryOperator(const UnaryOperator *UO,
> +                                     CallingContext *Ctx);
> +  til::SExpr *translateBinaryOperator(const BinaryOperator *BO,
> +                                      CallingContext *Ctx);
> +  til::SExpr *translateCastExpr(const CastExpr *CE, CallingContext *Ctx);
> +  til::SExpr *translateArraySubscriptExpr(const ArraySubscriptExpr *E,
> +                                          CallingContext *Ctx);
> +  til::SExpr *translateConditionalOperator(const ConditionalOperator *C,
> +                                           CallingContext *Ctx);
> +  til::SExpr *translateBinaryConditionalOperator(
> +      const BinaryConditionalOperator *C, CallingContext *Ctx);

It seems like a lot of these methods shouldn't be public.

> +
> +
> +  SExprBuilder(til::MemRegionRef A, StatementMap *SM = 0)
> +      : Arena(A), SMap(SM), SelfVar(0) {
> +    // FIXME: we don't always have a self-variable.
> +    SelfVar = new (Arena) til::Variable(til::Variable::VK_SFun);
> +  }
> +
> +protected:

Why protected?

> +  til::MemRegionRef Arena;
> +  StatementMap *SMap;       // Map from Stmt to TIL Variables
> +  til::Variable *SelfVar;   // Variable to use for 'this'
> +};
> +
> +
> +// Dump an SCFG to llvm::errs().
> +void printSCFG(CFGWalker &walker);

This seems like it'd be more reasonable as a dump() method on
CFGWalker than a stand-alone function.

> +
> +
> +} // end namespace threadSafety
> +
> +} // end namespace clang
>
> Added: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyOps.def
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyOps.def?rev=205728&view=auto
> ==============================================================================
> --- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyOps.def (added)
> +++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyOps.def Mon Apr  7 13:09:54 2014
> @@ -0,0 +1,44 @@
> +//===- ThreadSafetyTIL.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 the list of core opcodes for the Thread Safety
> +// Typed Intermediate language.  Please see ThreadSafetyTIL.h for more
> +// information.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +
> +TIL_OPCODE_DEF(Future)
> +TIL_OPCODE_DEF(Undefined)
> +TIL_OPCODE_DEF(Wildcard)
> +
> +TIL_OPCODE_DEF(Literal)
> +TIL_OPCODE_DEF(LiteralPtr)
> +TIL_OPCODE_DEF(Variable)
> +TIL_OPCODE_DEF(Function)
> +TIL_OPCODE_DEF(SFunction)
> +TIL_OPCODE_DEF(Code)
> +
> +TIL_OPCODE_DEF(Apply)
> +TIL_OPCODE_DEF(SApply)
> +TIL_OPCODE_DEF(Project)
> +
> +TIL_OPCODE_DEF(Call)
> +TIL_OPCODE_DEF(Alloc)
> +TIL_OPCODE_DEF(Load)
> +TIL_OPCODE_DEF(Store)
> +
> +TIL_OPCODE_DEF(UnaryOp)
> +TIL_OPCODE_DEF(BinaryOp)
> +TIL_OPCODE_DEF(Cast)
> +
> +TIL_OPCODE_DEF(SCFG)
> +TIL_OPCODE_DEF(Phi)
> +TIL_OPCODE_DEF(Goto)
> +TIL_OPCODE_DEF(Branch)
>
> Added: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h?rev=205728&view=auto
> ==============================================================================
> --- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h (added)
> +++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h Mon Apr  7 13:09:54 2014

Everything in this file is in the til namespace, yet it has an odd
mixture of naming conventions used. Eg) til::TILPrettyPrinter, vs
til::TIL_Opcode vs til::ThreadSafetyTIL -- I think all of the
capitalized TILs should likely be dropped as the namespace should
suffice.

> @@ -0,0 +1,1831 @@
> +//===- ThreadSafetyTIL.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 simple intermediate language that is used by the
> +// thread safety analysis (See ThreadSafety.cpp).  The thread safety analysis
> +// works by comparing mutex expressions, e.g.
> +//
> +// class A { Mutex mu; int dat GUARDED_BY(this->mu); }
> +// class B { A a; }
> +//
> +// void foo(B* b) {
> +//   (*b).a.mu.lock();     // locks (*b).a.mu
> +//   b->a.dat = 0;         // substitute &b->a for 'this';
> +//                         // requires lock on (&b->a)->mu
> +//   (b->a.mu).unlock();   // unlocks (b->a.mu)
> +// }
> +//
> +// As illustrated by the above example, clang Exprs are not well-suited to
> +// represent mutex expressions directly, since there is no easy way to compare
> +// Exprs for equivalence.  The thread safety analysis thus lowers clang Exprs
> +// into a simple intermediate language (IL).  The IL supports:
> +//
> +// (1) comparisons for semantic equality of expressions
> +// (2) SSA renaming of variables
> +// (3) wildcards and pattern matching over expressions
> +// (4) hash-based expression lookup
> +//
> +// The IL is currently very experimental, is intended only for use within
> +// the thread safety analysis, and is subject to change without notice.
> +// After the API stabilizes and matures, it may be appropriate to make this
> +// more generally available to other analyses.
> +//
> +// UNDER CONSTRUCTION.  USE AT YOUR OWN RISK.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_CLANG_THREAD_SAFETY_TIL_H
> +#define LLVM_CLANG_THREAD_SAFETY_TIL_H
> +
> +#include "clang/AST/DeclCXX.h"
> +#include "clang/AST/ExprCXX.h"
> +#include "clang/AST/StmtCXX.h"
> +#include "clang/AST/Type.h"
> +#include "llvm/ADT/StringRef.h"
> +#include "llvm/Support/AlignOf.h"
> +#include "llvm/Support/Allocator.h"
> +
> +#include <cassert>
> +#include <cstddef>

Can any of these be forward declares as well?

> +
> +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(0) {}
> +  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.

Can an existing container class suffice? I'm not keen on adding
another container data type, much less exposing it like this.

> +template <class T> class SimpleArray {
> +public:
> +  SimpleArray() : Data(0), 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, bool Steal)
> +      : Data(A.Data), Size(A.Size), Capacity(A.Capacity) {
> +    A.Data = 0;
> +    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:
> +  T *Data;
> +  size_t Size;
> +  size_t Capacity;
> +};
> +
> +
> +enum TIL_Opcode {
> +#define TIL_OPCODE_DEF(X) COP_##X,
> +#include "clang/Analysis/Analyses/ThreadSafetyOps.def"
> +#undef TIL_OPCODE_DEF
> +  COP_MAX
> +};
> +
> +
> +typedef clang::BinaryOperatorKind TIL_BinaryOpcode;
> +typedef clang::UnaryOperatorKind TIL_UnaryOpcode;
> +typedef clang::CastKind TIL_CastOpcode;
> +
> +
> +enum TIL_TraversalKind {
> +  TRV_Normal,
> +  TRV_Lazy, // subexpression may need to be traversed lazily
> +  TRV_Tail  // subexpression occurs in a tail position
> +};
> +
> +
> +// Base class for AST nodes in the typed intermediate language.
> +class SExpr {
> +public:
> +  TIL_Opcode opcode() const { return static_cast<TIL_Opcode>(Opcode); }
> +
> +  // Subclasses of SExpr must define the following:
> +  //
> +  // This(const This& E, ...) {
> +  //   copy constructor: construct copy of E, with some additional arguments.
> +  // }
> +  //
> +  // template <class V> typename V::R_SExpr traverse(V &Visitor) {
> +  //   traverse all subexpressions, following the traversal/rewriter interface
> +  // }
> +  //
> +  // template <class C> typename C::CType compare(CType* E, C& Cmp) {
> +  //   compare all subexpressions, following the comparator interface
> +  // }
> +
> +protected:
> +  SExpr(TIL_Opcode Op) : Opcode(Op), Reserved(0), Flags(0) {}
> +  SExpr(const SExpr &E) : Opcode(E.Opcode), Reserved(0), Flags(E.Flags) {}

You're kind of missing a virtual destructor here. Future inherits from
SExpr and exposes virtual functions, so polymorphic deletion of a
Future through a static type of SExpr would be problematic.

> +
> +  const unsigned char Opcode;
> +  unsigned char Reserved;
> +  unsigned short Flags;
> +
> +private:
> +  SExpr();
> +};
> +
> +typedef SExpr* SExprRef;

This isn't a typical pattern used in the code base, and it makes it
harder to write const-correct code.

> +
> +
> +// Contains various helper functions for SExprs.
> +class ThreadSafetyTIL {
> +public:
> +  static const int MaxOpcode = COP_MAX;
> +
> +  static inline bool isTrivial(SExpr *E) {
> +    unsigned Op = E->opcode();
> +    return Op == COP_Variable || Op == COP_Literal;
> +  }
> +
> +  static inline bool isLargeValue(SExpr *E) {
> +    unsigned Op = E->opcode();
> +    return (Op >= COP_Function && Op <= COP_Code);
> +  }
> +};
> +
> +
> +// Placeholder for an expression that has not yet been created.
> +// Used to implement lazy copy and rewriting strategies.
> +class Future : public SExpr {
> +public:
> +  static bool classof(const SExpr *E) { return E->opcode() == COP_Future; }
> +
> +  enum FutureStatus {
> +    FS_pending,
> +    FS_evaluating,
> +    FS_done
> +  };
> +
> +  Future() : SExpr(COP_Future), Status(FS_pending), Result(0), Location(0) {}
> +  virtual ~Future() {}
> +
> +  // Registers the location in the AST where this future is stored.
> +  // Forcing the future will automatically update the AST.
> +  static inline void registerLocation(SExpr **Member) {
> +    if (Future *F = dyn_cast_or_null<Future>(*Member))
> +      F->Location = Member;
> +  }
> +
> +  // A lazy rewriting strategy should subclass Future and override this method.
> +  virtual SExpr *create() { return 0; }

nullptr instead of 0?

> +
> +  // Return the result of this future if it exists, otherwise return null.
> +  SExpr *maybeGetResult() {
> +    return Result;
> +  }
> +
> +  // Return the result of this future; forcing it if necessary.
> +  SExpr *result() {
> +    switch (Status) {
> +    case FS_pending:
> +      force();
> +      return Result;
> +    case FS_evaluating:
> +      return 0; // infinite loop; illegal recursion.

nullptr, and should probably assert.

> +    case FS_done:
> +      return Result;
> +    }
> +  }
> +
> +  template <class V> typename V::R_SExpr traverse(V &Visitor) {
> +    assert(Result && "Cannot traverse Future that has not been forced.");
> +    return Visitor.traverse(Result);
> +  }
> +
> +  template <class C> typename C::CType compare(Future* E, C& Cmp) {
> +    if (!Result || !E->Result)
> +      return Cmp.comparePointers(this, E);
> +    return Cmp.compare(Result, E->Result);
> +  }
> +
> +private:
> +  // Force the future.
> +  void force() {
> +    Status = FS_evaluating;
> +    SExpr *R = create();
> +    Result = R;
> +    if (Location) {
> +      *Location = R;
> +    }
> +    Status = FS_done;
> +  }
> +
> +  FutureStatus Status;
> +  SExpr *Result;
> +  SExpr **Location;
> +};
> +
> +
> +// Placeholder for C++ expressions that cannot be represented in the TIL.
> +class Undefined : public SExpr {
> +public:
> +  static bool classof(const SExpr *E) { return E->opcode() == COP_Undefined; }
> +
> +  Undefined(const clang::Stmt *S = 0) : SExpr(COP_Undefined), Cstmt(S) {}
> +  Undefined(const Undefined &U) : SExpr(U), Cstmt(U.Cstmt) {}
> +
> +  template <class V> typename V::R_SExpr traverse(V &Visitor) {
> +    return Visitor.reduceUndefined(*this);
> +  }
> +
> +  template <class C> typename C::CType compare(Undefined* E, C& Cmp) {
> +    return Cmp.comparePointers(Cstmt, E->Cstmt);
> +  }
> +
> +private:
> +  const clang::Stmt *Cstmt;
> +};
> +
> +
> +// Placeholder for a wildcard that matches any other expression.
> +class Wildcard : public SExpr {
> +public:
> +  static bool classof(const SExpr *E) { return E->opcode() == COP_Wildcard; }
> +
> +  Wildcard() : SExpr(COP_Wildcard) {}
> +  Wildcard(const Wildcard &W) : SExpr(W) {}
> +
> +  template <class V> typename V::R_SExpr traverse(V &Visitor) {
> +    return Visitor.reduceWildcard(*this);
> +  }
> +
> +  template <class C> typename C::CType compare(Wildcard* E, C& Cmp) {
> +    return Cmp.trueResult();
> +  }
> +};
> +
> +
> +// Base class for literal values.
> +class Literal : public SExpr {
> +public:
> +  static bool classof(const SExpr *E) { return E->opcode() == COP_Literal; }
> +
> +  Literal(const clang::Expr *C) : SExpr(COP_Literal), Cexpr(C) {}
> +  Literal(const Literal &L) : SExpr(L), Cexpr(L.Cexpr) {}
> +
> +  // The clang expression for this literal.
> +  const clang::Expr *clangExpr() { return Cexpr; }

expr() instead of clangExpr()? A bit of a bikeshed, but the name is
just kind of odd to me.

> +
> +  template <class V> typename V::R_SExpr traverse(V &Visitor) {
> +    return Visitor.reduceLiteral(*this);
> +  }
> +
> +  template <class C> typename C::CType compare(Literal* E, C& Cmp) {
> +    // TODO -- use value, not pointer equality
> +    return Cmp.comparePointers(Cexpr, E->Cexpr);
> +  }
> +
> +private:
> +  const clang::Expr *Cexpr;
> +};
> +
> +
> +// Literal pointer to an object allocated in memory.
> +// At compile time, pointer literals are represented by symbolic names.
> +class LiteralPtr : public SExpr {
> +public:
> +  static bool classof(const SExpr *E) { return E->opcode() == COP_LiteralPtr; }
> +
> +  LiteralPtr(const clang::ValueDecl *D) : SExpr(COP_LiteralPtr), Cvdecl(D) {}
> +  LiteralPtr(const LiteralPtr &R) : SExpr(R), Cvdecl(R.Cvdecl) {}
> +
> +  // The clang declaration for the value that this pointer points to.
> +  const clang::ValueDecl *clangDecl() { return Cvdecl; }

decl() instead of clangDecl() for the same reasoning as above?

> +
> +  template <class V> typename V::R_SExpr traverse(V &Visitor) {
> +    return Visitor.reduceLiteralPtr(*this);
> +  }
> +
> +  template <class C> typename C::CType compare(LiteralPtr* E, C& Cmp) {
> +    return Cmp.comparePointers(Cvdecl, E->Cvdecl);
> +  }
> +
> +private:
> +  const clang::ValueDecl *Cvdecl;
> +};
> +
> +
> +// A named variable, e.g. "x".
> +//
> +// There are two distinct places in which a Variable can appear in the AST.
> +// A variable declaration introduces a new variable, and can occur in 3 places:
> +//   Let-expressions:           (Let (x = t) u)
> +//   Functions:                 (Function (x : t) u)
> +//   Self-applicable functions  (SFunction (x) t)
> +//
> +// If a variable occurs in any other location, it is a reference to an existing
> +// variable declaration -- e.g. 'x' in (x * y + z). To save space, we don't
> +// allocate a separate AST node for variable references; a reference is just a
> +// pointer to the original declaration.
> +class Variable : public SExpr {
> +public:
> +  static bool classof(const SExpr *E) { return E->opcode() == COP_Variable; }
> +
> +  // Let-variable, function parameter, or self-variable
> +  enum VariableKind {
> +    VK_Let,
> +    VK_Fun,
> +    VK_SFun
> +  };
> +
> +  Variable(VariableKind K, SExpr *D = 0, const clang::ValueDecl *Cvd = 0)
> +      : SExpr(COP_Variable), Definition(D), Cvdecl(Cvd),
> +        BlockID(0), Id(0),  NumUses(0) {
> +    Flags = K;
> +    Future::registerLocation(&Definition);
> +  }
> +  Variable(const clang::ValueDecl *Cvd, SExpr *D = 0)
> +      : SExpr(COP_Variable), Definition(D), Cvdecl(Cvd),
> +        BlockID(0), Id(0),  NumUses(0) {
> +    Flags = VK_Let;
> +    Future::registerLocation(&Definition);
> +  }
> +  Variable(const Variable &Vd, SExpr *D) // rewrite constructor
> +      : SExpr(Vd), Definition(D), Cvdecl(Vd.Cvdecl),
> +        BlockID(0), Id(0), NumUses(0) {
> +    Flags = Vd.kind();
> +    Future::registerLocation(&Definition);
> +  }
> +
> +  VariableKind kind() const { return static_cast<VariableKind>(Flags); }
> +
> +  StringRef name() const { return Cvdecl ? Cvdecl->getName() : "_x"; }

Why _x?

> +  const clang::ValueDecl *clangDecl() const { return Cvdecl; }

decl() instead of clangDecl?

> +
> +  // Returns the definition (for let vars) or type (for parameter & self vars)
> +  SExpr *definition() const { return Definition; }
> +
> +  void attachVar() const { ++NumUses; }
> +  void detachVar() const { --NumUses; }

Should there be an assert that NumUses >= 0 when detaching (to catch
mismatches)?

> +
> +  unsigned getID() { return Id; }
> +  unsigned getBlockID() { return BlockID; }
> +
> +  void setID(unsigned Bid, unsigned I) {
> +    BlockID = static_cast<unsigned short>(Bid);
> +    Id = static_cast<unsigned short>(I);
> +  }
> +
> +  template <class V> typename V::R_SExpr traverse(V &Visitor) {
> +    // This routine is only called for variable references.
> +    return Visitor.reduceVariableRef(this);
> +  }
> +
> +  template <class C> typename C::CType compare(Variable* E, C& Cmp) {
> +    return Cmp.compareVariableRefs(this, E);
> +  }
> +
> +private:
> +  friend class Function;
> +  friend class SFunction;
> +  friend class BasicBlock;
> +
> +  // Function, SFunction, and BasicBlock will reset the kind.
> +  void setKind(VariableKind K) { Flags = K; }
> +
> +  SExpr *Definition;               // The TIL type or definition
> +  const clang::ValueDecl *Cvdecl;  // The clang declaration for this variable.
> +
> +  unsigned short BlockID;
> +  unsigned short Id;
> +  mutable int NumUses;

Seems like NumUses should be unsigned.

> +};
> +
> +
> +// A function -- a.k.a. lambda abstraction.
> +// Functions with multiple arguments are created by currying,
> +// e.g. (function (x: Int) (function (y: Int) (add x y)))
> +class Function : public SExpr {
> +public:
> +  static bool classof(const SExpr *E) { return E->opcode() == COP_Function; }
> +
> +  Function(Variable *Vd, SExpr *Bd)
> +      : SExpr(COP_Function), VarDecl(Vd), Body(Bd) {
> +    Vd->setKind(Variable::VK_Fun);
> +  }
> +  Function(const Function &F, Variable *Vd, SExpr *Bd) // rewrite constructor
> +      : SExpr(F), VarDecl(Vd), Body(Bd) {
> +    Vd->setKind(Variable::VK_Fun);
> +  }
> +
> +  Variable *variableDecl() const { return VarDecl; }
> +  SExpr *body() const { return Body; }
> +
> +  template <class V> typename V::R_SExpr traverse(V &Visitor) {
> +    // This is a variable declaration, so traverse the definition.
> +    typename V::R_SExpr E0 = Visitor.traverse(VarDecl->Definition, TRV_Lazy);
> +    // Tell the rewriter to enter the scope of the function.
> +    Variable *Nvd = Visitor.enterScope(*VarDecl, E0);
> +    typename V::R_SExpr E1 = Visitor.traverse(Body);
> +    Visitor.exitScope(*VarDecl);
> +    return Visitor.reduceFunction(*this, Nvd, E1);
> +  }
> +
> +  template <class C> typename C::CType compare(Function* E, C& Cmp) {
> +    typename C::CType Ct =
> +      Cmp.compare(VarDecl->definition(), E->VarDecl->definition());
> +    if (Cmp.notTrue(Ct))
> +      return Ct;
> +    Cmp.enterScope(VarDecl, E->VarDecl);
> +    Ct = Cmp.compare(Body, E->Body);
> +    Cmp.leaveScope();
> +    return Ct;
> +  }
> +
> +private:
> +  Variable *VarDecl;
> +  SExpr *Body;
> +};
> +
> +
> +// A self-applicable function.
> +// A self-applicable function can be applied to itself.  It's useful for
> +// implementing objects and late binding
> +class SFunction : public SExpr {
> +public:
> +  static bool classof(const SExpr *E) { return E->opcode() == COP_SFunction; }
> +
> +  SFunction(Variable *Vd, SExpr *B)
> +      : SExpr(COP_SFunction), VarDecl(Vd), Body(B) {
> +    assert(Vd->Definition == 0);
> +    Vd->setKind(Variable::VK_SFun);
> +    Vd->Definition = this;
> +  }
> +  SFunction(const SFunction &F, Variable *Vd, SExpr *B) // rewrite constructor
> +      : SExpr(F),
> +        VarDecl(Vd),
> +        Body(B) {
> +    assert(Vd->Definition == 0);
> +    Vd->setKind(Variable::VK_SFun);
> +    Vd->Definition = this;
> +  }
> +
> +  Variable *variableDecl() const { return VarDecl; }
> +  SExpr *body() const { return Body; }
> +
> +  template <class V> typename V::R_SExpr traverse(V &Visitor) {
> +    // A self-variable points to the SFunction itself.
> +    // A rewrite must introduce the variable with a null definition, and update
> +    // it after 'this' has been rewritten.
> +    Variable *Nvd = Visitor.enterScope(*VarDecl, 0 /* def */);
> +    typename V::R_SExpr E1 = Visitor.traverse(Body);
> +    Visitor.exitScope(*VarDecl);
> +    // A rewrite operation will call SFun constructor to set Vvd->Definition.
> +    return Visitor.reduceSFunction(*this, Nvd, E1);
> +  }
> +
> +  template <class C> typename C::CType compare(SFunction* E, C& Cmp) {
> +    Cmp.enterScope(VarDecl, E->VarDecl);
> +    typename C::CType Ct = Cmp.compare(Body, E->Body);
> +    Cmp.leaveScope();
> +    return Ct;
> +  }
> +
> +private:
> +  Variable *VarDecl;
> +  SExpr *Body;
> +};
> +
> +
> +// A block of code -- e.g. the body of a function.
> +class Code : public SExpr {
> +public:
> +  static bool classof(const SExpr *E) { return E->opcode() == COP_Code; }
> +
> +  Code(SExpr *T, SExpr *B) : SExpr(COP_Code), ReturnType(T), Body(B) {
> +    Future::registerLocation(&ReturnType);
> +    Future::registerLocation(&Body);
> +  }
> +  Code(const Code &C, SExpr *T, SExpr *B) // rewrite constructor
> +      : SExpr(C),
> +        ReturnType(T),
> +        Body(B) {
> +    Future::registerLocation(&ReturnType);
> +    Future::registerLocation(&Body);
> +  }
> +
> +  SExpr *returnType() { return ReturnType; }
> +  SExpr *body() { return Body; }
> +
> +  template <class V> typename V::R_SExpr traverse(V &Visitor) {
> +    typename V::R_SExpr Nt = Visitor.traverse(ReturnType, TRV_Lazy);
> +    typename V::R_SExpr Nb = Visitor.traverse(Body, TRV_Lazy);
> +    return Visitor.reduceCode(*this, Nt, Nb);
> +  }
> +
> +  template <class C> typename C::CType compare(Code* E, C& Cmp) {
> +    typename C::CType Ct = Cmp.compare(ReturnType, E->ReturnType);
> +    if (Cmp.notTrue(Ct))
> +      return Ct;
> +    return Cmp.compare(Body, E->Body);
> +  }
> +
> +private:
> +  SExpr *ReturnType;
> +  SExpr *Body;
> +};
> +
> +
> +// Apply an argument to a function
> +class Apply : public SExpr {
> +public:
> +  static bool classof(const SExpr *E) { return E->opcode() == COP_Apply; }
> +
> +  Apply(SExpr *F, SExpr *A) : SExpr(COP_Apply), Fun(F), Arg(A) {}
> +  Apply(const Apply &A, SExpr *F, SExpr *Ar)  // rewrite constructor
> +      : SExpr(A), Fun(F), Arg(Ar)
> +  {}
> +
> +  SExpr *fun() const { return Fun; }
> +  SExpr *arg() const { return Arg; }
> +
> +  template <class V> typename V::R_SExpr traverse(V &Visitor) {
> +    typename V::R_SExpr Nf = Visitor.traverse(Fun);
> +    typename V::R_SExpr Na = Visitor.traverse(Arg);
> +    return Visitor.reduceApply(*this, Nf, Na);
> +  }
> +
> +  template <class C> typename C::CType compare(Apply* E, C& Cmp) {
> +    typename C::CType Ct = Cmp.compare(Fun, E->Fun);
> +    if (Cmp.notTrue(Ct))
> +      return Ct;
> +    return Cmp.compare(Arg, E->Arg);
> +  }
> +
> +private:
> +  SExpr *Fun;
> +  SExpr *Arg;
> +};
> +
> +
> +// Apply a self-argument to a self-applicable function
> +class SApply : public SExpr {
> +public:
> +  static bool classof(const SExpr *E) { return E->opcode() == COP_SApply; }
> +
> +  SApply(SExpr *Sf, SExpr *A = 0) : SExpr(COP_SApply), Sfun(Sf), Arg(A) {}
> +  SApply(SApply &A, SExpr *Sf, SExpr *Ar = 0)  // rewrite constructor
> +      : SExpr(A),  Sfun(Sf), Arg(Ar)
> +  {}
> +
> +  SExpr *sfun() const { return Sfun; }
> +  SExpr *arg() const { return Arg ? Arg : Sfun; }
> +
> +  bool isDelegation() const { return Arg == 0; }
> +
> +  template <class V> typename V::R_SExpr traverse(V &Visitor) {
> +    typename V::R_SExpr Nf = Visitor.traverse(Sfun);
> +    typename V::R_SExpr Na = Arg ? Visitor.traverse(Arg) : 0;
> +    return Visitor.reduceSApply(*this, Nf, Na);
> +  }
> +
> +  template <class C> typename C::CType compare(SApply* E, C& Cmp) {
> +    typename C::CType Ct = Cmp.compare(Sfun, E->Sfun);
> +    if (Cmp.notTrue(Ct) || (!Arg && !E->Arg))
> +      return Ct;
> +    return Cmp.compare(arg(), E->arg());
> +  }
> +
> +private:
> +  SExpr *Sfun;
> +  SExpr *Arg;
> +};
> +
> +
> +// Project a named slot from a C++ struct or class.
> +class Project : public SExpr {
> +public:
> +  static bool classof(const SExpr *E) { return E->opcode() == COP_Project; }
> +
> +  Project(SExpr *R, clang::ValueDecl *Cvd)
> +      : SExpr(COP_Project), Rec(R), Cvdecl(Cvd) {}
> +  Project(const Project &P, SExpr *R) : SExpr(P), Rec(R), Cvdecl(P.Cvdecl) {}
> +
> +  SExpr *record() const { return Rec; }
> +  clang::ValueDecl *clangValueDecl() const { return Cvdecl; }
> +
> +  StringRef slotName() const { return Cvdecl->getName(); }
> +
> +  template <class V> typename V::R_SExpr traverse(V &Visitor) {
> +    typename V::R_SExpr Nr = Visitor.traverse(Rec);
> +    return Visitor.reduceProject(*this, Nr);
> +  }
> +
> +  template <class C> typename C::CType compare(Project* E, C& Cmp) {
> +    typename C::CType Ct = Cmp.compare(Rec, E->Rec);
> +    if (Cmp.notTrue(Ct))
> +      return Ct;
> +    return Cmp.comparePointers(Cvdecl, E->Cvdecl);
> +  }
> +
> +private:
> +  SExpr *Rec;
> +  clang::ValueDecl *Cvdecl;
> +};
> +
> +
> +// Call a function (after all arguments have been applied).
> +class Call : public SExpr {
> +public:
> +  static bool classof(const SExpr *E) { return E->opcode() == COP_Call; }
> +
> +  Call(SExpr *T, const clang::CallExpr *Ce = 0)
> +      : SExpr(COP_Call), Target(T), Cexpr(Ce) {}
> +  Call(const Call &C, SExpr *T) : SExpr(C), Target(T), Cexpr(C.Cexpr) {}
> +
> +  SExpr *target() const { return Target; }
> +  const clang::CallExpr *clangCallExpr() { return Cexpr; }

callExpr() instead of clangCallExpr()?

> +
> +  template <class V> typename V::R_SExpr traverse(V &Visitor) {
> +    typename V::R_SExpr Nt = Visitor.traverse(Target);
> +    return Visitor.reduceCall(*this, Nt);
> +  }
> +
> +  template <class C> typename C::CType compare(Call* E, C& Cmp) {
> +    return Cmp.compare(Target, E->Target);
> +  }
> +
> +private:
> +  SExpr *Target;
> +  const clang::CallExpr *Cexpr;
> +};
> +
> +
> +// Allocate memory for a new value on the heap or stack.
> +class Alloc : public SExpr {
> +public:
> +  static bool classof(const SExpr *E) { return E->opcode() == COP_Call; }
> +
> +  enum AllocKind {
> +    AK_Stack,
> +    AK_Heap
> +  };
> +
> +  Alloc(SExpr* D, AllocKind K) : SExpr(COP_Alloc), Dtype(D) {
> +    Flags = K;
> +  }
> +  Alloc(const Alloc &A, SExpr* Dt) : SExpr(A), Dtype(Dt) {
> +    Flags = A.kind();
> +  }
> +
> +  AllocKind kind() const { return static_cast<AllocKind>(Flags); }
> +  SExpr*    dataType() const { return Dtype; }
> +
> +  template <class V> typename V::R_SExpr traverse(V &Visitor) {
> +    typename V::R_SExpr Nd = Visitor.traverse(Dtype);
> +    return Visitor.reduceAlloc(*this, Nd);
> +  }
> +
> +  template <class C> typename C::CType compare(Alloc* E, C& Cmp) {
> +    typename C::CType Ct = Cmp.compareIntegers(kind(), E->kind());
> +    if (Cmp.notTrue(Ct))
> +      return Ct;
> +    return Cmp.compare(Dtype, E->Dtype);
> +  }
> +
> +private:
> +  SExpr* Dtype;
> +};
> +
> +
> +// Load a value from memory.
> +class Load : public SExpr {
> +public:
> +  static bool classof(const SExpr *E) { return E->opcode() == COP_Load; }
> +
> +  Load(SExpr *P) : SExpr(COP_Load), Ptr(P) {}
> +  Load(const Load &L, SExpr *P) : SExpr(L), Ptr(P) {}
> +
> +  SExpr *pointer() { return Ptr; }
> +
> +  template <class V> typename V::R_SExpr traverse(V &Visitor) {
> +    typename V::R_SExpr Np = Visitor.traverse(Ptr);
> +    return Visitor.reduceLoad(*this, Np);
> +  }
> +
> +  template <class C> typename C::CType compare(Load* E, C& Cmp) {
> +    return Cmp.compare(Ptr, E->Ptr);
> +  }
> +
> +private:
> +  SExpr *Ptr;
> +};
> +
> +
> +// Store a value to memory.
> +class Store : public SExpr {
> +public:
> +  static bool classof(const SExpr *E) { return E->opcode() == COP_Store; }
> +
> +  Store(SExpr *P, SExpr *V) : SExpr(COP_Store), Ptr(P) {}
> +  Store(const Store &S, SExpr *P, SExpr *V) : SExpr(S), Ptr(P) {}
> +
> +  SExpr *pointer() const { return Ptr; }
> +  SExpr *value() const { return Value; }
> +
> +  template <class V> typename V::R_SExpr traverse(V &Visitor) {
> +    typename V::R_SExpr Np = Visitor.traverse(Ptr);
> +    typename V::R_SExpr Nv = Visitor.traverse(Value);
> +    return Visitor.reduceStore(*this, Np, Nv);
> +  }
> +
> +  template <class C> typename C::CType compare(Store* E, C& Cmp) {
> +    typename C::CType Ct = Cmp.compare(Ptr, E->Ptr);
> +    if (Cmp.notTrue(Ct))
> +      return Ct;
> +    return Cmp.compare(Value, E->Value);
> +  }
> +
> +  SExpr *Ptr;
> +  SExpr *Value;
> +};
> +
> +
> +// Simple unary operation -- e.g. !, ~, etc.
> +class UnaryOp : public SExpr {
> +public:
> +  static bool classof(const SExpr *E) { return E->opcode() == COP_UnaryOp; }
> +
> +  UnaryOp(TIL_UnaryOpcode Op, SExpr *E) : SExpr(COP_UnaryOp), Expr0(E) {
> +    Flags = Op;
> +  }
> +  UnaryOp(const UnaryOp &U, SExpr *E) : SExpr(U) { Flags = U.Flags; }
> +
> +  TIL_UnaryOpcode unaryOpcode() { return static_cast<TIL_UnaryOpcode>(Flags); }
> +
> +  SExpr *expr() const { return Expr0; }
> +
> +  template <class V> typename V::R_SExpr traverse(V &Visitor) {
> +    typename V::R_SExpr Ne = Visitor.traverse(Expr0);
> +    return Visitor.reduceUnaryOp(*this, Ne);
> +  }
> +
> +  template <class C> typename C::CType compare(UnaryOp* E, C& Cmp) {
> +    typename C::CType Ct =
> +      Cmp.compareIntegers(unaryOpcode(), E->unaryOpcode());
> +    if (Cmp.notTrue(Ct))
> +      return Ct;
> +    return Cmp.compare(Expr0, E->Expr0);
> +  }
> +
> +private:
> +  SExpr *Expr0;
> +};
> +
> +
> +// Simple binary operation -- e.g. +, -, etc.
> +class BinaryOp : public SExpr {
> +public:
> +  static bool classof(const SExpr *E) { return E->opcode() == COP_BinaryOp; }
> +
> +  BinaryOp(TIL_BinaryOpcode Op, SExpr *E0, SExpr *E1)
> +      : SExpr(COP_BinaryOp), Expr0(E0), Expr1(E1) {
> +    Flags = Op;
> +  }
> +  BinaryOp(const BinaryOp &B, SExpr *E0, SExpr *E1)
> +      : SExpr(B), Expr0(E0), Expr1(E1) {
> +    Flags = B.Flags;
> +  }
> +
> +  TIL_BinaryOpcode binaryOpcode() {
> +    return static_cast<TIL_BinaryOpcode>(Flags);
> +  }
> +
> +  SExpr *expr0() const { return Expr0; }
> +  SExpr *expr1() const { return Expr1; }
> +
> +  template <class V> typename V::R_SExpr traverse(V &Visitor) {
> +    typename V::R_SExpr Ne0 = Visitor.traverse(Expr0);
> +    typename V::R_SExpr Ne1 = Visitor.traverse(Expr1);
> +    return Visitor.reduceBinaryOp(*this, Ne0, Ne1);
> +  }
> +
> +  template <class C> typename C::CType compare(BinaryOp* E, C& Cmp) {
> +    typename C::CType Ct =
> +      Cmp.compareIntegers(binaryOpcode(), E->binaryOpcode());
> +    if (Cmp.notTrue(Ct))
> +      return Ct;
> +    Ct = Cmp.compare(Expr0, E->Expr0);
> +    if (Cmp.notTrue(Ct))
> +      return Ct;
> +    return Cmp.compare(Expr1, E->Expr1);
> +  }
> +
> +private:
> +  SExpr *Expr0;
> +  SExpr *Expr1;
> +};
> +
> +
> +// Cast expression
> +class Cast : public SExpr {
> +public:
> +  static bool classof(const SExpr *E) { return E->opcode() == COP_Cast; }
> +
> +  Cast(TIL_CastOpcode Op, SExpr *E) : SExpr(COP_Cast), Expr0(E) { Flags = Op; }
> +  Cast(const Cast &C, SExpr *E) : SExpr(C), Expr0(E) { Flags = C.Flags; }
> +
> +  TIL_BinaryOpcode castOpcode() { return static_cast<TIL_BinaryOpcode>(Flags); }
> +
> +  SExpr *expr() const { return Expr0; }
> +
> +  template <class V> typename V::R_SExpr traverse(V &Visitor) {
> +    typename V::R_SExpr Ne = Visitor.traverse(Expr0);
> +    return Visitor.reduceCast(*this, Ne);
> +  }
> +
> +  template <class C> typename C::CType compare(Cast* E, C& Cmp) {
> +    typename C::CType Ct =
> +      Cmp.compareIntegers(castOpcode(), E->castOpcode());
> +    if (Cmp.notTrue(Ct))
> +      return Ct;
> +    return Cmp.compare(Expr0, E->Expr0);
> +  }
> +
> +private:
> +  SExpr *Expr0;
> +};
> +
> +
> +
> +
> +class BasicBlock;
> +
> +
> +// An SCFG is a control-flow graph.  It consists of a set of basic blocks, each
> +// of which terminates in a branch to another basic block.  There is one
> +// entry point, and one exit point.
> +class SCFG : public SExpr {
> +public:
> +  typedef SimpleArray<BasicBlock*> BlockArray;
> +
> +  static bool classof(const SExpr *E) { return E->opcode() == COP_SCFG; }
> +
> +  SCFG(MemRegionRef A, unsigned Nblocks)
> +      : SExpr(COP_SCFG), Blocks(A, Nblocks), Entry(0), Exit(0) {}
> +  SCFG(const SCFG &Cfg, BlockArray &Ba) // steals memory from ba

I would really rather not see a constructor which steals memory from
something else -- could it be a factory function instead, so it's at
least a little more readily apparent to callers?

> +      : SExpr(COP_SCFG),
> +        Blocks(Ba, true),
> +        Entry(0),
> +        Exit(0) { /* TODO: set entry and exit! */
> +  }
> +
> +  typedef BlockArray::iterator iterator;
> +  typedef BlockArray::const_iterator const_iterator;
> +
> +  iterator begin() { return Blocks.begin(); }
> +  iterator end() { return Blocks.end(); }
> +
> +  const_iterator cbegin() const { return Blocks.cbegin(); }
> +  const_iterator cend() const { return Blocks.cend(); }
> +
> +  BasicBlock *entry() const { return Entry; }
> +  BasicBlock *exit() const { return Exit; }
> +
> +  void add(BasicBlock *BB) { Blocks.push_back(BB); }
> +  void setEntry(BasicBlock *BB) { Entry = BB; }
> +  void setExit(BasicBlock *BB) { Exit = BB; }
> +
> +  template <class V> typename V::R_SExpr traverse(V &Visitor);
> +
> +  template <class C> typename C::CType compare(SCFG* E, C& Cmp) {
> +    // TODO -- implement CFG comparisons
> +    return Cmp.comparePointers(this, E);
> +  }
> +
> +private:
> +  BlockArray Blocks;
> +  BasicBlock *Entry;
> +  BasicBlock *Exit;
> +};
> +
> +
> +// A basic block is part of an SCFG, and can be treated as a function in
> +// continuation passing style.  It consists of a sequence of phi nodes, which
> +// are "arguments" to the function, followed by a sequence of instructions.
> +// Both arguments and instructions define new variables.  It ends with a
> +// branch or goto to another basic block in the same SCFG.
> +class BasicBlock {
> +public:
> +  typedef SimpleArray<Variable*> VarArray;
> +
> +  BasicBlock(MemRegionRef A, unsigned Nargs, unsigned Nins, SExpr *Term = 0)
> +      : BlockID(0), Parent(0), Args(A, Nargs), Instrs(A, Nins),
> +        Terminator(Term) {}
> +  BasicBlock(const BasicBlock &B, VarArray &As, VarArray &Is, SExpr *T)
> +      : BlockID(0), Parent(0), Args(As, true), Instrs(Is, true), Terminator(T)
> +  {}
> +
> +  unsigned blockID() const { return BlockID; }
> +  BasicBlock *parent() const { return Parent; }
> +
> +  const VarArray &arguments() const { return Args; }
> +  VarArray &arguments() { return Args; }
> +
> +  const VarArray &instructions() const { return Instrs; }
> +  VarArray &instructions() { return Instrs; }
> +
> +  const SExpr *terminator() const { return Terminator; }
> +  SExpr *terminator() { return Terminator; }
> +
> +  void setParent(BasicBlock *P) { Parent = P; }
> +  void setBlockID(unsigned i) { BlockID = i; }
> +  void setTerminator(SExpr *E) { Terminator = E; }
> +  void addArgument(Variable *V) { Args.push_back(V); }
> +  void addInstr(Variable *V) { Args.push_back(V); }
> +
> +  template <class V> BasicBlock *traverse(V &Visitor) {
> +    typename V::template Container<Variable*> Nas(Visitor, Args.size());
> +    typename V::template Container<Variable*> Nis(Visitor, Instrs.size());
> +
> +    for (unsigned I = 0; I < Args.size(); ++I) {

Range-based for loop?

> +      typename V::R_SExpr Ne = Visitor.traverse(Args[I]->Definition);
> +      Variable *Nvd = Visitor.enterScope(*Args[I], Ne);
> +      Nas.push_back(Nvd);
> +    }
> +    for (unsigned J = 0; J < Instrs.size(); ++J) {

Same here.

> +      typename V::R_SExpr Ne = Visitor.traverse(Instrs[J]->Definition);
> +      Variable *Nvd = Visitor.enterScope(*Instrs[J], Ne);
> +      Nis.push_back(Nvd);
> +    }
> +    typename V::R_SExpr Nt = Visitor.traverse(Terminator);
> +
> +    for (unsigned J = 0, JN = Instrs.size(); J < JN; ++J)
> +      Visitor.exitScope(*Instrs[JN-J]);
> +    for (unsigned I = 0, IN = Instrs.size(); I < IN; ++I)
> +      Visitor.exitScope(*Args[IN-I]);

This would be more clear with reverse iterators (until we get a
reverse range adapter).

> +
> +    return Visitor.reduceBasicBlock(*this, Nas, Nis, Nt);
> +  }
> +
> +  template <class C> typename C::CType compare(BasicBlock* E, C& Cmp) {
> +    // TODO -- implement CFG comparisons
> +    return Cmp.comparePointers(this, E);
> +  }
> +
> +private:
> +  friend class SCFG;
> +
> +  unsigned BlockID;
> +  BasicBlock *Parent;   // The parent block is the enclosing lexical scope.
> +                        // The parent dominates this block.
> +  VarArray Args;        // Phi nodes
> +  VarArray Instrs;
> +  SExpr *Terminator;
> +};
> +
> +
> +template <class V>
> +typename V::R_SExpr SCFG::traverse(V &Visitor) {
> +  Visitor.enterCFG(*this);
> +  typename V::template Container<BasicBlock *> Bbs(Visitor, Blocks.size());
> +  for (unsigned I = 0; I < Blocks.size(); ++I) {

Range-based for loop

> +    BasicBlock *Nbb = Blocks[I]->traverse(Visitor);
> +    Bbs.push_back(Nbb);
> +  }
> +  Visitor.exitCFG(*this);
> +  return Visitor.reduceSCFG(*this, Bbs);
> +}
> +
> +
> +
> +class Phi : public SExpr {
> +public:
> +  typedef SimpleArray<SExpr *> ValArray;
> +
> +  static bool classof(const SExpr *E) { return E->opcode() == COP_Phi; }
> +
> +  Phi(MemRegionRef A, unsigned Nvals) : SExpr(COP_Phi), Values(A, Nvals) {}
> +  Phi(const Phi &P, ValArray &Vs)  // steals memory of vs
> +      : SExpr(COP_Phi), Values(Vs, true) {}

Still worried about memory theft...

> +
> +  const ValArray &values() const { return Values; }
> +  ValArray &values() { return Values; }
> +
> +  template <class V> typename V::R_SExpr traverse(V &Visitor) {
> +    typename V::template Container<typename V::R_SExpr> Nvs(Visitor,
> +                                                            Values.size());
> +    for (ValArray::iterator I = Values.begin(), E = Values.end(); I != E; ++I) {
> +      typename V::R_SExpr Nv = Visitor.traverse(*I);
> +      Nvs.push_back(Nv);
> +    }
> +    return Visitor.reducePhi(*this, Nvs);
> +  }
> +
> +  template <class C> typename C::CType compare(Phi* E, C& Cmp) {
> +    // TODO -- implement CFG comparisons
> +    return Cmp.comparePointers(this, E);
> +  }
> +
> +private:
> +  ValArray Values;
> +};
> +
> +
> +class Goto : public SExpr {
> +public:
> +  static bool classof(const SExpr *E) { return E->opcode() == COP_Goto; }
> +
> +  Goto(BasicBlock *B, unsigned Index)
> +      : SExpr(COP_Goto), TargetBlock(B) {}
> +  Goto(const Goto &G, BasicBlock *B, unsigned Index)
> +      : SExpr(COP_Goto), TargetBlock(B) {}
> +
> +  BasicBlock *targetBlock() const { return TargetBlock; }
> +  unsigned index() const { return Index; }
> +
> +  template <class V> typename V::R_SExpr traverse(V &Visitor) {
> +    // TODO -- rewrite indices properly
> +    BasicBlock *Ntb = Visitor.reduceBasicBlockRef(TargetBlock);
> +    return Visitor.reduceGoto(*this, Ntb, Index);
> +  }
> +
> +  template <class C> typename C::CType compare(Goto* E, C& Cmp) {
> +    // TODO -- implement CFG comparisons
> +    return Cmp.comparePointers(this, E);
> +  }
> +
> +private:
> +  BasicBlock *TargetBlock;
> +  unsigned Index;   // Index into Phi nodes of target block.
> +};
> +
> +
> +class Branch : public SExpr {
> +public:
> +  static bool classof(const SExpr *E) { return E->opcode() == COP_Branch; }
> +
> +  Branch(SExpr *C, BasicBlock *T, BasicBlock *E)
> +      : SExpr(COP_Branch), Condition(C), ThenBlock(T), ElseBlock(E) {}
> +  Branch(const Branch &Br, SExpr *C, BasicBlock *T, BasicBlock *E)
> +      : SExpr(COP_Branch), Condition(C), ThenBlock(T), ElseBlock(E) {}
> +
> +  SExpr *condition() { return Condition; }
> +  BasicBlock *thenBlock() { return ThenBlock; }
> +  BasicBlock *elseBlock() { return ElseBlock; }
> +
> +  template <class V> typename V::R_SExpr traverse(V &Visitor) {
> +    typename V::R_SExpr Nc = Visitor.traverse(Condition);
> +    BasicBlock *Ntb = Visitor.reduceBasicBlockRef(ThenBlock);
> +    BasicBlock *Nte = Visitor.reduceBasicBlockRef(ElseBlock);
> +    return Visitor.reduceBranch(*this, Nc, Ntb, Nte);
> +  }
> +
> +  template <class C> typename C::CType compare(Branch* E, C& Cmp) {
> +    // TODO -- implement CFG comparisons
> +    return Cmp.comparePointers(this, E);
> +  }
> +
> +private:
> +  SExpr *Condition;
> +  BasicBlock *ThenBlock;
> +  BasicBlock *ElseBlock;
> +};
> +
> +
> +
> +// 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 TILTraversal : 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.  TIL_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(SExpr *E, TIL_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 TILCopyReducer {
> +public:
> +  TILCopyReducer() {}

Why is this needed?

> +
> +  void setArena(MemRegionRef A) { Arena = A; }

This seems like it could be used as a constructor parameter instead.

> +
> +  // 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(TILCopyReducer &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 TILCopyReducer;
> +    SimpleArray<T> Elems;
> +  };
> +
> +public:

public is redundant.

> +  R_SExpr reduceNull() {
> +    return 0;

nullptr instead of 0

> +  }
> +  // 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);
> +  }
> +  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, Bbs.Elems);
> +  }
> +  R_SExpr reducePhi(Phi &Orig, Container<R_SExpr> As) {
> +    return new (Arena) Phi(Orig, 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, As.Elems, 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 TILTraversal<SExprCopier, TILCopyReducer> {
> +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 TILVisitReducer {
> +public:
> +  TILVisitReducer() {}
> +
> +  // 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(TILVisitReducer &R, unsigned N) : Success(true) {}
> +    void push_back(bool E) { Success = Success && E; }
> +
> +  private:
> +    friend class TILVisitReducer;
> +    bool Success;
> +  };
> +
> +public:

public is redundant.

> +  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, Container<R_SExpr> As) {
> +    return As.Success;
> +  }
> +  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 : 0;
> +  }
> +
> +  Variable *enterScope(Variable &Orig, R_SExpr E0) { return E0 ? &Orig : 0; }
> +  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 TILTraversal<Self, TILVisitReducer> {
> +public:
> +  SExprVisitor() : Success(true) {}
> +
> +  bool traverse(SExpr *E, TIL_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 TILComparator {
> +public:
> +  Self *self() { return reinterpret_cast<Self *>(this); }

Does this need to be 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 TILEqualsComparator : public TILComparator<TILEqualsComparator> {
> +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) {
> +    TILEqualsComparator Eq;
> +    return Eq.compareExprs(E1, E2);
> +  }
> +};
> +
> +
> +// Pretty printer for TIL expressions
> +template <typename Self, typename StreamType>
> +class TILPrettyPrinter {
> +public:
> +  static void print(SExpr *E, StreamType &SS) {
> +    Self printer;
> +    printer.printSExpr(E, SS, Prec_MAX);
> +  }
> +
> +protected:

Why not private?

> +  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;

Why not an enumeration instead?

> +
> +  // 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->pointer(), SS, Prec_Other-1);
> +    SS << " = ";
> +    self()->printSExpr(E->value(), 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) {

should be const auto * (similar comments apply elsewhere in this class).

> +      SS << "BB_" << BBI->blockID() << ":";
> +      newline(SS);
> +      for (auto I : BBI->arguments()) {
> +        SS << "let ";
> +        self()->printVariable(I, SS);
> +        SS << " = ";
> +        self()->printSExpr(I->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
>
> Modified: cfe/trunk/lib/Analysis/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CMakeLists.txt?rev=205728&r1=205727&r2=205728&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Analysis/CMakeLists.txt (original)
> +++ cfe/trunk/lib/Analysis/CMakeLists.txt Mon Apr  7 13:09:54 2014
> @@ -22,6 +22,7 @@ add_clang_library(clangAnalysis
>    PseudoConstantAnalysis.cpp
>    ReachableCode.cpp
>    ScanfFormatString.cpp
> +  ThreadSafetyCommon.cpp
>    ThreadSafety.cpp
>    UninitializedValues.cpp
>
>
> Modified: cfe/trunk/lib/Analysis/ThreadSafety.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafety.cpp?rev=205728&r1=205727&r2=205728&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Analysis/ThreadSafety.cpp (original)
> +++ cfe/trunk/lib/Analysis/ThreadSafety.cpp Mon Apr  7 13:09:54 2014
> @@ -10,18 +10,20 @@
>  // A intra-procedural analysis for thread safety (e.g. deadlocks and race
>  // conditions), based off of an annotation system.
>  //
> -// See http://clang.llvm.org/docs/LanguageExtensions.html#thread-safety-annotation-checking
> +// See http://clang.llvm.org/docs/ThreadSafetyAnalysis.html
>  // for more information.
>  //
>  //===----------------------------------------------------------------------===//
>
> -#include "clang/Analysis/Analyses/ThreadSafety.h"
>  #include "clang/AST/Attr.h"
>  #include "clang/AST/DeclCXX.h"
>  #include "clang/AST/ExprCXX.h"
>  #include "clang/AST/StmtCXX.h"
>  #include "clang/AST/StmtVisitor.h"
>  #include "clang/Analysis/Analyses/PostOrderCFGView.h"
> +#include "clang/Analysis/Analyses/ThreadSafety.h"
> +#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
> +#include "clang/Analysis/Analyses/ThreadSafetyCommon.h"
>  #include "clang/Analysis/AnalysisContext.h"
>  #include "clang/Analysis/CFG.h"
>  #include "clang/Analysis/CFGStmtMap.h"
> @@ -2362,16 +2364,21 @@ inline bool neverReturns(const CFGBlock*
>  /// at the end of each block, and issue warnings for thread safety violations.
>  /// Each block in the CFG is traversed exactly once.
>  void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
> -  CFG *CFGraph = AC.getCFG();
> -  if (!CFGraph) return;
> -  const NamedDecl *D = dyn_cast_or_null<NamedDecl>(AC.getDecl());
> +  // TODO: this whole function needs be rewritten as a visitor for CFGWalker.
> +  // For now, we just use the walker to set things up.
> +  threadSafety::CFGWalker walker;
> +  if (!walker.init(AC))
> +    return;
>
>    // AC.dumpCFG(true);
> +  // threadSafety::printSCFG(walker);

These two lines can be removed entirely instead of left commented out.

> +
> +  CFG *CFGraph = walker.CFGraph;
> +  const NamedDecl *D = walker.FDecl;
>
> -  if (!D)
> -    return;  // Ignore anonymous functions for now.
>    if (D->hasAttr<NoThreadSafetyAnalysisAttr>())
>      return;
> +
>    // FIXME: Do something a bit more intelligent inside constructor and
>    // destructor code.  Constructors and destructors must assume unique access
>    // to 'this', so checks on member variable access is disabled, but we should
> @@ -2387,7 +2394,7 @@ void ThreadSafetyAnalyzer::runAnalysis(A
>    // We need to explore the CFG via a "topological" ordering.
>    // That way, we will be guaranteed to have information about required
>    // predecessor locksets when exploring a new block.
> -  PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
> +  PostOrderCFGView *SortedGraph = walker.SortedGraph;
>    PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph);
>
>    // Mark entry block as reachable
>
> Added: cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp?rev=205728&view=auto
> ==============================================================================
> --- cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp (added)
> +++ cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp Mon Apr  7 13:09:54 2014
> @@ -0,0 +1,407 @@
> +//===- ThreadSafetyCommon.cpp ----------------------------------*- C++ --*-===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// Implementation of the interfaces declared in ThreadSafetyCommon.h
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "clang/AST/Attr.h"
> +#include "clang/AST/DeclCXX.h"
> +#include "clang/AST/ExprCXX.h"
> +#include "clang/AST/StmtCXX.h"
> +#include "clang/AST/StmtVisitor.h"
> +#include "clang/Analysis/Analyses/PostOrderCFGView.h"
> +#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
> +#include "clang/Analysis/Analyses/ThreadSafetyCommon.h"
> +#include "clang/Analysis/AnalysisContext.h"
> +#include "clang/Analysis/CFG.h"
> +#include "clang/Analysis/CFGStmtMap.h"
> +#include "clang/Basic/OperatorKinds.h"
> +#include "clang/Basic/SourceLocation.h"
> +#include "clang/Basic/SourceManager.h"
> +#include "llvm/ADT/BitVector.h"
> +#include "llvm/ADT/DenseMap.h"
> +#include "llvm/ADT/FoldingSet.h"
> +#include "llvm/ADT/ImmutableMap.h"
> +#include "llvm/ADT/PostOrderIterator.h"
> +#include "llvm/ADT/SmallVector.h"
> +#include "llvm/ADT/StringRef.h"
> +#include <vector>
> +
> +
> +namespace clang {
> +namespace threadSafety {
> +
> +typedef SExprBuilder::CallingContext CallingContext;
> +
> +
> +til::SExpr *SExprBuilder::lookupStmt(const Stmt *S) {
> +  if (!SMap)
> +    return 0;
> +  auto It = SMap->find(S);
> +  if (It != SMap->end())
> +    return It->second;
> +  return 0;
> +}
> +
> +void SExprBuilder::insertStmt(const Stmt *S, til::Variable *V) {
> +  SMap->insert(std::make_pair(S, V));
> +}
> +
> +
> +// Translate a clang statement or expression to a TIL expression.
> +// Also performs substitution of variables; Ctx provides the context.
> +// Dispatches on the type of S.
> +til::SExpr *SExprBuilder::translate(const Stmt *S, CallingContext *Ctx) {
> +  // Check if S has already been translated and cached.
> +  // This handles the lookup of SSA names for DeclRefExprs here.
> +  if (til::SExpr *E = lookupStmt(S))
> +    return E;
> +
> +  switch (S->getStmtClass()) {
> +  case Stmt::DeclRefExprClass:
> +    return translateDeclRefExpr(cast<DeclRefExpr>(S), Ctx);
> +  case Stmt::CXXThisExprClass:
> +    return translateCXXThisExpr(cast<CXXThisExpr>(S), Ctx);
> +  case Stmt::MemberExprClass:
> +    return translateMemberExpr(cast<MemberExpr>(S), Ctx);
> +  case Stmt::CallExprClass:
> +    return translateCallExpr(cast<CallExpr>(S), Ctx);
> +  case Stmt::CXXMemberCallExprClass:
> +    return translateCXXMemberCallExpr(cast<CXXMemberCallExpr>(S), Ctx);
> +  case Stmt::CXXOperatorCallExprClass:
> +    return translateCXXOperatorCallExpr(cast<CXXOperatorCallExpr>(S), Ctx);
> +  case Stmt::UnaryOperatorClass:
> +    return translateUnaryOperator(cast<UnaryOperator>(S), Ctx);
> +  case Stmt::BinaryOperatorClass:
> +    return translateBinaryOperator(cast<BinaryOperator>(S), Ctx);
> +
> +  case Stmt::ArraySubscriptExprClass:
> +    return translateArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Ctx);
> +  case Stmt::ConditionalOperatorClass:
> +    return translateConditionalOperator(cast<ConditionalOperator>(S), Ctx);
> +  case Stmt::BinaryConditionalOperatorClass:
> +    return translateBinaryConditionalOperator(
> +             cast<BinaryConditionalOperator>(S), Ctx);
> +
> +  // We treat these as no-ops
> +  case Stmt::ParenExprClass:
> +    return translate(cast<ParenExpr>(S)->getSubExpr(), Ctx);
> +  case Stmt::ExprWithCleanupsClass:
> +    return translate(cast<ExprWithCleanups>(S)->getSubExpr(), Ctx);
> +  case Stmt::CXXBindTemporaryExprClass:
> +    return translate(cast<CXXBindTemporaryExpr>(S)->getSubExpr(), Ctx);
> +
> +  // Collect all literals
> +  case Stmt::CharacterLiteralClass:
> +  case Stmt::CXXNullPtrLiteralExprClass:
> +  case Stmt::GNUNullExprClass:
> +  case Stmt::CXXBoolLiteralExprClass:
> +  case Stmt::FloatingLiteralClass:
> +  case Stmt::ImaginaryLiteralClass:
> +  case Stmt::IntegerLiteralClass:
> +  case Stmt::StringLiteralClass:
> +  case Stmt::ObjCStringLiteralClass:
> +    return new (Arena) til::Literal(cast<Expr>(S));
> +  default:
> +    break;
> +  }
> +  if (const CastExpr *CE = dyn_cast<CastExpr>(S))
> +    return translateCastExpr(CE, Ctx);
> +
> +  return new (Arena) til::Undefined(S);
> +}
> +
> +
> +til::SExpr *SExprBuilder::translateDeclRefExpr(const DeclRefExpr *DRE,
> +                                               CallingContext *Ctx) {
> +  const ValueDecl *VD = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl());
> +
> +  // Function parameters require substitution and/or renaming.
> +  if (const ParmVarDecl *PV = dyn_cast_or_null<ParmVarDecl>(VD)) {
> +    const FunctionDecl *FD =
> +        cast<FunctionDecl>(PV->getDeclContext())->getCanonicalDecl();
> +    unsigned I = PV->getFunctionScopeIndex();
> +
> +    if (Ctx && Ctx->FunArgs && FD == Ctx->AttrDecl->getCanonicalDecl()) {
> +      // Substitute call arguments for references to function parameters
> +      assert(I < Ctx->NumArgs);
> +      return translate(Ctx->FunArgs[I], Ctx->Prev);
> +    }
> +    // Map the param back to the param of the original function declaration
> +    // for consistent comparisons.
> +    VD = FD->getParamDecl(I);
> +  }
> +
> +  // For non-local variables, treat it as a referenced to a named object.
> +  return new (Arena) til::LiteralPtr(VD);
> +}
> +
> +
> +til::SExpr *SExprBuilder::translateCXXThisExpr(const CXXThisExpr *TE,
> +                                               CallingContext *Ctx) {
> +  // Substitute for 'this'
> +  if (Ctx && Ctx->SelfArg)
> +    return translate(Ctx->SelfArg, Ctx->Prev);
> +  assert(SelfVar && "We have no variable for 'this'!");
> +  return SelfVar;
> +}
> +
> +
> +til::SExpr *SExprBuilder::translateMemberExpr(const MemberExpr *ME,
> +                                              CallingContext *Ctx) {
> +  til::SExpr *E = translate(ME->getBase(), Ctx);
> +  E = new (Arena) til::SApply(E);
> +  return new (Arena) til::Project(E, ME->getMemberDecl());
> +}
> +
> +
> +til::SExpr *SExprBuilder::translateCallExpr(const CallExpr *CE,
> +                                            CallingContext *Ctx) {
> +  // TODO -- Lock returned
> +  til::SExpr *E = translate(CE->getCallee(), Ctx);
> +  for (unsigned I = 0, N = CE->getNumArgs(); I < N; ++I) {

Seems like CallExpr could use an arguments() range function that could
be used here.  ;-)

> +    til::SExpr *A = translate(CE->getArg(I), Ctx);
> +    E = new (Arena) til::Apply(E, A);
> +  }
> +  return new (Arena) til::Call(E, CE);
> +}
> +
> +
> +til::SExpr *SExprBuilder::translateCXXMemberCallExpr(
> +    const CXXMemberCallExpr *ME, CallingContext *Ctx) {
> +  return translateCallExpr(cast<CallExpr>(ME), Ctx);
> +}
> +
> +
> +til::SExpr *SExprBuilder::translateCXXOperatorCallExpr(
> +    const CXXOperatorCallExpr *OCE, CallingContext *Ctx) {
> +  return translateCallExpr(cast<CallExpr>(OCE), Ctx);
> +}
> +
> +
> +til::SExpr *SExprBuilder::translateUnaryOperator(const UnaryOperator *UO,
> +                                                 CallingContext *Ctx) {
> +  switch (UO->getOpcode()) {
> +  case UO_PostInc:
> +  case UO_PostDec:
> +  case UO_PreInc:
> +  case UO_PreDec:
> +    return new (Arena) til::Undefined(UO);
> +
> +  // We treat these as no-ops
> +  case UO_AddrOf:
> +  case UO_Deref:
> +  case UO_Plus:
> +    return translate(UO->getSubExpr(), Ctx);
> +
> +  case UO_Minus:
> +  case UO_Not:
> +  case UO_LNot:
> +  case UO_Real:
> +  case UO_Imag:
> +  case UO_Extension: {
> +    til::SExpr *E0 = translate(UO->getSubExpr(), Ctx);
> +    return new (Arena) til::UnaryOp(UO->getOpcode(), E0);
> +  }
> +  }
> +  return new (Arena) til::Undefined(UO);
> +}
> +
> +til::SExpr *SExprBuilder::translateBinaryOperator(const BinaryOperator *BO,
> +                                                  CallingContext *Ctx) {
> +  switch (BO->getOpcode()) {
> +  case BO_PtrMemD:
> +  case BO_PtrMemI:
> +    return new (Arena) til::Undefined(BO);
> +
> +  case BO_Mul:
> +  case BO_Div:
> +  case BO_Rem:
> +  case BO_Add:
> +  case BO_Sub:
> +  case BO_Shl:
> +  case BO_Shr:
> +  case BO_LT:
> +  case BO_GT:
> +  case BO_LE:
> +  case BO_GE:
> +  case BO_EQ:
> +  case BO_NE:
> +  case BO_And:
> +  case BO_Xor:
> +  case BO_Or:
> +  case BO_LAnd:
> +  case BO_LOr: {
> +    til::SExpr *E0 = translate(BO->getLHS(), Ctx);
> +    til::SExpr *E1 = translate(BO->getRHS(), Ctx);
> +    return new (Arena) til::BinaryOp(BO->getOpcode(), E0, E1);
> +  }
> +  case BO_Assign: {
> +    til::SExpr *E0 = translate(BO->getLHS(), Ctx);
> +    til::SExpr *E1 = translate(BO->getRHS(), Ctx);
> +    return new (Arena) til::Store(E0, E1);
> +  }
> +  case BO_MulAssign:
> +  case BO_DivAssign:
> +  case BO_RemAssign:
> +  case BO_AddAssign:
> +  case BO_SubAssign:
> +  case BO_ShlAssign:
> +  case BO_ShrAssign:
> +  case BO_AndAssign:
> +  case BO_XorAssign:
> +  case BO_OrAssign:
> +    return new (Arena) til::Undefined(BO);
> +
> +  case BO_Comma:
> +    // TODO: handle LHS
> +    return translate(BO->getRHS(), Ctx);
> +  }
> +
> +  return new (Arena) til::Undefined(BO);
> +}
> +
> +
> +til::SExpr *SExprBuilder::translateCastExpr(const CastExpr *CE,
> +                                            CallingContext *Ctx) {
> +  til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);
> +
> +  clang::CastKind K = CE->getCastKind();
> +  switch (K) {
> +  case CK_LValueToRValue:
> +    return new (Arena) til::Load(E0);
> +
> +  case CK_NoOp:
> +  case CK_DerivedToBase:
> +  case CK_UncheckedDerivedToBase:
> +  case CK_ArrayToPointerDecay:
> +  case CK_FunctionToPointerDecay:
> +    return E0;
> +
> +  default:
> +    return new (Arena) til::Cast(K, E0);
> +  }
> +}
> +
> +
> +til::SExpr *SExprBuilder::translateArraySubscriptExpr(
> +    const ArraySubscriptExpr *E, CallingContext *Ctx) {
> +  return new (Arena) til::Undefined(E);
> +}
> +
> +
> +til::SExpr *SExprBuilder::translateConditionalOperator(
> +    const ConditionalOperator *C,  CallingContext *Ctx) {
> +  return new (Arena) til::Undefined(C);
> +}
> +
> +
> +til::SExpr *SExprBuilder::translateBinaryConditionalOperator(
> +    const BinaryConditionalOperator *C, CallingContext *Ctx) {
> +  return new (Arena) til::Undefined(C);
> +}
> +
> +
> +// Build a complete SCFG from a clang CFG.
> +class SCFGBuilder : public CFGVisitor {
> +public:
> +  // return true if E should be included in the SCFG
> +  bool includeExpr(til::SExpr* E) {

This should be private. That goes for other members of this class as well.

> +    if (!E)
> +      return false;
> +    if (E->opcode() == til::COP_Variable)
> +      return false;
> +    if (E->opcode() == til::COP_LiteralPtr)
> +      return false;
> +    return true;
> +  }
> +
> +  // Enter the CFG for Decl D, and perform any initial setup operations.
> +  void enterCFG(CFG *Cfg, const NamedDecl *D, const CFGBlock *First) {
> +    Scfg = new til::SCFG(Arena, Cfg->getNumBlockIDs());
> +    CallCtx = new SExprBuilder::CallingContext(D);

These are being leaked. unique_ptr perhaps?

> +  }
> +
> +  // Enter a CFGBlock.
> +  void enterCFGBlock(const CFGBlock *B) {
> +    CurrentBB = new til::BasicBlock(Arena, 0, B->size());
> +    CurrentBB->setBlockID(CurrentBlockID);
> +    CurrentVarID = 0;
> +    Scfg->add(CurrentBB);

All of these blocks wind up being leaked.

> +  }
> +
> +  // Process an ordinary statement.
> +  void handleStatement(const Stmt *S) {
> +    til::SExpr *E = BuildEx.translate(S, CallCtx);
> +    if (includeExpr(E)) {
> +      til::Variable *V = new til::Variable(til::Variable::VK_Let, E);
> +      V->setID(CurrentBlockID, CurrentVarID++);
> +      CurrentBB->addInstr(V);

All of these are leaked as well.

> +      BuildEx.insertStmt(S, V);
> +    }
> +  }
> +
> +  // Process a destructor call
> +  void handleDestructorCall(const VarDecl *VD, const CXXDestructorDecl *DD) {}
> +
> +  // Process a successor edge.
> +  void handleSuccessor(const CFGBlock *Succ) {}
> +
> +  // Process a successor back edge to a previously visited block.
> +  void handleSuccessorBackEdge(const CFGBlock *Succ) {}
> +
> +  // Leave a CFGBlock.
> +  void exitCFGBlock(const CFGBlock *B) {
> +    CurrentBlockID++;
> +    CurrentBB = 0;
> +  }
> +
> +  // Leave the CFG, and perform any final cleanup operations.
> +  void exitCFG(const CFGBlock *Last) {}
> +
> +  SCFGBuilder(til::MemRegionRef A)
> +      : Arena(A), Scfg(0), CurrentBB(0), CurrentBlockID(0),
> +        BuildEx(A, new SExprBuilder::StatementMap())
> +  { }
> +
> +  til::SCFG *getCFG() const { return Scfg; }
> +
> +private:
> +  til::MemRegionRef Arena;
> +  til::SCFG *Scfg;
> +  til::BasicBlock *CurrentBB;
> +  unsigned CurrentBlockID;
> +  unsigned CurrentVarID;
> +
> +  SExprBuilder BuildEx;
> +  SExprBuilder::CallingContext *CallCtx;
> +};
> +
> +
> +
> +class LLVMPrinter :
> +    public til::TILPrettyPrinter<LLVMPrinter, llvm::raw_ostream> {
> +};
> +
> +
> +void printSCFG(CFGWalker &walker) {
> +  llvm::BumpPtrAllocator Bpa;
> +  til::MemRegionRef Arena(&Bpa);
> +  SCFGBuilder builder(Arena);
> +  // CFGVisitor visitor;
> +  walker.walk(builder);
> +  LLVMPrinter::print(builder.getCFG(), llvm::errs());
> +}
> +
> +
> +
> +} // end namespace threadSafety
> +
> +} // end namespace clang
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

~Aaron



More information about the cfe-commits mailing list