r208830 - Thread Safety Analysis: add new node types to thread safety TIL.

DeLesley Hutchins delesley at google.com
Wed May 14 17:50:36 PDT 2014


Author: delesley
Date: Wed May 14 19:50:36 2014
New Revision: 208830

URL: http://llvm.org/viewvc/llvm-project?rev=208830&view=rev
Log:
Thread Safety Analysis: add new node types to thread safety TIL.
This fills in a few missing gaps in functionality.

Added:
    cfe/trunk/lib/Analysis/ThreadSafetyTIL.cpp
Modified:
    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/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h
    cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyUtil.h
    cfe/trunk/lib/Analysis/CMakeLists.txt
    cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp

Modified: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h?rev=208830&r1=208829&r2=208830&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h Wed May 14 19:50:36 2014
@@ -238,7 +238,8 @@ public:
       : Arena(A), SelfVar(nullptr), Scfg(nullptr), CurrentBB(nullptr),
         CurrentBlockInfo(nullptr) {
     // FIXME: we don't always have a self-variable.
-    SelfVar = new (Arena) til::Variable(til::Variable::VK_SFun);
+    SelfVar = new (Arena) til::Variable();
+    SelfVar->setKind(til::Variable::VK_SFun);
   }
 
   // Translate a clang statement or expression to a TIL expression.
@@ -268,9 +269,12 @@ private:
                                            CallingContext *Ctx);
   til::SExpr *translateUnaryOperator(const UnaryOperator *UO,
                                      CallingContext *Ctx);
+  til::SExpr *translateBinOp(til::TIL_BinaryOpcode Op,
+                             const BinaryOperator *BO,
+                             CallingContext *Ctx, bool Reverse = false);
   til::SExpr *translateBinAssign(til::TIL_BinaryOpcode Op,
                                  const BinaryOperator *BO,
-                                 CallingContext *Ctx);
+                                 CallingContext *Ctx, bool Assign = false);
   til::SExpr *translateBinaryOperator(const BinaryOperator *BO,
                                       CallingContext *Ctx);
   til::SExpr *translateCastExpr(const CastExpr *CE, CallingContext *Ctx);

