text: //===- 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/Analysis/Analyses/ThreadSafetyCommon.h"
  #include "clang/AST/Attr.h"
  #include "clang/AST/DeclCXX.h"
  #include "clang/AST/DeclObjC.h"
  #include "clang/AST/ExprCXX.h"
  #include "clang/AST/StmtCXX.h"
  #include "clang/Analysis/Analyses/PostOrderCFGView.h"
  #include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
  #include "clang/Analysis/Analyses/ThreadSafetyTraverse.h"
  #include "clang/Analysis/AnalysisContext.h"
  #include "clang/Analysis/CFG.h"
  #include "clang/Basic/OperatorKinds.h"
  #include "clang/Basic/SourceLocation.h"
  #include "clang/Basic/SourceManager.h"
  #include "llvm/ADT/DenseMap.h"
  #include "llvm/ADT/SmallVector.h"
  #include "llvm/ADT/StringRef.h"
  #include <algorithm>
  #include <climits>
  #include <vector>
  using namespace clang;
  using namespace threadSafety;
  
  // From ThreadSafetyUtil.h
  std::string threadSafety::getSourceLiteralString(const clang::Expr *CE) {
    switch (CE->getStmtClass()) {
      case Stmt::IntegerLiteralClass:
        return cast<IntegerLiteral>(CE)->getValue().toString(10, true);
      case Stmt::StringLiteralClass: {
        std::string ret("\"");
        ret += cast<StringLiteral>(CE)->getString();
        ret += "\"";
        return ret;
      }
      case Stmt::CharacterLiteralClass:
      case Stmt::CXXNullPtrLiteralExprClass:
      case Stmt::GNUNullExprClass:
      case Stmt::CXXBoolLiteralExprClass:
      case Stmt::FloatingLiteralClass:
      case Stmt::ImaginaryLiteralClass:
      case Stmt::ObjCStringLiteralClass:
      default:
        return "#lit";
    }
  }
  
  // Return true if E is a variable that points to an incomplete Phi node.
  static bool isIncompletePhi(const til::SExpr *E) {
    if (const auto *Ph = dyn_cast<til::Phi>(E))
      return Ph->status() == til::Phi::PH_Incomplete;
    return false;
  }
  
  typedef SExprBuilder::CallingContext CallingContext;
  
  
  til::SExpr *SExprBuilder::lookupStmt(const Stmt *S) {
    auto It = SMap.find(S);
    if (It != SMap.end())
      return It->second;
    return nullptr;
  }
  
  
  til::SCFG *SExprBuilder::buildCFG(CFGWalker &Walker) {
    Walker.walk(*this);
    return Scfg;
  }
  
  static bool isCalleeArrow(const Expr *E) {
    const MemberExpr *ME = dyn_cast<MemberExpr>(E->IgnoreParenCasts());
    return ME ? ME->isArrow() : false;
  }
  
  
  /// \brief Translate a clang expression in an attribute to a til::SExpr.
  /// Constructs the context from D, DeclExp, and SelfDecl.
  ///
  /// \param AttrExp The expression to translate.
  /// \param D       The declaration to which the attribute is attached.
  /// \param DeclExp An expression involving the Decl to which the attribute
  ///                is attached.  E.g. the call to a function.
  CapabilityExpr SExprBuilder::translateAttrExpr(const Expr *AttrExp,
                                                 const NamedDecl *D,
                                                 const Expr *DeclExp,
                                                 VarDecl *SelfDecl) {
    // If we are processing a raw attribute expression, with no substitutions.
    if (!DeclExp)
      return translateAttrExpr(AttrExp, nullptr);
  
    CallingContext Ctx(nullptr, D);
  
    // Examine DeclExp to find SelfArg and FunArgs, which are used to substitute
    // for formal parameters when we call buildMutexID later.
    if (const MemberExpr *ME = dyn_cast<MemberExpr>(DeclExp)) {
      Ctx.SelfArg   = ME->getBase();
      Ctx.SelfArrow = ME->isArrow();
    } else if (const CXXMemberCallExpr *CE =
               dyn_cast<CXXMemberCallExpr>(DeclExp)) {
      Ctx.SelfArg   = CE->getImplicitObjectArgument();
      Ctx.SelfArrow = isCalleeArrow(CE->getCallee());
      Ctx.NumArgs   = CE->getNumArgs();
      Ctx.FunArgs   = CE->getArgs();
    } else if (const CallExpr *CE = dyn_cast<CallExpr>(DeclExp)) {
      Ctx.NumArgs = CE->getNumArgs();
      Ctx.FunArgs = CE->getArgs();
    } else if (const CXXConstructExpr *CE =
               dyn_cast<CXXConstructExpr>(DeclExp)) {
      Ctx.SelfArg = nullptr;  // Will be set below
      Ctx.NumArgs = CE->getNumArgs();
      Ctx.FunArgs = CE->getArgs();
    } else if (D && isa<CXXDestructorDecl>(D)) {
      // There's no such thing as a "destructor call" in the AST.
      Ctx.SelfArg = DeclExp;
    }
  
    // Hack to handle constructors, where self cannot be recovered from
    // the expression.
    if (SelfDecl && !Ctx.SelfArg) {
      DeclRefExpr SelfDRE(SelfDecl, false, SelfDecl->getType(), VK_LValue,
                          SelfDecl->getLocation());
      Ctx.SelfArg = &SelfDRE;
  
      // If the attribute has no arguments, then assume the argument is "this".
      if (!AttrExp)
        return translateAttrExpr(Ctx.SelfArg, nullptr);
      else  // For most attributes.
        return translateAttrExpr(AttrExp, &Ctx);
    }
  
    // If the attribute has no arguments, then assume the argument is "this".
    if (!AttrExp)
      return translateAttrExpr(Ctx.SelfArg, nullptr);
    else  // For most attributes.
      return translateAttrExpr(AttrExp, &Ctx);
  }
  
  
  /// \brief Translate a clang expression in an attribute to a til::SExpr.
  // This assumes a CallingContext has already been created.
  CapabilityExpr SExprBuilder::translateAttrExpr(const Expr *AttrExp,
                                                 CallingContext *Ctx) {
    if (!AttrExp)
      return CapabilityExpr(nullptr, false);
  
    if (auto* SLit = dyn_cast<StringLiteral>(AttrExp)) {
      if (SLit->getString() == StringRef("*"))
        // The "*" expr is a universal lock, which essentially turns off
        // checks until it is removed from the lockset.
        return CapabilityExpr(new (Arena) til::Wildcard(), false);
      else
        // Ignore other string literals for now.
        return CapabilityExpr(nullptr, false);
    }
  
    bool Neg = false;
    if (auto *OE = dyn_cast<CXXOperatorCallExpr>(AttrExp)) {
      if (OE->getOperator() == OO_Exclaim) {
        Neg = true;
        AttrExp = OE->getArg(0);
      }
    }
    else if (auto *UO = dyn_cast<UnaryOperator>(AttrExp)) {
      if (UO->getOpcode() == UO_LNot) {
        Neg = true;
        AttrExp = UO->getSubExpr();
      }
    }
  
    til::SExpr *E = translate(AttrExp, Ctx);
  
    // Trap mutex expressions like nullptr, or 0.
    // Any literal value is nonsense.
    if (!E || isa<til::Literal>(E))
      return CapabilityExpr(nullptr, false);
  
    // Hack to deal with smart pointers -- strip off top-level pointer casts.
    if (auto *CE = dyn_cast_or_null<til::Cast>(E)) {
      if (CE->castOpcode() == til::CAST_objToPtr)
        return CapabilityExpr(CE->expr(), Neg);
    }
    return CapabilityExpr(E, Neg);
  }
  
  
  
  // 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) {
    if (!S)
      return nullptr;
  
    // Check if S has already been translated and cached.
    // This handles the lookup of SSA names for DeclRefExprs here.
    if (til::SExpr *E = lookupStmt(S))
      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:
    case Stmt::CompoundAssignOperatorClass:
      return translateBinaryOperator(cast<BinaryOperator>(S), Ctx);
  
    case Stmt::ArraySubscriptExprClass:
      return translateArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Ctx);
    case Stmt::ConditionalOperatorClass:
      return translateAbstractConditionalOperator(
               cast<ConditionalOperator>(S), Ctx);
    case Stmt::BinaryConditionalOperatorClass:
      return translateAbstractConditionalOperator(
               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));
  
    case Stmt::DeclStmtClass:
      return translateDeclStmt(cast<DeclStmt>(S), Ctx);
    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;
  }
  
  static const ValueDecl *getValueDeclFromSExpr(const til::SExpr *E) {
    if (auto *V = dyn_cast<til::Variable>(E))
      return V->clangDecl();
    if (auto *Ph = dyn_cast<til::Phi>(E))
      return Ph->clangDecl();
    if (auto *P = dyn_cast<til::Project>(E))
      return P->clangDecl();
    if (auto *L = dyn_cast<til::LiteralPtr>(E))
      return L->clangDecl();
    return 0;
  }
  
  static bool hasCppPointerType(const til::SExpr *E) {
    auto *VD = getValueDeclFromSExpr(E);
    if (VD && VD->getType()->isPointerType())
      return true;
    if (auto *C = dyn_cast<til::Cast>(E))
      return C->castOpcode() == til::CAST_objToPtr;
  
    return false;
  }
  
  // Grab the very first declaration of virtual method D
  static const CXXMethodDecl *getFirstVirtualDecl(const CXXMethodDecl *D) {
    while (true) {
      D = D->getCanonicalDecl();
      CXXMethodDecl::method_iterator I = D->begin_overridden_methods(),
                                     E = D->end_overridden_methods();
      if (I == E)
        return D;  // Method does not override anything
      D = *I;      // FIXME: this does not work with multiple inheritance.
    }
    return nullptr;
  }
  
  til::SExpr *SExprBuilder::translateMemberExpr(const MemberExpr *ME,
                                                CallingContext *Ctx) {
    til::SExpr *BE = translate(ME->getBase(), Ctx);
    til::SExpr *E  = new (Arena) til::SApply(BE);
  
    const ValueDecl *D = ME->getMemberDecl();
    if (auto *VD = dyn_cast<CXXMethodDecl>(D))
      D = getFirstVirtualDecl(VD);
  
    til::Project *P = new (Arena) til::Project(E, D);
    if (hasCppPointerType(BE))
      P->setArrow(true);
    return P;
  }
  
  
  til::SExpr *SExprBuilder::translateCallExpr(const CallExpr *CE,
                                              CallingContext *Ctx,
                                              const Expr *SelfE) {
    if (CapabilityExprMode) {
      // Handle LOCK_RETURNED
      const FunctionDecl *FD = CE->getDirectCallee()->getMostRecentDecl();
      if (LockReturnedAttr* At = FD->getAttr<LockReturnedAttr>()) {
        CallingContext LRCallCtx(Ctx);
        LRCallCtx.AttrDecl = CE->getDirectCallee();
        LRCallCtx.SelfArg  = SelfE;
        LRCallCtx.NumArgs  = CE->getNumArgs();
        LRCallCtx.FunArgs  = CE->getArgs();
        return const_cast<til::SExpr*>(
            translateAttrExpr(At->getArg(), &LRCallCtx).sexpr());
      }
    }
  
    til::SExpr *E = translate(CE->getCallee(), Ctx);
    for (const auto *Arg : CE->arguments()) {
      til::SExpr *A = translate(Arg, Ctx);
      E = new (Arena) til::Apply(E, A);
    }
    return new (Arena) til::Call(E, CE);
  }
  
  
  til::SExpr *SExprBuilder::translateCXXMemberCallExpr(
      const CXXMemberCallExpr *ME, CallingContext *Ctx) {
    if (CapabilityExprMode) {
      // Ignore calls to get() on smart pointers.
      if (ME->getMethodDecl()->getNameAsString() == "get" &&
          ME->getNumArgs() == 0) {
        auto *E = translate(ME->getImplicitObjectArgument(), Ctx);
        return new (Arena) til::Cast(til::CAST_objToPtr, E);
        // return E;
      }
    }
    return translateCallExpr(cast<CallExpr>(ME), Ctx,
                             ME->getImplicitObjectArgument());
  }
  
  
  til::SExpr *SExprBuilder::translateCXXOperatorCallExpr(
      const CXXOperatorCallExpr *OCE, CallingContext *Ctx) {
    if (CapabilityExprMode) {
      // Ignore operator * and operator -> on smart pointers.
      OverloadedOperatorKind k = OCE->getOperator();
      if (k == OO_Star || k == OO_Arrow) {
        auto *E = translate(OCE->getArg(0), Ctx);
        return new (Arena) til::Cast(til::CAST_objToPtr, E);
        // return E;
      }
    }
    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);
  
    case UO_AddrOf: {
      if (CapabilityExprMode) {
        // interpret &Graph::mu_ as an existential.
        if (DeclRefExpr* DRE = dyn_cast<DeclRefExpr>(UO->getSubExpr())) {
          if (DRE->getDecl()->isCXXInstanceMember()) {
            // This is a pointer-to-member expression, e.g. &MyClass::mu_.
            // We interpret this syntax specially, as a wildcard.
            auto *W = new (Arena) til::Wildcard();
            return new (Arena) til::Project(W, DRE->getDecl());
          }
        }
      }
      // otherwise, & is a no-op
      return translate(UO->getSubExpr(), Ctx);
    }
  
    // We treat these as no-ops
    case UO_Deref:
    case UO_Plus:
      return translate(UO->getSubExpr(), Ctx);
  
    case UO_Minus:
      return new (Arena)
        til::UnaryOp(til::UOP_Minus, translate(UO->getSubExpr(), Ctx));
    case UO_Not:
      return new (Arena)
        til::UnaryOp(til::UOP_BitNot, translate(UO->getSubExpr(), Ctx));
    case UO_LNot:
      return new (Arena)
        til::UnaryOp(til::UOP_LogicNot, translate(UO->getSubExpr(), Ctx));
  
    // Currently unsupported
    case UO_Real:
    case UO_Imag:
    case UO_Extension:
      return new (Arena) til::Undefined(UO);
    }
    return new (Arena) til::Undefined(UO);
  }
  
  
  til::SExpr *SExprBuilder::translateBinOp(til::TIL_BinaryOpcode Op,
                                           const BinaryOperator *BO,
                                           CallingContext *Ctx, bool Reverse) {
     til::SExpr *E0 = translate(BO->getLHS(), Ctx);
     til::SExpr *E1 = translate(BO->getRHS(), Ctx);
     if (Reverse)
       return new (Arena) til::BinaryOp(Op, E1, E0);
     else
       return new (Arena) til::BinaryOp(Op, E0, E1);
  }
  
  
  til::SExpr *SExprBuilder::translateBinAssign(til::TIL_BinaryOpcode Op,
                                               const BinaryOperator *BO,
                                               CallingContext *Ctx,
                                               bool Assign) {
    const Expr *LHS = BO->getLHS();
    const Expr *RHS = BO->getRHS();
    til::SExpr *E0 = translate(LHS, Ctx);
    til::SExpr *E1 = translate(RHS, Ctx);
  
    const ValueDecl *VD = nullptr;
    til::SExpr *CV = nullptr;
    if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(LHS)) {
      VD = DRE->getDecl();
      CV = lookupVarDecl(VD);
    }
  
    if (!Assign) {
      til::SExpr *Arg = CV ? CV : new (Arena) til::Load(E0);
      E1 = new (Arena) til::BinaryOp(Op, Arg, E1);
      E1 = addStatement(E1, nullptr, VD);
    }
    if (VD && CV)
      return updateVarDecl(VD, E1);
    return new (Arena) til::Store(E0, E1);
  }
  
  
  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:  return translateBinOp(til::BOP_Mul, BO, Ctx);
    case BO_Div:  return translateBinOp(til::BOP_Div, BO, Ctx);
    case BO_Rem:  return translateBinOp(til::BOP_Rem, BO, Ctx);
    case BO_Add:  return translateBinOp(til::BOP_Add, BO, Ctx);
    case BO_Sub:  return translateBinOp(til::BOP_Sub, BO, Ctx);
    case BO_Shl:  return translateBinOp(til::BOP_Shl, BO, Ctx);
    case BO_Shr:  return translateBinOp(til::BOP_Shr, BO, Ctx);
    case BO_LT:   return translateBinOp(til::BOP_Lt,  BO, Ctx);
    case BO_GT:   return translateBinOp(til::BOP_Lt,  BO, Ctx, true);
    case BO_LE:   return translateBinOp(til::BOP_Leq, BO, Ctx);
    case BO_GE:   return translateBinOp(til::BOP_Leq, BO, Ctx, true);
    case BO_EQ:   return translateBinOp(til::BOP_Eq,  BO, Ctx);
    case BO_NE:   return translateBinOp(til::BOP_Neq, BO, Ctx);
    case BO_And:  return translateBinOp(til::BOP_BitAnd,   BO, Ctx);
    case BO_Xor:  return translateBinOp(til::BOP_BitXor,   BO, Ctx);
    case BO_Or:   return translateBinOp(til::BOP_BitOr,    BO, Ctx);
    case BO_LAnd: return translateBinOp(til::BOP_LogicAnd, BO, Ctx);
    case BO_LOr:  return translateBinOp(til::BOP_LogicOr,  BO, Ctx);
  
    case BO_Assign:    return translateBinAssign(til::BOP_Eq,  BO, Ctx, true);
    case BO_MulAssign: return translateBinAssign(til::BOP_Mul, BO, Ctx);
    case BO_DivAssign: return translateBinAssign(til::BOP_Div, BO, Ctx);
    case BO_RemAssign: return translateBinAssign(til::BOP_Rem, BO, Ctx);
    case BO_AddAssign: return translateBinAssign(til::BOP_Add, BO, Ctx);
    case BO_SubAssign: return translateBinAssign(til::BOP_Sub, BO, Ctx);
    case BO_ShlAssign: return translateBinAssign(til::BOP_Shl, BO, Ctx);
    case BO_ShrAssign: return translateBinAssign(til::BOP_Shr, BO, Ctx);
    case BO_AndAssign: return translateBinAssign(til::BOP_BitAnd, BO, Ctx);
    case BO_XorAssign: return translateBinAssign(til::BOP_BitXor, BO, Ctx);
    case BO_OrAssign:  return translateBinAssign(til::BOP_BitOr,  BO, Ctx);
  
    case BO_Comma:
      // The clang CFG should have already processed both sides.
      return translate(BO->getRHS(), Ctx);
    }
    return new (Arena) til::Undefined(BO);
  }
  
  
  til::SExpr *SExprBuilder::translateCastExpr(const CastExpr *CE,
                                              CallingContext *Ctx) {
    clang::CastKind K = CE->getCastKind();
    switch (K) {
    case CK_LValueToRValue: {
      if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CE->getSubExpr())) {
        til::SExpr *E0 = lookupVarDecl(DRE->getDecl());
        if (E0)
          return E0;
      }
      til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);
      return E0;
      // FIXME!! -- get Load working properly
      // return new (Arena) til::Load(E0);
    }
    case CK_NoOp:
    case CK_DerivedToBase:
    case CK_UncheckedDerivedToBase:
    case CK_ArrayToPointerDecay:
    case CK_FunctionToPointerDecay: {
      til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);
      return E0;
    }
    default: {
      // FIXME: handle different kinds of casts.
      til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);
      if (CapabilityExprMode)
        return E0;
      return new (Arena) til::Cast(til::CAST_none, E0);
    }
    }
  }
  
  
  til::SExpr *
  SExprBuilder::translateArraySubscriptExpr(const ArraySubscriptExpr *E,
                                            CallingContext *Ctx) {
    til::SExpr *E0 = translate(E->getBase(), Ctx);
    til::SExpr *E1 = translate(E->getIdx(), Ctx);
    return new (Arena) til::ArrayIndex(E0, E1);
  }
  
  
  til::SExpr *
  SExprBuilder::translateAbstractConditionalOperator(
      const AbstractConditionalOperator *CO, CallingContext *Ctx) {
    auto *C = translate(CO->getCond(), Ctx);
    auto *T = translate(CO->getTrueExpr(), Ctx);
    auto *E = translate(CO->getFalseExpr(), Ctx);
    return new (Arena) til::IfThenElse(C, T, E);
  }
  
  
  til::SExpr *
  SExprBuilder::translateDeclStmt(const DeclStmt *S, CallingContext *Ctx) {
    DeclGroupRef DGrp = S->getDeclGroup();
    for (DeclGroupRef::iterator I = DGrp.begin(), E = DGrp.end(); I != E; ++I) {
      if (VarDecl *VD = dyn_cast_or_null<VarDecl>(*I)) {
        Expr *E = VD->getInit();
        til::SExpr* SE = translate(E, Ctx);
  
        // Add local variables with trivial type to the variable map
        QualType T = VD->getType();
        if (T.isTrivialType(VD->getASTContext())) {
          return addVarDecl(VD, SE);
        }
        else {
          // TODO: add alloca
        }
      }
    }
    return nullptr;
  }
  
  
  
  // If (E) is non-trivial, then add it to the current basic block, and
  // update the statement map so that S refers to E.  Returns a new variable
  // that refers to E.
  // If E is trivial returns E.
  til::SExpr *SExprBuilder::addStatement(til::SExpr* E, const Stmt *S,
                                         const ValueDecl *VD) {
    if (!E || !CurrentBB || E->block() || til::ThreadSafetyTIL::isTrivial(E))
      return E;
    if (VD)
      E = new (Arena) til::Variable(E, VD);
    CurrentInstructions.push_back(E);
    if (S)
      insertStmt(S, E);
    return E;
  }
  
  
  // Returns the current value of VD, if known, and nullptr otherwise.
  til::SExpr *SExprBuilder::lookupVarDecl(const ValueDecl *VD) {
    auto It = LVarIdxMap.find(VD);
    if (It != LVarIdxMap.end()) {
      assert(CurrentLVarMap[It->second].first == VD);
      return CurrentLVarMap[It->second].second;
    }
    return nullptr;
  }
  
  
  // if E is a til::Variable, update its clangDecl.
  static void maybeUpdateVD(til::SExpr *E, const ValueDecl *VD) {
    if (!E)
      return;
    if (til::Variable *V = dyn_cast<til::Variable>(E)) {
      if (!V->clangDecl())
        V->setClangDecl(VD);
    }
  }
  
  // Adds a new variable declaration.
  til::SExpr *SExprBuilder::addVarDecl(const ValueDecl *VD, til::SExpr *E) {
    maybeUpdateVD(E, VD);
    LVarIdxMap.insert(std::make_pair(VD, CurrentLVarMap.size()));
    CurrentLVarMap.makeWritable();
    CurrentLVarMap.push_back(std::make_pair(VD, E));
    return E;
  }
  
  
  // Updates a current variable declaration.  (E.g. by assignment)
  til::SExpr *SExprBuilder::updateVarDecl(const ValueDecl *VD, til::SExpr *E) {
    maybeUpdateVD(E, VD);
    auto It = LVarIdxMap.find(VD);
    if (It == LVarIdxMap.end()) {
      til::SExpr *Ptr = new (Arena) til::LiteralPtr(VD);
      til::SExpr *St  = new (Arena) til::Store(Ptr, E);
      return St;
    }
    CurrentLVarMap.makeWritable();
    CurrentLVarMap.elem(It->second).second = E;
    return E;
  }
  
  
  // Make a Phi node in the current block for the i^th variable in CurrentVarMap.
  // If E != null, sets Phi[CurrentBlockInfo->ArgIndex] = E.
  // If E == null, this is a backedge and will be set later.
  void SExprBuilder::makePhiNodeVar(unsigned i, unsigned NPreds, til::SExpr *E) {
    unsigned ArgIndex = CurrentBlockInfo->ProcessedPredecessors;
    assert(ArgIndex > 0 && ArgIndex < NPreds);
  
    til::SExpr *CurrE = CurrentLVarMap[i].second;
    if (CurrE->block() == CurrentBB) {
      // We already have a Phi node in the current block,
      // so just add the new variable to the Phi node.
      til::Phi *Ph = dyn_cast<til::Phi>(CurrE);
      assert(Ph && "Expecting Phi node.");
      if (E)
        Ph->values()[ArgIndex] = E;
      return;
    }
  
    // Make a new phi node: phi(..., E)
    // All phi args up to the current index are set to the current value.
    til::Phi *Ph = new (Arena) til::Phi(Arena, NPreds);
    Ph->values().setValues(NPreds, nullptr);
    for (unsigned PIdx = 0; PIdx < ArgIndex; ++PIdx)
      Ph->values()[PIdx] = CurrE;
    if (E)
      Ph->values()[ArgIndex] = E;
    Ph->setClangDecl(CurrentLVarMap[i].first);
    // If E is from a back-edge, or either E or CurrE are incomplete, then
    // mark this node as incomplete; we may need to remove it later.
    if (!E || isIncompletePhi(E) || isIncompletePhi(CurrE)) {
      Ph->setStatus(til::Phi::PH_Incomplete);
    }
  
    // Add Phi node to current block, and update CurrentLVarMap[i]
    CurrentArguments.push_back(Ph);
    if (Ph->status() == til::Phi::PH_Incomplete)
      IncompleteArgs.push_back(Ph);
  
    CurrentLVarMap.makeWritable();
    CurrentLVarMap.elem(i).second = Ph;
  }
  
  
  // Merge values from Map into the current variable map.
  // This will construct Phi nodes in the current basic block as necessary.
  void SExprBuilder::mergeEntryMap(LVarDefinitionMap Map) {
    assert(CurrentBlockInfo && "Not processing a block!");
  
    if (!CurrentLVarMap.valid()) {
      // Steal Map, using copy-on-write.
      CurrentLVarMap = std::move(Map);
      return;
    }
    if (CurrentLVarMap.sameAs(Map))
      return;  // Easy merge: maps from different predecessors are unchanged.
  
    unsigned NPreds = CurrentBB->numPredecessors();
    unsigned ESz = CurrentLVarMap.size();
    unsigned MSz = Map.size();
    unsigned Sz  = std::min(ESz, MSz);
  
    for (unsigned i=0; i<Sz; ++i) {
      if (CurrentLVarMap[i].first != Map[i].first) {
        // We've reached the end of variables in common.
        CurrentLVarMap.makeWritable();
        CurrentLVarMap.downsize(i);
        break;
      }
      if (CurrentLVarMap[i].second != Map[i].second)
        makePhiNodeVar(i, NPreds, Map[i].second);
    }
    if (ESz > MSz) {
      CurrentLVarMap.makeWritable();
      CurrentLVarMap.downsize(Map.size());
    }
  }
  
  
  // Merge a back edge into the current variable map.
  // This will create phi nodes for all variables in the variable map.
  void SExprBuilder::mergeEntryMapBackEdge() {
    // We don't have definitions for variables on the backedge, because we
    // haven't gotten that far in the CFG.  Thus, when encountering a back edge,
    // we conservatively create Phi nodes for all variables.  Unnecessary Phi
    // nodes will be marked as incomplete, and stripped out at the end.
    //
    // An Phi node is unnecessary if it only refers to itself and one other
    // variable, e.g. x = Phi(y, y, x)  can be reduced to x = y.
  
    assert(CurrentBlockInfo && "Not processing a block!");
  
    if (CurrentBlockInfo->HasBackEdges)
      return;
    CurrentBlockInfo->HasBackEdges = true;
  
    CurrentLVarMap.makeWritable();
    unsigned Sz = CurrentLVarMap.size();
    unsigned NPreds = CurrentBB->numPredecessors();
  
    for (unsigned i=0; i < Sz; ++i) {
      makePhiNodeVar(i, NPreds, nullptr);
    }
  }
  
  
  // Update the phi nodes that were initially created for a back edge
  // once the variable definitions have been computed.
  // I.e., merge the current variable map into the phi nodes for Blk.
  void SExprBuilder::mergePhiNodesBackEdge(const CFGBlock *Blk) {
    til::BasicBlock *BB = lookupBlock(Blk);
    unsigned ArgIndex = BBInfo[Blk->getBlockID()].ProcessedPredecessors;
    assert(ArgIndex > 0 && ArgIndex < BB->numPredecessors());
  
    for (til::SExpr *PE : BB->arguments()) {
      til::Phi *Ph = dyn_cast_or_null<til::Phi>(PE);
      assert(Ph && "Expecting Phi Node.");
      assert(Ph->values()[ArgIndex] == nullptr && "Wrong index for back edge.");
  
      til::SExpr *E = lookupVarDecl(Ph->clangDecl());
      assert(E && "Couldn't find local variable for Phi node.");
      Ph->values()[ArgIndex] = E;
    }
  }
  
  void SExprBuilder::enterCFG(CFG *Cfg, const NamedDecl *D,
                              const CFGBlock *First) {
    // Perform initial setup operations.
    unsigned NBlocks = Cfg->getNumBlockIDs();
    Scfg = new (Arena) til::SCFG(Arena, NBlocks);
  
    // allocate all basic blocks immediately, to handle forward references.
    BBInfo.resize(NBlocks);
    BlockMap.resize(NBlocks, nullptr);
    // create map from clang blockID to til::BasicBlocks
    for (auto *B : *Cfg) {
      auto *BB = new (Arena) til::BasicBlock(Arena);
      BB->reserveInstructions(B->size());
      BlockMap[B->getBlockID()] = BB;
    }
  
    CurrentBB = lookupBlock(&Cfg->getEntry());
    auto Parms = isa<ObjCMethodDecl>(D) ? cast<ObjCMethodDecl>(D)->parameters()
                                        : cast<FunctionDecl>(D)->parameters();
    for (auto *Pm : Parms) {
      QualType T = Pm->getType();
      if (!T.isTrivialType(Pm->getASTContext()))
        continue;
  
      // Add parameters to local variable map.
      // FIXME: right now we emulate params with loads; that should be fixed.
      til::SExpr *Lp = new (Arena) til::LiteralPtr(Pm);
      til::SExpr *Ld = new (Arena) til::Load(Lp);
      til::SExpr *V  = addStatement(Ld, nullptr, Pm);
      addVarDecl(Pm, V);
    }
  }
  
  
  void SExprBuilder::enterCFGBlock(const CFGBlock *B) {
    // Intialize TIL basic block and add it to the CFG.
    CurrentBB = lookupBlock(B);
    CurrentBB->reservePredecessors(B->pred_size());
    Scfg->add(CurrentBB);
  
    CurrentBlockInfo = &BBInfo[B->getBlockID()];
  
    // CurrentLVarMap is moved to ExitMap on block exit.
    // FIXME: the entry block will hold function parameters.
    // assert(!CurrentLVarMap.valid() && "CurrentLVarMap already initialized.");
  }
  
  
  void SExprBuilder::handlePredecessor(const CFGBlock *Pred) {
    // Compute CurrentLVarMap on entry from ExitMaps of predecessors
  
    CurrentBB->addPredecessor(BlockMap[Pred->getBlockID()]);
    BlockInfo *PredInfo = &BBInfo[Pred->getBlockID()];
    assert(PredInfo->UnprocessedSuccessors > 0);
  
    if (--PredInfo->UnprocessedSuccessors == 0)
      mergeEntryMap(std::move(PredInfo->ExitMap));
    else
      mergeEntryMap(PredInfo->ExitMap.clone());
  
    ++CurrentBlockInfo->ProcessedPredecessors;
  }
  
  
  void SExprBuilder::handlePredecessorBackEdge(const CFGBlock *Pred) {
    mergeEntryMapBackEdge();
  }
  
  
  void SExprBuilder::enterCFGBlockBody(const CFGBlock *B) {
    // The merge*() methods have created arguments.
    // Push those arguments onto the basic block.
    CurrentBB->arguments().reserve(
      static_cast<unsigned>(CurrentArguments.size()), Arena);
    for (auto *A : CurrentArguments)
      CurrentBB->addArgument(A);
  }
  
  
  void SExprBuilder::handleStatement(const Stmt *S) {
    til::SExpr *E = translate(S, nullptr);
    addStatement(E, S);
  }
  
  
  void SExprBuilder::handleDestructorCall(const VarDecl *VD,
                                          const CXXDestructorDecl *DD) {
    til::SExpr *Sf = new (Arena) til::LiteralPtr(VD);
    til::SExpr *Dr = new (Arena) til::LiteralPtr(DD);
    til::SExpr *Ap = new (Arena) til::Apply(Dr, Sf);
    til::SExpr *E = new (Arena) til::Call(Ap);
    addStatement(E, nullptr);
  }
  
  
  
  void SExprBuilder::exitCFGBlockBody(const CFGBlock *B) {
    CurrentBB->instructions().reserve(
      static_cast<unsigned>(CurrentInstructions.size()), Arena);
    for (auto *V : CurrentInstructions)
      CurrentBB->addInstruction(V);
  
    // Create an appropriate terminator
    unsigned N = B->succ_size();
    auto It = B->succ_begin();
    if (N == 1) {
      til::BasicBlock *BB = *It ? lookupBlock(*It) : nullptr;
      // TODO: set index
      unsigned Idx = BB ? BB->findPredecessorIndex(CurrentBB) : 0;
      auto *Tm = new (Arena) til::Goto(BB, Idx);
      CurrentBB->setTerminator(Tm);
    }
    else if (N == 2) {
      til::SExpr *C = translate(B->getTerminatorCondition(true), nullptr);
      til::BasicBlock *BB1 = *It ? lookupBlock(*It) : nullptr;
      ++It;
      til::BasicBlock *BB2 = *It ? lookupBlock(*It) : nullptr;
      // FIXME: make sure these arent' critical edges.
      auto *Tm = new (Arena) til::Branch(C, BB1, BB2);
      CurrentBB->setTerminator(Tm);
    }
  }
  
  
  void SExprBuilder::handleSuccessor(const CFGBlock *Succ) {
    ++CurrentBlockInfo->UnprocessedSuccessors;
  }
  
  
  void SExprBuilder::handleSuccessorBackEdge(const CFGBlock *Succ) {
    mergePhiNodesBackEdge(Succ);
    ++BBInfo[Succ->getBlockID()].ProcessedPredecessors;
  }
  
  
  void SExprBuilder::exitCFGBlock(const CFGBlock *B) {
    CurrentArguments.clear();
    CurrentInstructions.clear();
    CurrentBlockInfo->ExitMap = std::move(CurrentLVarMap);
    CurrentBB = nullptr;
    CurrentBlockInfo = nullptr;
  }
  
  
  void SExprBuilder::exitCFG(const CFGBlock *Last) {
    for (auto *Ph : IncompleteArgs) {
      if (Ph->status() == til::Phi::PH_Incomplete)
        simplifyIncompleteArg(Ph);
    }
  
    CurrentArguments.clear();
    CurrentInstructions.clear();
    IncompleteArgs.clear();
  }
  
  
  /*
  void printSCFG(CFGWalker &Walker) {
    llvm::BumpPtrAllocator Bpa;
    til::MemRegionRef Arena(&Bpa);
    SExprBuilder SxBuilder(Arena);
    til::SCFG *Scfg = SxBuilder.buildCFG(Walker);
    TILPrinter::print(Scfg, llvm::errs());
  }
  */
  