Thread Safety Analysis: add new node types to thread safety TIL.
This fills in a few missing gaps in functionality.

llvm-svn: 208830
diff --git a/clang/lib/Analysis/CMakeLists.txt b/clang/lib/Analysis/CMakeLists.txt
index 89f8593..5e97ce2 100644
--- a/clang/lib/Analysis/CMakeLists.txt
+++ b/clang/lib/Analysis/CMakeLists.txt
@@ -25,6 +25,7 @@
   ThreadSafety.cpp
   ThreadSafetyCommon.cpp
   ThreadSafetyLogical.cpp
+  ThreadSafetyTIL.cpp
   UninitializedValues.cpp
 
   LINK_LIBS
diff --git a/clang/lib/Analysis/ThreadSafetyCommon.cpp b/clang/lib/Analysis/ThreadSafetyCommon.cpp
index fb96834..91cf849 100644
--- a/clang/lib/Analysis/ThreadSafetyCommon.cpp
+++ b/clang/lib/Analysis/ThreadSafetyCommon.cpp
@@ -37,66 +37,31 @@
 namespace clang {
 namespace threadSafety {
 
+// 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;
+    }
+    case Stmt::CharacterLiteralClass:
+    case Stmt::CXXNullPtrLiteralExprClass:
+    case Stmt::GNUNullExprClass:
+    case Stmt::CXXBoolLiteralExprClass:
+    case Stmt::FloatingLiteralClass:
+    case Stmt::ImaginaryLiteralClass:
+    case Stmt::ObjCStringLiteralClass:
+    default:
+      return "#lit";
+  }
+}
+
 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;
-      }
-    }
-    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]);
-}
-
-
 // Return true if E is a variable that points to an incomplete Phi node.
 static bool isIncompleteVar(const SExpr *E) {
   if (const auto *V = dyn_cast<Variable>(E)) {
@@ -106,7 +71,6 @@
   return false;
 }
 
-
 }  // end namespace til
 
 
@@ -281,21 +245,41 @@
     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 @@
     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 @@
   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_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(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_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 @@
     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 @@
 
 
 
-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 @@
   til::MemRegionRef Arena(&Bpa);
   SExprBuilder builder(Arena);
   til::SCFG *Cfg = builder.buildCFG(Walker);
-  LLVMPrinter::print(Cfg, llvm::errs());
+  TILPrinter::print(Cfg, llvm::errs());
 }
 
 
diff --git a/clang/lib/Analysis/ThreadSafetyTIL.cpp b/clang/lib/Analysis/ThreadSafetyTIL.cpp
new file mode 100644
index 0000000..f4da8d4
--- /dev/null
+++ b/clang/lib/Analysis/ThreadSafetyTIL.cpp
@@ -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
+