Modified: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyOps.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyOps.def?rev=208830&r1=208829&r2=208830&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyOps.def (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyOps.def Wed May 14 19:50:36 2014
@@ -24,6 +24,7 @@ TIL_OPCODE_DEF(Variable)
 TIL_OPCODE_DEF(Function)
 TIL_OPCODE_DEF(SFunction)
 TIL_OPCODE_DEF(Code)
+TIL_OPCODE_DEF(Field)
 
 TIL_OPCODE_DEF(Apply)
 TIL_OPCODE_DEF(SApply)
@@ -44,3 +45,9 @@ TIL_OPCODE_DEF(SCFG)
 TIL_OPCODE_DEF(Phi)
 TIL_OPCODE_DEF(Goto)
 TIL_OPCODE_DEF(Branch)
+
+// psuedo-terms
+TIL_OPCODE_DEF(Identifier)
+TIL_OPCODE_DEF(IfThenElse)
+TIL_OPCODE_DEF(Let)
+

Modified: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h?rev=208830&r1=208829&r2=208830&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h Wed May 14 19:50:36 2014
@@ -3,13 +3,17 @@
 //                     The LLVM Compiler Infrastructure
 //
 // This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// License. See LICENSE.TXT in the llvm repository 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.
+// This file defines a simple Typed Intermediate Language, or TIL, that is used
+// by the thread safety analysis (See ThreadSafety.cpp).  The TIL is intended
+// to be largely independent of clang, in the hope that the analysis can be
+// reused for other non-C++ languages.  All dependencies on clang/llvm should
+// go in ThreadSafetyUtil.h.
+//
+// Thread safety analysis works by comparing mutex expressions, e.g.
 //
 // class A { Mutex mu; int dat GUARDED_BY(this->mu); }
 // class B { A a; }
@@ -31,7 +35,7 @@
 // (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 TIL 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.
@@ -43,11 +47,11 @@
 #ifndef LLVM_CLANG_THREAD_SAFETY_TIL_H
 #define LLVM_CLANG_THREAD_SAFETY_TIL_H
 
-#include "clang/Analysis/Analyses/ThreadSafetyUtil.h"
-#include "clang/AST/ExprCXX.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Compiler.h"
+// All clang include dependencies for this file must be put in
+// ThreadSafetyUtil.h.
+#include "ThreadSafetyUtil.h"
 
+#include <stdint.h>
 #include <cassert>
 #include <cstddef>
 #include <utility>
@@ -57,21 +61,189 @@ namespace clang {
 namespace threadSafety {
 namespace til {
 
-using llvm::StringRef;
-using clang::SourceLocation;
-
 
 enum TIL_Opcode {
 #define TIL_OPCODE_DEF(X) COP_##X,
-#include "clang/Analysis/Analyses/ThreadSafetyOps.def"
+#include "ThreadSafetyOps.def"
 #undef TIL_OPCODE_DEF
-  COP_MAX
 };
 
+enum TIL_UnaryOpcode : unsigned char {
+  UOP_Minus,        //  -
+  UOP_BitNot,       //  ~
+  UOP_LogicNot      //  !
+};
+
+enum TIL_BinaryOpcode : unsigned char {
+  BOP_Mul,          //  *
+  BOP_Div,          //  /
+  BOP_Rem,          //  %
+  BOP_Add,          //  +
+  BOP_Sub,          //  -
+  BOP_Shl,          //  <<
+  BOP_Shr,          //  >>
+  BOP_BitAnd,       //  &
+  BOP_BitXor,       //  ^
+  BOP_BitOr,        //  |
+  BOP_Eq,           //  ==
+  BOP_Neq,          //  !=
+  BOP_Lt,           //  <
+  BOP_Leq,          //  <=
+  BOP_LogicAnd,     //  &&
+  BOP_LogicOr       //  ||
+};
+
+enum TIL_CastOpcode : unsigned char {
+  CAST_none = 0,
+  CAST_extendNum,   // extend precision of numeric type
+  CAST_truncNum,    // truncate precision of numeric type
+  CAST_toFloat,     // convert to floating point type
+  CAST_toInt,       // convert to integer type
+};
+
+const TIL_Opcode       COP_Min  = COP_Future;
+const TIL_Opcode       COP_Max  = COP_Branch;
+const TIL_UnaryOpcode  UOP_Min  = UOP_Minus;
+const TIL_UnaryOpcode  UOP_Max  = UOP_LogicNot;
+const TIL_BinaryOpcode BOP_Min  = BOP_Mul;
+const TIL_BinaryOpcode BOP_Max  = BOP_LogicOr;
+const TIL_CastOpcode   CAST_Min = CAST_none;
+const TIL_CastOpcode   CAST_Max = CAST_toInt;
+
+StringRef getUnaryOpcodeString(TIL_UnaryOpcode Op);
+StringRef getBinaryOpcodeString(TIL_BinaryOpcode Op);
+
+
+// ValueTypes are data types that can actually be held in registers.
+// All variables and expressions must have a vBNF_Nonealue type.
+// Pointer types are further subdivided into the various heap-allocated
+// types, such as functions, records, etc.
+// Structured types that are passed by value (e.g. complex numbers)
+// require special handling; they use BT_ValueRef, and size ST_0.
+struct ValueType {
+  enum BaseType : unsigned char {
+    BT_Void = 0,
+    BT_Bool,
+    BT_Int,
+    BT_Float,
+    BT_String,    // String literals
+    BT_Pointer,
+    BT_ValueRef
+  };
+
+  enum SizeType : unsigned char {
+    ST_0 = 0,
+    ST_1,
+    ST_8,
+    ST_16,
+    ST_32,
+    ST_64,
+    ST_128
+  };
+
+  inline static SizeType getSizeType(unsigned nbytes);
+
+  template <class T>
+  inline static ValueType getValueType();
+
+  ValueType(BaseType B, SizeType Sz, bool S, unsigned char VS)
+      : Base(B), Size(Sz), Signed(S), VectSize(VS)
+  { }
+
+  BaseType      Base;
+  SizeType      Size;
+  bool          Signed;
+  unsigned char VectSize;  // 0 for scalar, otherwise num elements in vector
+};
+
+
+inline ValueType::SizeType ValueType::getSizeType(unsigned nbytes) {
+  switch (nbytes) {
+    case 1: return ST_8;
+    case 2: return ST_16;
+    case 4: return ST_32;
+    case 8: return ST_64;
+    case 16: return ST_128;
+    default: return ST_0;
+  }
+}
+
+
+template<>
+inline ValueType ValueType::getValueType<void>() {
+  return ValueType(BT_Void, ST_0, false, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<bool>() {
+  return ValueType(BT_Bool, ST_1, false, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<int8_t>() {
+  return ValueType(BT_Int, ST_8, true, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<uint8_t>() {
+  return ValueType(BT_Int, ST_8, false, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<int16_t>() {
+  return ValueType(BT_Int, ST_16, true, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<uint16_t>() {
+  return ValueType(BT_Int, ST_16, false, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<int32_t>() {
+  return ValueType(BT_Int, ST_32, true, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<uint32_t>() {
+  return ValueType(BT_Int, ST_32, false, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<int64_t>() {
+  return ValueType(BT_Int, ST_64, true, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<uint64_t>() {
+  return ValueType(BT_Int, ST_64, false, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<float>() {
+  return ValueType(BT_Float, ST_32, true, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<double>() {
+  return ValueType(BT_Float, ST_64, true, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<long double>() {
+  return ValueType(BT_Float, ST_128, true, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<StringRef>() {
+  return ValueType(BT_Pointer, getSizeType(sizeof(StringRef)), false, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<void*>() {
+  return ValueType(BT_Pointer, getSizeType(sizeof(void*)), false, 0);
+}
 
-typedef clang::BinaryOperatorKind TIL_BinaryOpcode;
-typedef clang::UnaryOperatorKind TIL_UnaryOpcode;
-typedef clang::CastKind TIL_CastOpcode;
 
 
 enum TraversalKind {
@@ -100,7 +272,7 @@ public:
   //   compare all subexpressions, following the comparator interface
   // }
 
-  void *operator new(size_t S, clang::threadSafety::til::MemRegionRef &R) {
+  void *operator new(size_t S, MemRegionRef &R) {
     return ::operator new(S, R);
   }
 
@@ -149,10 +321,10 @@ public:
 
   bool operator==(const SExprRef &R) const { return Ptr == R.Ptr; }
   bool operator!=(const SExprRef &R) const { return !operator==(R); }
-  bool operator==(const SExpr *P) const { return Ptr == P; }
-  bool operator!=(const SExpr *P) const { return !operator==(P); }
-  bool operator==(std::nullptr_t) const { return Ptr == nullptr; }
-  bool operator!=(std::nullptr_t) const { return Ptr != nullptr; }
+  bool operator==(const SExpr *P)    const { return Ptr == P; }
+  bool operator!=(const SExpr *P)    const { return !operator==(P); }
+  bool operator==(std::nullptr_t)    const { return Ptr == nullptr; }
+  bool operator!=(std::nullptr_t)    const { return Ptr != nullptr; }
 
   inline void reset(SExpr *E);
 
@@ -172,9 +344,11 @@ namespace ThreadSafetyTIL {
   }
 }
 
+// Nodes which declare variables
 class Function;
 class SFunction;
 class BasicBlock;
+class Let;
 
 
 // A named variable, e.g. "x".
@@ -201,14 +375,13 @@ public:
   };
 
   // These are defined after SExprRef contructor, below
-  inline Variable(VariableKind K, SExpr *D = nullptr,
-                  const clang::ValueDecl *Cvd = nullptr);
+  inline Variable(StringRef s, SExpr *D = nullptr);
   inline Variable(SExpr *D = nullptr, const clang::ValueDecl *Cvd = nullptr);
   inline Variable(const Variable &Vd, SExpr *D);
 
   VariableKind kind() const { return static_cast<VariableKind>(Flags); }
 
-  const StringRef name() const { return Cvdecl ? Cvdecl->getName() : "_x"; }
+  const StringRef name() const { return Name; }
   const clang::ValueDecl *clangDecl() const { return Cvdecl; }
 
   // Returns the definition (for let vars) or type (for parameter & self vars)
@@ -227,6 +400,7 @@ public:
   }
   void setClangDecl(const clang::ValueDecl *VD) { Cvdecl = VD; }
   void setDefinition(SExpr *E);
+  void setKind(VariableKind K) { Flags = K; }
 
   template <class V> typename V::R_SExpr traverse(V &Visitor) {
     // This routine is only called for variable references.
@@ -241,11 +415,10 @@ private:
   friend class Function;
   friend class SFunction;
   friend class BasicBlock;
+  friend class Let;
 
-  // Function, SFunction, and BasicBlock will reset the kind.
-  void setKind(VariableKind K) { Flags = K; }
-
-  SExprRef Definition;             // The TIL type or definition
+  StringRef Name;                  // The name of the variable.
+  SExprRef  Definition;            // The TIL type or definition
   const clang::ValueDecl *Cvdecl;  // The clang declaration for this variable.
 
   unsigned short BlockID;
@@ -355,20 +528,20 @@ inline void SExprRef::reset(SExpr *P) {
 }
 
 
-inline Variable::Variable(VariableKind K, SExpr *D, const clang::ValueDecl *Cvd)
-    : SExpr(COP_Variable), Definition(D), Cvdecl(Cvd),
-      BlockID(0), Id(0),  NumUses(0) {
-  Flags = K;
+inline Variable::Variable(StringRef s, SExpr *D)
+    : SExpr(COP_Variable), Name(s), Definition(D), Cvdecl(nullptr),
+      BlockID(0), Id(0), NumUses(0) {
+  Flags = VK_Let;
 }
 
 inline Variable::Variable(SExpr *D, const clang::ValueDecl *Cvd)
-    : SExpr(COP_Variable), Definition(D), Cvdecl(Cvd),
-      BlockID(0), Id(0),  NumUses(0) {
+    : SExpr(COP_Variable), Name(Cvd ? Cvd->getName() : "_x"),
+      Definition(D), Cvdecl(Cvd), BlockID(0), Id(0), NumUses(0) {
   Flags = VK_Let;
 }
 
 inline Variable::Variable(const Variable &Vd, SExpr *D) // rewrite constructor
-    : SExpr(Vd), Definition(D), Cvdecl(Vd.Cvdecl),
+    : SExpr(Vd), Name(Vd.Name), Definition(D), Cvdecl(Vd.Cvdecl),
       BlockID(0), Id(0), NumUses(0) {
   Flags = Vd.kind();
 }
@@ -431,8 +604,11 @@ 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) {}
+  Literal(const clang::Expr *C)
+     : SExpr(COP_Literal), ValType(ValueType::getValueType<void>())
+  { }
+  Literal(ValueType VT) : SExpr(COP_Literal), ValType(VT) {}
+  Literal(const Literal &L) : SExpr(L), ValType(L.ValType), Cexpr(L.Cexpr) {}
 
   // The clang expression for this literal.
   const clang::Expr *clangExpr() const { return Cexpr; }
@@ -447,9 +623,26 @@ public:
   }
 
 private:
+  ValueType ValType;
   const clang::Expr *Cexpr;
 };
 
+
+// Derived class for literal values, which stores the actual value.
+template<class T>
+class LiteralT : public Literal {
+public:
+  LiteralT(T Dat) : Literal(ValueType::getValueType<T>()), Val(Dat) { }
+  LiteralT(const LiteralT<T> &L) : Literal(L), Val(L.Val) { }
+
+  T  value() const { return Val;}
+  T& value() { return Val; }
+
+private:
+  T Val;
+};
+
+
 // Literal pointer to an object allocated in memory.
 // At compile time, pointer literals are represented by symbolic names.
 class LiteralPtr : public SExpr {
@@ -474,6 +667,7 @@ private:
   const clang::ValueDecl *Cvdecl;
 };
 
+
 // 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)))
@@ -607,6 +801,40 @@ private:
 };
 
 
+// A typed, writable location in memory
+class Field : public SExpr {
+public:
+  static bool classof(const SExpr *E) { return E->opcode() == COP_Field; }
+
+  Field(SExpr *R, SExpr *B) : SExpr(COP_Field), Range(R), Body(B) {}
+  Field(const Field &C, SExpr *R, SExpr *B) // rewrite constructor
+      : SExpr(C), Range(R), Body(B) {}
+
+  SExpr *range() { return Range.get(); }
+  const SExpr *range() const { return Range.get(); }
+
+  SExpr *body() { return Body.get(); }
+  const SExpr *body() const { return Body.get(); }
+
+  template <class V> typename V::R_SExpr traverse(V &Visitor) {
+    typename V::R_SExpr Nr = Visitor.traverse(Range, TRV_Lazy);
+    typename V::R_SExpr Nb = Visitor.traverse(Body,  TRV_Lazy);
+    return Visitor.reduceField(*this, Nr, Nb);
+  }
+
+  template <class C> typename C::CType compare(Field* E, C& Cmp) {
+    typename C::CType Ct = Cmp.compare(range(), E->range());
+    if (Cmp.notTrue(Ct))
+      return Ct;
+    return Cmp.compare(body(), E->body());
+  }
+
+private:
+  SExprRef Range;
+  SExprRef Body;
+};
+
+
 // Apply an argument to a function
 class Apply : public SExpr {
 public:
@@ -683,9 +911,15 @@ class Project : public SExpr {
 public:
   static bool classof(const SExpr *E) { return E->opcode() == COP_Project; }
 
+  Project(SExpr *R, StringRef SName)
+      : SExpr(COP_Project), Rec(R), SlotName(SName), Cvdecl(nullptr)
+  { }
   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(COP_Project), Rec(R), SlotName(Cvd->getName()), Cvdecl(Cvd)
+  { }
+  Project(const Project &P, SExpr *R)
+      : SExpr(P), Rec(R), SlotName(P.SlotName), Cvdecl(P.Cvdecl)
+  { }
 
   SExpr *record() { return Rec.get(); }
   const SExpr *record() const { return Rec.get(); }
@@ -708,6 +942,7 @@ public:
 
 private:
   SExprRef Rec;
+  StringRef SlotName;
   clang::ValueDecl *Cvdecl;
 };
 
@@ -1300,10 +1535,125 @@ private:
 };
 
 
-SExpr *getCanonicalVal(SExpr *E);
-void simplifyIncompleteArg(Variable *V, til::Phi *Ph);
+// An identifier, e.g. 'foo' or 'x'.
+// This is a pseduo-term; it will be lowered to a variable or projection.
+class Identifier : public SExpr {
+public:
+  static bool classof(const SExpr *E) { return E->opcode() == COP_Identifier; }
+
+  Identifier(StringRef Id): SExpr(COP_Identifier), Name(Id) { }
+  Identifier(const Identifier& I) : SExpr(I), Name(I.Name)  { }
+
+  StringRef name() const { return Name; }
+
+  template <class V> typename V::R_SExpr traverse(V &Visitor) {
+    return Visitor.reduceIdentifier(*this);
+  }
+
+  template <class C> typename C::CType compare(Identifier* E, C& Cmp) {
+    return Cmp.compareStrings(name(), E->name());
+  }
+
+private:
+  StringRef Name;
+};
+
+
+// An if-then-else expression.
+// This is a pseduo-term; it will be lowered to a CFG.
+class IfThenElse : public SExpr {
+public:
+  static bool classof(const SExpr *E) { return E->opcode() == COP_IfThenElse; }
+
+  IfThenElse(SExpr *C, SExpr *T, SExpr *E)
+    : SExpr(COP_IfThenElse), Condition(C), ThenExpr(T), ElseExpr(E)
+  { }
+  IfThenElse(const IfThenElse &I, SExpr *C, SExpr *T, SExpr *E)
+    : SExpr(I), Condition(C), ThenExpr(T), ElseExpr(E)
+  { }
+
+  SExpr *condition() { return Condition.get(); }   // Address to store to
+  const SExpr *condition() const { return Condition.get(); }
+
+  SExpr *thenExpr() { return ThenExpr.get(); }     // Value to store
+  const SExpr *thenExpr() const { return ThenExpr.get(); }
+
+  SExpr *elseExpr() { return ElseExpr.get(); }     // Value to store
+  const SExpr *elseExpr() const { return ElseExpr.get(); }
+
+  template <class V> typename V::R_SExpr traverse(V &Visitor) {
+    typename V::R_SExpr Nc = Visitor.traverse(Condition);
+    typename V::R_SExpr Nt = Visitor.traverse(ThenExpr);
+    typename V::R_SExpr Ne = Visitor.traverse(ElseExpr);
+    return Visitor.reduceIfThenElse(*this, Nc, Nt, Ne);
+  }
+
+  template <class C> typename C::CType compare(IfThenElse* E, C& Cmp) {
+    typename C::CType Ct = Cmp.compare(condition(), E->condition());
+    if (Cmp.notTrue(Ct))
+      return Ct;
+    Ct = Cmp.compare(thenExpr(), E->thenExpr());
+    if (Cmp.notTrue(Ct))
+      return Ct;
+    return Cmp.compare(elseExpr(), E->elseExpr());
+  }
+
+private:
+  SExprRef Condition;
+  SExprRef ThenExpr;
+  SExprRef ElseExpr;
+};
+
 
+// A let-expression,  e.g.  let x=t; u.
+// This is a pseduo-term; it will be lowered to a CFG.
+class Let : public SExpr {
+public:
+  static bool classof(const SExpr *E) { return E->opcode() == COP_Let; }
+
+  Let(Variable *Vd, SExpr *Bd) : SExpr(COP_Let), VarDecl(Vd), Body(Bd) {
+    Vd->setKind(Variable::VK_Let);
+  }
+  Let(const Let &L, Variable *Vd, SExpr *Bd) : SExpr(L), VarDecl(Vd), Body(Bd) {
+    Vd->setKind(Variable::VK_Let);
+  }
+
+  Variable *variableDecl()  { return VarDecl; }
+  const Variable *variableDecl() const { return VarDecl; }
+
+  SExpr *body() { return Body.get(); }
+  const SExpr *body() const { return Body.get(); }
 
+  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 let variable.
+    Variable *Nvd = Visitor.enterScope(*VarDecl, E0);
+    typename V::R_SExpr E1 = Visitor.traverse(Body);
+    Visitor.exitScope(*VarDecl);
+    return Visitor.reduceLet(*this, Nvd, E1);
+  }
+
+  template <class C> typename C::CType compare(Let* E, C& Cmp) {
+    typename C::CType Ct =
+      Cmp.compare(VarDecl->definition(), E->VarDecl->definition());
+    if (Cmp.notTrue(Ct))
+      return Ct;
+    Cmp.enterScope(variableDecl(), E->variableDecl());
+    Ct = Cmp.compare(body(), E->body());
+    Cmp.leaveScope();
+    return Ct;
+  }
+
+private:
+  Variable *VarDecl;
+  SExprRef Body;
+};
+
+
+
+SExpr *getCanonicalVal(SExpr *E);
+void simplifyIncompleteArg(Variable *V, til::Phi *Ph);
 
 
 } // end namespace til

Modified: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h?rev=208830&r1=208829&r2=208830&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h Wed May 14 19:50:36 2014
@@ -17,7 +17,7 @@
 #ifndef LLVM_CLANG_THREAD_SAFETY_TRAVERSE_H
 #define LLVM_CLANG_THREAD_SAFETY_TRAVERSE_H
 
-#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
+#include "ThreadSafetyTIL.h"
 
 namespace clang {
 namespace threadSafety {
@@ -72,10 +72,8 @@ public:
 #define TIL_OPCODE_DEF(X)                                                   \
     case COP_##X:                                                           \
       return self()->traverse##X(cast<X>(E));
-#include "clang/Analysis/Analyses/ThreadSafetyOps.def"
+#include "ThreadSafetyOps.def"
 #undef TIL_OPCODE_DEF
-    case COP_MAX:
-      return self()->reduceNull();
     }
   }
 
@@ -83,7 +81,7 @@ public:
 // 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"
+#include "ThreadSafetyOps.def"
 #undef TIL_OPCODE_DEF
 };
 
@@ -146,6 +144,9 @@ public:
   R_SExpr reduceCode(Code &Orig, R_SExpr E0, R_SExpr E1) {
     return new (Arena) Code(Orig, E0, E1);
   }
+  R_SExpr reduceField(Field &Orig, R_SExpr E0, R_SExpr E1) {
+    return new (Arena) Field(Orig, E0, E1);
+  }
 
   R_SExpr reduceApply(Apply &Orig, R_SExpr E0, R_SExpr E1) {
     return new (Arena) Apply(Orig, E0, E1);
@@ -198,6 +199,16 @@ public:
     return new (Arena) Branch(O, C, B0, B1);
   }
 
+  R_SExpr reduceIdentifier(Identifier &Orig) {
+    return new (Arena) Identifier(Orig);
+  }
+  R_SExpr reduceIfThenElse(IfThenElse &Orig, R_SExpr C, R_SExpr T, R_SExpr E) {
+    return new (Arena) IfThenElse(Orig, C, T, E);
+  }
+  R_SExpr reduceLet(Let &Orig, Variable *Nvd, R_SExpr B) {
+    return new (Arena) Let(Orig, Nvd, B);
+  }
+
   BasicBlock *reduceBasicBlock(BasicBlock &Orig, Container<Variable *> &As,
                                Container<Variable *> &Is, R_SExpr T) {
     return new (Arena) BasicBlock(Orig, std::move(As.Elems),
@@ -274,6 +285,9 @@ public:
   R_SExpr reduceCode(Code &Orig, R_SExpr E0, R_SExpr E1) {
     return E0 && E1;
   }
+  R_SExpr reduceField(Field &Orig, R_SExpr E0, R_SExpr E1) {
+    return E0 && E1;
+  }
   R_SExpr reduceApply(Apply &Orig, R_SExpr E0, R_SExpr E1) {
     return E0 && E1;
   }
@@ -308,6 +322,16 @@ public:
     return C;
   }
 
+  R_SExpr reduceIdentifier(Identifier &Orig) {
+    return true;
+  }
+  R_SExpr reduceIfThenElse(IfThenElse &Orig, R_SExpr C, R_SExpr T, R_SExpr E) {
+    return C && T && E;
+  }
+  R_SExpr reduceLet(Let &Orig, Variable *Nvd, R_SExpr B) {
+    return Nvd && B;
+  }
+
   BasicBlock *reduceBasicBlock(BasicBlock &Orig, Container<Variable *> &As,
                                Container<Variable *> &Is, R_SExpr T) {
     return (As.Success && Is.Success && T) ? &Orig : nullptr;
@@ -360,10 +384,8 @@ public:
 #define TIL_OPCODE_DEF(X)                                                     \
     case COP_##X:                                                             \
       return cast<X>(E1)->compare(cast<X>(E2), *self());
-#include "clang/Analysis/Analyses/ThreadSafetyOps.def"
+#include "ThreadSafetyOps.def"
 #undef TIL_OPCODE_DEF
-    case COP_MAX:
-      return false;
     }
   }
 };
@@ -379,7 +401,8 @@ public:
   CType trueResult() { return true; }
   bool notTrue(CType ct) { return !ct; }
 
-  bool compareIntegers(unsigned i, unsigned j) { return i == j; }
+  bool compareIntegers(unsigned i, unsigned j)       { return i == j; }
+  bool compareStrings (StringRef s, StringRef r)     { return s == r; }
   bool comparePointers(const void* P, const void* Q) { return P == Q; }
 
   bool compare(SExpr *E1, SExpr* E2) {
@@ -455,6 +478,7 @@ protected:
       case COP_Function:   return Prec_Decl;
       case COP_SFunction:  return Prec_Decl;
       case COP_Code:       return Prec_Decl;
+      case COP_Field:      return Prec_Decl;
 
       case COP_Apply:      return Prec_Postfix;
       case COP_SApply:     return Prec_Postfix;
@@ -475,7 +499,10 @@ protected:
       case COP_Phi:        return Prec_Atom;
       case COP_Goto:       return Prec_Atom;
       case COP_Branch:     return Prec_Atom;
-      case COP_MAX:        return Prec_MAX;
+
+      case COP_Identifier: return Prec_Atom;
+      case COP_IfThenElse: return Prec_Other;
+      case COP_Let:        return Prec_Decl;
     }
     return Prec_MAX;
   }
@@ -498,10 +525,8 @@ protected:
     case COP_##X:                                                          \
       self()->print##X(cast<X>(E), SS);                                    \
       return;
-#include "clang/Analysis/Analyses/ThreadSafetyOps.def"
+#include "ThreadSafetyOps.def"
 #undef TIL_OPCODE_DEF
-    case COP_MAX:
-      return;
     }
   }
 
@@ -522,25 +547,7 @@ protected:
   }
 
   void printLiteral(Literal *E, StreamType &SS) {
-    const clang::Expr *CE = E->clangExpr();
-    switch (CE->getStmtClass()) {
-      case Stmt::IntegerLiteralClass:
-        SS << cast<IntegerLiteral>(CE)->getValue().toString(10, true);
-        return;
-      case Stmt::StringLiteralClass:
-        SS << "\"" << cast<StringLiteral>(CE)->getString() << "\"";
-        return;
-      case Stmt::CharacterLiteralClass:
-      case Stmt::CXXNullPtrLiteralExprClass:
-      case Stmt::GNUNullExprClass:
-      case Stmt::CXXBoolLiteralExprClass:
-      case Stmt::FloatingLiteralClass:
-      case Stmt::ImaginaryLiteralClass:
-      case Stmt::ObjCStringLiteralClass:
-      default:
-        SS << "#lit";
-        return;
-    }
+    SS << getSourceLiteralString(E->clangExpr());
   }
 
   void printLiteralPtr(LiteralPtr *E, StreamType &SS) {
@@ -596,6 +603,13 @@ protected:
   void printCode(Code *E, StreamType &SS) {
     SS << ": ";
     self()->printSExpr(E->returnType(), SS, Prec_Decl-1);
+    SS << " -> ";
+    self()->printSExpr(E->body(), SS, Prec_Decl);
+  }
+
+  void printField(Field *E, StreamType &SS) {
+    SS << ": ";
+    self()->printSExpr(E->range(), SS, Prec_Decl-1);
     SS << " = ";
     self()->printSExpr(E->body(), SS, Prec_Decl);
   }
@@ -659,7 +673,7 @@ protected:
 
   void printArrayFirst(ArrayFirst *E, StreamType &SS) {
     self()->printSExpr(E->array(), SS, Prec_Postfix);
-    if (ArrayAdd *A = dyn_cast_or_null<ArrayAdd>(E)) {
+    if (ArrayAdd *A = dyn_cast_or_null<ArrayAdd>(E->array())) {
       SS << "[";
       printSExpr(A->index(), SS, Prec_MAX);
       SS << "]";
@@ -675,17 +689,18 @@ protected:
   }
 
   void printUnaryOp(UnaryOp *E, StreamType &SS) {
+    SS << getUnaryOpcodeString(E->unaryOpcode());
     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()) << " ";
+    SS << " " << getBinaryOpcodeString(E->binaryOpcode()) << " ";
     self()->printSExpr(E->expr1(), SS, Prec_Binary-1);
   }
 
   void printCast(Cast *E, StreamType &SS) {
-    SS << "~";
+    SS << "%";
     self()->printSExpr(E->expr(), SS, Prec_Unary);
   }
 
@@ -752,6 +767,28 @@ protected:
     SS << " ";
     printBlockLabel(SS, E->elseBlock(), E->elseIndex());
   }
+
+  void printIdentifier(Identifier *E, StreamType &SS) {
+    SS << "$" << E->name();
+  }
+
+  void printIfThenElse(IfThenElse *E, StreamType &SS) {
+    SS << "if (";
+    printSExpr(E->condition(), SS, Prec_MAX);
+    SS << ") then ";
+    printSExpr(E->thenExpr(), SS, Prec_Other);
+    SS << " else ";
+    printSExpr(E->elseExpr(), SS, Prec_Other);
+  }
+
+  void printLet(Let *E, StreamType &SS) {
+    SS << "let ";
+    printVariable(E->variableDecl(), SS, true);
+    SS << " = ";
+    printSExpr(E->variableDecl()->definition(), SS, Prec_Decl-1);
+    SS << ";";
+    printSExpr(E->body(), SS, Prec_Decl-1);
+  }
 };
 
 

Modified: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyUtil.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyUtil.h?rev=208830&r1=208829&r2=208830&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyUtil.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyUtil.h Wed May 14 19:50:36 2014
@@ -17,6 +17,8 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/AlignOf.h"
 #include "llvm/Support/Allocator.h"
+#include "llvm/Support/Compiler.h"
+#include "clang/AST/ExprCXX.h"
 
 #include <cassert>
 #include <cstddef>
@@ -70,9 +72,14 @@ inline void *operator new(size_t Sz,
 
 namespace clang {
 namespace threadSafety {
-namespace til {
+
+std::string getSourceLiteralString(const clang::Expr *CE);
 
 using llvm::StringRef;
+using clang::SourceLocation;
+
+namespace til {
+
 
 // A simple fixed size array class that does not manage its own memory,
 // suitable for use with bump pointer allocation.
@@ -163,7 +170,7 @@ private:
   size_t Capacity;
 };
 
-} // end namespace til
+}  // end namespace til
 
 
 // A copy on write vector.

Modified: cfe/trunk/lib/Analysis/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CMakeLists.txt?rev=208830&r1=208829&r2=208830&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CMakeLists.txt (original)
+++ cfe/trunk/lib/Analysis/CMakeLists.txt Wed May 14 19:50:36 2014
@@ -25,6 +25,7 @@ add_clang_library(clangAnalysis
   ThreadSafety.cpp
   ThreadSafetyCommon.cpp
   ThreadSafetyLogical.cpp
+  ThreadSafetyTIL.cpp
   UninitializedValues.cpp
 
   LINK_LIBS

Modified: cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp?rev=208830&r1=208829&r2=208830&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp (original)
+++ cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp Wed May 14 19:50:36 2014
@@ -37,65 +37,30 @@
 namespace clang {
 namespace threadSafety {
 
-namespace til {
-
-// If E is a variable, then trace back through any aliases or redundant
-// Phi nodes to find the canonical definition.
-SExpr *getCanonicalVal(SExpr *E) {
-  while (auto *V = dyn_cast<Variable>(E)) {
-    SExpr *D;
-    do {
-      if (V->kind() != Variable::VK_Let)
-        return V;
-      D = V->definition();
-      auto *V2 = dyn_cast<Variable>(D);
-      if (V2)
-        V = V2;
-      else
-        break;
-    } while (true);
-
-    if (ThreadSafetyTIL::isTrivial(D))
-      return D;
-
-    if (Phi *Ph = dyn_cast<Phi>(D)) {
-      if (Ph->status() == Phi::PH_Incomplete)
-        simplifyIncompleteArg(V, Ph);
-
-      if (Ph->status() == Phi::PH_SingleVal) {
-        E = Ph->values()[0];
-        continue;
-      }
+// From ThreadSafetyUtil.h
+std::string 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;
     }
-    return V;
+    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 E;
-}
-
-
-// Trace the arguments of an incomplete Phi node to see if they have the same
-// canonical definition.  If so, mark the Phi node as redundant.
-// getCanonicalVal() will recursively call simplifyIncompletePhi().
-void simplifyIncompleteArg(Variable *V, til::Phi *Ph) {
-  assert(Ph && Ph->status() == Phi::PH_Incomplete);
-
-  // eliminate infinite recursion -- assume that this node is not redundant.
-  Ph->setStatus(Phi::PH_MultiVal);
-
-  SExpr *E0 = getCanonicalVal(Ph->values()[0]);
-  for (unsigned i=1, n=Ph->values().size(); i<n; ++i) {
-    SExpr *Ei = getCanonicalVal(Ph->values()[i]);
-    if (Ei == V)
-      continue;  // Recursive reference to itself.  Don't count.
-    if (Ei != E0) {
-      return;    // Status is already set to MultiVal.
-    }
-  }
-  Ph->setStatus(Phi::PH_SingleVal);
-  // Eliminate Redundant Phi node.
-  V->setDefinition(Ph->values()[0]);
 }
 
+namespace til {
 
 // Return true if E is a variable that points to an incomplete Phi node.
 static bool isIncompleteVar(const SExpr *E) {
@@ -106,7 +71,6 @@ static bool isIncompleteVar(const SExpr
   return false;
 }
 
-
 }  // end namespace til
 
 
@@ -281,21 +245,41 @@ til::SExpr *SExprBuilder::translateUnary
     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::UnaryOp(UO->getOpcode(), translate(UO->getSubExpr(), Ctx));
+    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) {
+                                             CallingContext *Ctx,
+                                             bool Assign) {
   const Expr *LHS = BO->getLHS();
   const Expr *RHS = BO->getRHS();
   til::SExpr *E0 = translate(LHS, Ctx);
@@ -308,7 +292,7 @@ til::SExpr *SExprBuilder::translateBinAs
     CV = lookupVarDecl(VD);
   }
 
-  if (Op != BO_Assign) {
+  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);
@@ -326,39 +310,36 @@ til::SExpr *SExprBuilder::translateBinar
   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:
-    return new (Arena)
-        til::BinaryOp(BO->getOpcode(), translate(BO->getLHS(), Ctx),
-                      translate(BO->getRHS(), Ctx));
-
-  case BO_Assign:    return translateBinAssign(BO_Assign, BO, Ctx);
-  case BO_MulAssign: return translateBinAssign(BO_Mul, BO, Ctx);
-  case BO_DivAssign: return translateBinAssign(BO_Div, BO, Ctx);
-  case BO_RemAssign: return translateBinAssign(BO_Rem, BO, Ctx);
-  case BO_AddAssign: return translateBinAssign(BO_Add, BO, Ctx);
-  case BO_SubAssign: return translateBinAssign(BO_Sub, BO, Ctx);
-  case BO_ShlAssign: return translateBinAssign(BO_Shl, BO, Ctx);
-  case BO_ShrAssign: return translateBinAssign(BO_Shr, BO, Ctx);
-  case BO_AndAssign: return translateBinAssign(BO_And, BO, Ctx);
-  case BO_XorAssign: return translateBinAssign(BO_Xor, BO, Ctx);
-  case BO_OrAssign:  return translateBinAssign(BO_Or,  BO, Ctx);
+  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.
@@ -390,8 +371,9 @@ til::SExpr *SExprBuilder::translateCastE
     return E0;
   }
   default: {
+    // FIXME: handle different kinds of casts.
     til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);
-    return new (Arena) til::Cast(K, E0);
+    return new (Arena) til::Cast(til::CAST_none, E0);
   }
   }
 }
@@ -791,8 +773,7 @@ void SExprBuilder::exitCFG(const CFGBloc
 
 
 
-class LLVMPrinter : public til::PrettyPrinter<LLVMPrinter, llvm::raw_ostream> {
-};
+class TILPrinter : public til::PrettyPrinter<TILPrinter, llvm::raw_ostream> {};
 
 
 void printSCFG(CFGWalker &Walker) {
@@ -800,7 +781,7 @@ void printSCFG(CFGWalker &Walker) {
   til::MemRegionRef Arena(&Bpa);
   SExprBuilder builder(Arena);
   til::SCFG *Cfg = builder.buildCFG(Walker);
-  LLVMPrinter::print(Cfg, llvm::errs());
+  TILPrinter::print(Cfg, llvm::errs());
 }
 
 

Added: cfe/trunk/lib/Analysis/ThreadSafetyTIL.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafetyTIL.cpp?rev=208830&view=auto
==============================================================================
--- cfe/trunk/lib/Analysis/ThreadSafetyTIL.cpp (added)
+++ cfe/trunk/lib/Analysis/ThreadSafetyTIL.cpp Wed May 14 19:50:36 2014
@@ -0,0 +1,113 @@
+//===- ThreadSafetyTIL.cpp -------------------------------------*- C++ --*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT in the llvm repository for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
+#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h"
+
+namespace clang {
+namespace threadSafety {
+namespace til {
+
+
+StringRef getUnaryOpcodeString(TIL_UnaryOpcode Op) {
+  switch (Op) {
+    case UOP_Minus:    return "-";
+    case UOP_BitNot:   return "~";
+    case UOP_LogicNot: return "!";
+  }
+  return "";
+}
+
+
+StringRef getBinaryOpcodeString(TIL_BinaryOpcode Op) {
+  switch (Op) {
+    case BOP_Mul:      return "*";
+    case BOP_Div:      return "/";
+    case BOP_Rem:      return "%";
+    case BOP_Add:      return "+";
+    case BOP_Sub:      return "-";
+    case BOP_Shl:      return "<<";
+    case BOP_Shr:      return ">>";
+    case BOP_BitAnd:   return "&";
+    case BOP_BitXor:   return "^";
+    case BOP_BitOr:    return "|";
+    case BOP_Eq:       return "==";
+    case BOP_Neq:      return "!=";
+    case BOP_Lt:       return "<";
+    case BOP_Leq:      return "<=";
+    case BOP_LogicAnd: return "&&";
+    case BOP_LogicOr:  return "||";
+  }
+  return "";
+}
+
+
+
+// If E is a variable, then trace back through any aliases or redundant
+// Phi nodes to find the canonical definition.
+SExpr *getCanonicalVal(SExpr *E) {
+  while (auto *V = dyn_cast<Variable>(E)) {
+    SExpr *D;
+    do {
+      if (V->kind() != Variable::VK_Let)
+        return V;
+      D = V->definition();
+      auto *V2 = dyn_cast<Variable>(D);
+      if (V2)
+        V = V2;
+      else
+        break;
+    } while (true);
+
+    if (ThreadSafetyTIL::isTrivial(D))
+      return D;
+
+    if (Phi *Ph = dyn_cast<Phi>(D)) {
+      if (Ph->status() == Phi::PH_Incomplete)
+        simplifyIncompleteArg(V, Ph);
+
+      if (Ph->status() == Phi::PH_SingleVal) {
+        E = Ph->values()[0];
+        continue;
+      }
+    }
+    return V;
+  }
+  return E;
+}
+
+
+// Trace the arguments of an incomplete Phi node to see if they have the same
+// canonical definition.  If so, mark the Phi node as redundant.
+// getCanonicalVal() will recursively call simplifyIncompletePhi().
+void simplifyIncompleteArg(Variable *V, til::Phi *Ph) {
+  assert(Ph && Ph->status() == Phi::PH_Incomplete);
+
+  // eliminate infinite recursion -- assume that this node is not redundant.
+  Ph->setStatus(Phi::PH_MultiVal);
+
+  SExpr *E0 = getCanonicalVal(Ph->values()[0]);
+  for (unsigned i=1, n=Ph->values().size(); i<n; ++i) {
+    SExpr *Ei = getCanonicalVal(Ph->values()[i]);
+    if (Ei == V)
+      continue;  // Recursive reference to itself.  Don't count.
+    if (Ei != E0) {
+      return;    // Status is already set to MultiVal.
+    }
+  }
+  Ph->setStatus(Phi::PH_SingleVal);
+  // Eliminate Redundant Phi node.
+  V->setDefinition(Ph->values()[0]);
+}
+
+
+}  // end namespace til
+}  // end namespace threadSafety
+}  // end namespace clang
+





More information about the cfe-commits mailing list