Improved side-effects/can-throw information on intrinsics.

Rationale: improved side effect and exception analysis gives
           many more opportunities for GVN/LICM/BCE.

Change-Id: I8aa9b757d77c7bd9d58271204a657c2c525195b5
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index 7127215..c6da9a3 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -36,8 +36,8 @@
   switch (i) {
     case Intrinsics::kNone:
       return kInterface;  // Non-sensical for intrinsic.
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache) \
-    case Intrinsics::k ## Name:               \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+    case Intrinsics::k ## Name: \
       return IsStatic;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
@@ -52,8 +52,8 @@
   switch (i) {
     case Intrinsics::kNone:
       return kNeedsEnvironmentOrCache;  // Non-sensical for intrinsic.
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache) \
-    case Intrinsics::k ## Name:               \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+    case Intrinsics::k ## Name: \
       return NeedsEnvironmentOrCache;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
@@ -63,6 +63,38 @@
   return kNeedsEnvironmentOrCache;
 }
 
+// Function that returns whether an intrinsic has side effects.
+static inline IntrinsicSideEffects GetSideEffects(Intrinsics i) {
+  switch (i) {
+    case Intrinsics::kNone:
+      return kAllSideEffects;
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+    case Intrinsics::k ## Name: \
+      return SideEffects;
+#include "intrinsics_list.h"
+INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
+#undef INTRINSICS_LIST
+#undef OPTIMIZING_INTRINSICS
+  }
+  return kAllSideEffects;
+}
+
+// Function that returns whether an intrinsic can throw exceptions.
+static inline IntrinsicExceptions GetExceptions(Intrinsics i) {
+  switch (i) {
+    case Intrinsics::kNone:
+      return kCanThrow;
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+    case Intrinsics::k ## Name: \
+      return Exceptions;
+#include "intrinsics_list.h"
+INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
+#undef INTRINSICS_LIST
+#undef OPTIMIZING_INTRINSICS
+  }
+  return kCanThrow;
+}
+
 static Primitive::Type GetType(uint64_t data, bool is_op_size) {
   if (is_op_size) {
     switch (static_cast<OpSize>(data)) {
@@ -248,7 +280,7 @@
 
     // Thread.currentThread.
     case kIntrinsicCurrentThread:
-      return  Intrinsics::kThreadCurrentThread;
+      return Intrinsics::kThreadCurrentThread;
 
     // Memory.peek.
     case kIntrinsicPeek:
@@ -473,7 +505,10 @@
                   << PrettyMethod(invoke->GetDexMethodIndex(), invoke->GetDexFile())
                   << invoke->DebugName();
             } else {
-              invoke->SetIntrinsic(intrinsic, NeedsEnvironmentOrCache(intrinsic));
+              invoke->SetIntrinsic(intrinsic,
+                                   NeedsEnvironmentOrCache(intrinsic),
+                                   GetSideEffects(intrinsic),
+                                   GetExceptions(intrinsic));
             }
           }
         }
@@ -487,7 +522,7 @@
     case Intrinsics::kNone:
       os << "None";
       break;
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
     case Intrinsics::k ## Name: \
       os << # Name; \
       break;
diff --git a/compiler/optimizing/intrinsics.h b/compiler/optimizing/intrinsics.h
index a6db1e8..9f50d18 100644
--- a/compiler/optimizing/intrinsics.h
+++ b/compiler/optimizing/intrinsics.h
@@ -57,9 +57,9 @@
     switch (invoke->GetIntrinsic()) {
       case Intrinsics::kNone:
         return;
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment) \
-      case Intrinsics::k ## Name:             \
-        Visit ## Name(invoke);                \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment, SideEffects, Exceptions) \
+      case Intrinsics::k ## Name: \
+        Visit ## Name(invoke);    \
         return;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
@@ -72,7 +72,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment)                    \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment, SideEffects, Exceptions) \
   virtual void Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \
   }
 #include "intrinsics_list.h"
diff --git a/compiler/optimizing/intrinsics_arm.h b/compiler/optimizing/intrinsics_arm.h
index 127e9a4..e01b6ff 100644
--- a/compiler/optimizing/intrinsics_arm.h
+++ b/compiler/optimizing/intrinsics_arm.h
@@ -40,7 +40,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache)   \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
   void Visit ## Name(HInvoke* invoke) OVERRIDE;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
@@ -67,7 +67,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache)   \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
   void Visit ## Name(HInvoke* invoke) OVERRIDE;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
diff --git a/compiler/optimizing/intrinsics_arm64.h b/compiler/optimizing/intrinsics_arm64.h
index 4250ecf..d47448a 100644
--- a/compiler/optimizing/intrinsics_arm64.h
+++ b/compiler/optimizing/intrinsics_arm64.h
@@ -41,7 +41,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache)   \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
   void Visit ## Name(HInvoke* invoke) OVERRIDE;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
@@ -65,7 +65,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache)   \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
   void Visit ## Name(HInvoke* invoke) OVERRIDE;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
diff --git a/compiler/optimizing/intrinsics_list.h b/compiler/optimizing/intrinsics_list.h
index 96f43a0..2e87546 100644
--- a/compiler/optimizing/intrinsics_list.h
+++ b/compiler/optimizing/intrinsics_list.h
@@ -22,97 +22,97 @@
 // environment.
 
 #define INTRINSICS_LIST(V) \
-  V(DoubleDoubleToRawLongBits, kStatic, kNeedsEnvironmentOrCache) \
-  V(DoubleLongBitsToDouble, kStatic, kNeedsEnvironmentOrCache) \
-  V(FloatFloatToRawIntBits, kStatic, kNeedsEnvironmentOrCache) \
-  V(FloatIntBitsToFloat, kStatic, kNeedsEnvironmentOrCache) \
-  V(IntegerReverse, kStatic, kNeedsEnvironmentOrCache) \
-  V(IntegerReverseBytes, kStatic, kNeedsEnvironmentOrCache) \
-  V(IntegerNumberOfLeadingZeros, kStatic, kNeedsEnvironmentOrCache) \
-  V(IntegerNumberOfTrailingZeros, kStatic, kNeedsEnvironmentOrCache) \
-  V(IntegerRotateRight, kStatic, kNeedsEnvironmentOrCache) \
-  V(IntegerRotateLeft, kStatic, kNeedsEnvironmentOrCache) \
-  V(LongReverse, kStatic, kNeedsEnvironmentOrCache) \
-  V(LongReverseBytes, kStatic, kNeedsEnvironmentOrCache) \
-  V(LongNumberOfLeadingZeros, kStatic, kNeedsEnvironmentOrCache) \
-  V(LongNumberOfTrailingZeros, kStatic, kNeedsEnvironmentOrCache) \
-  V(LongRotateRight, kStatic, kNeedsEnvironmentOrCache) \
-  V(LongRotateLeft, kStatic, kNeedsEnvironmentOrCache) \
-  V(ShortReverseBytes, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathAbsDouble, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathAbsFloat, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathAbsLong, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathAbsInt, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathMinDoubleDouble, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathMinFloatFloat, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathMinLongLong, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathMinIntInt, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathMaxDoubleDouble, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathMaxFloatFloat, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathMaxLongLong, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathMaxIntInt, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathCos, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathSin, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathAcos, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathAsin, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathAtan, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathAtan2, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathCbrt, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathCosh, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathExp, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathExpm1, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathHypot, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathLog, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathLog10, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathNextAfter, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathSinh, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathTan, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathTanh, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathSqrt, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathCeil, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathFloor, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathRint, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathRoundDouble, kStatic, kNeedsEnvironmentOrCache) \
-  V(MathRoundFloat, kStatic, kNeedsEnvironmentOrCache) \
-  V(SystemArrayCopyChar, kStatic, kNeedsEnvironmentOrCache) \
-  V(SystemArrayCopy, kStatic, kNeedsEnvironmentOrCache) \
-  V(ThreadCurrentThread, kStatic, kNeedsEnvironmentOrCache) \
-  V(MemoryPeekByte, kStatic, kNeedsEnvironmentOrCache) \
-  V(MemoryPeekIntNative, kStatic, kNeedsEnvironmentOrCache) \
-  V(MemoryPeekLongNative, kStatic, kNeedsEnvironmentOrCache) \
-  V(MemoryPeekShortNative, kStatic, kNeedsEnvironmentOrCache) \
-  V(MemoryPokeByte, kStatic, kNeedsEnvironmentOrCache) \
-  V(MemoryPokeIntNative, kStatic, kNeedsEnvironmentOrCache) \
-  V(MemoryPokeLongNative, kStatic, kNeedsEnvironmentOrCache) \
-  V(MemoryPokeShortNative, kStatic, kNeedsEnvironmentOrCache) \
-  V(StringCharAt, kDirect, kNeedsEnvironmentOrCache) \
-  V(StringCompareTo, kDirect, kNeedsEnvironmentOrCache) \
-  V(StringEquals, kDirect, kNeedsEnvironmentOrCache) \
-  V(StringGetCharsNoCheck, kDirect, kNeedsEnvironmentOrCache) \
-  V(StringIndexOf, kDirect, kNeedsEnvironmentOrCache) \
-  V(StringIndexOfAfter, kDirect, kNeedsEnvironmentOrCache) \
-  V(StringNewStringFromBytes, kStatic, kNeedsEnvironmentOrCache) \
-  V(StringNewStringFromChars, kStatic, kNeedsEnvironmentOrCache) \
-  V(StringNewStringFromString, kStatic, kNeedsEnvironmentOrCache) \
-  V(UnsafeCASInt, kDirect, kNeedsEnvironmentOrCache) \
-  V(UnsafeCASLong, kDirect, kNeedsEnvironmentOrCache) \
-  V(UnsafeCASObject, kDirect, kNeedsEnvironmentOrCache) \
-  V(UnsafeGet, kDirect, kNeedsEnvironmentOrCache) \
-  V(UnsafeGetVolatile, kDirect, kNeedsEnvironmentOrCache) \
-  V(UnsafeGetObject, kDirect, kNeedsEnvironmentOrCache) \
-  V(UnsafeGetObjectVolatile, kDirect, kNeedsEnvironmentOrCache) \
-  V(UnsafeGetLong, kDirect, kNeedsEnvironmentOrCache) \
-  V(UnsafeGetLongVolatile, kDirect, kNeedsEnvironmentOrCache) \
-  V(UnsafePut, kDirect, kNeedsEnvironmentOrCache) \
-  V(UnsafePutOrdered, kDirect, kNeedsEnvironmentOrCache) \
-  V(UnsafePutVolatile, kDirect, kNeedsEnvironmentOrCache) \
-  V(UnsafePutObject, kDirect, kNeedsEnvironmentOrCache) \
-  V(UnsafePutObjectOrdered, kDirect, kNeedsEnvironmentOrCache) \
-  V(UnsafePutObjectVolatile, kDirect, kNeedsEnvironmentOrCache) \
-  V(UnsafePutLong, kDirect, kNeedsEnvironmentOrCache) \
-  V(UnsafePutLongOrdered, kDirect, kNeedsEnvironmentOrCache) \
-  V(UnsafePutLongVolatile, kDirect, kNeedsEnvironmentOrCache) \
-  V(ReferenceGetReferent, kDirect, kNeedsEnvironmentOrCache)
+  V(DoubleDoubleToRawLongBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(DoubleLongBitsToDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(FloatFloatToRawIntBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(FloatIntBitsToFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(IntegerReverse, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(IntegerReverseBytes, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(IntegerNumberOfLeadingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(IntegerNumberOfTrailingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(IntegerRotateRight, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(IntegerRotateLeft, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(LongReverse, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(LongReverseBytes, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(LongNumberOfLeadingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(LongNumberOfTrailingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(LongRotateRight, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(LongRotateLeft, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(ShortReverseBytes, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathAbsDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathAbsFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathAbsLong, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathAbsInt, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathMinDoubleDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathMinFloatFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathMinLongLong, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathMinIntInt, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathMaxDoubleDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathMaxFloatFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathMaxLongLong, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathMaxIntInt, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathCos, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathSin, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathAcos, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathAsin, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathAtan, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathAtan2, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathCbrt, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathCosh, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathExp, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathExpm1, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathHypot, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathLog, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathLog10, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathNextAfter, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathSinh, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathTan, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathTanh, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathSqrt, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathCeil, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathFloor, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathRint, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathRoundDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MathRoundFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(SystemArrayCopyChar, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
+  V(SystemArrayCopy, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
+  V(ThreadCurrentThread, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(MemoryPeekByte, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
+  V(MemoryPeekIntNative, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
+  V(MemoryPeekLongNative, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
+  V(MemoryPeekShortNative, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
+  V(MemoryPokeByte, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kCanThrow) \
+  V(MemoryPokeIntNative, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kCanThrow) \
+  V(MemoryPokeLongNative, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kCanThrow) \
+  V(MemoryPokeShortNative, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kCanThrow) \
+  V(StringCharAt, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
+  V(StringCompareTo, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
+  V(StringEquals, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
+  V(StringGetCharsNoCheck, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
+  V(StringIndexOf, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
+  V(StringIndexOfAfter, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
+  V(StringNewStringFromBytes, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
+  V(StringNewStringFromChars, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
+  V(StringNewStringFromString, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
+  V(UnsafeCASInt, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
+  V(UnsafeCASLong, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
+  V(UnsafeCASObject, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
+  V(UnsafeGet, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
+  V(UnsafeGetVolatile, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
+  V(UnsafeGetObject, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
+  V(UnsafeGetObjectVolatile, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
+  V(UnsafeGetLong, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
+  V(UnsafeGetLongVolatile, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
+  V(UnsafePut, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
+  V(UnsafePutOrdered, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
+  V(UnsafePutVolatile, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
+  V(UnsafePutObject, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
+  V(UnsafePutObjectOrdered, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
+  V(UnsafePutObjectVolatile, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
+  V(UnsafePutLong, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
+  V(UnsafePutLongOrdered, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
+  V(UnsafePutLongVolatile, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
+  V(ReferenceGetReferent, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow)
 
 #endif  // ART_COMPILER_OPTIMIZING_INTRINSICS_LIST_H_
 #undef ART_COMPILER_OPTIMIZING_INTRINSICS_LIST_H_   // #define is only for lint.
diff --git a/compiler/optimizing/intrinsics_mips.h b/compiler/optimizing/intrinsics_mips.h
index 19ad525..f86b0ef 100644
--- a/compiler/optimizing/intrinsics_mips.h
+++ b/compiler/optimizing/intrinsics_mips.h
@@ -36,7 +36,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache)   \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
   void Visit ## Name(HInvoke* invoke) OVERRIDE;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
@@ -60,7 +60,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache)   \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
   void Visit ## Name(HInvoke* invoke) OVERRIDE;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
diff --git a/compiler/optimizing/intrinsics_mips64.h b/compiler/optimizing/intrinsics_mips64.h
index 1481d24..4137fbd 100644
--- a/compiler/optimizing/intrinsics_mips64.h
+++ b/compiler/optimizing/intrinsics_mips64.h
@@ -36,7 +36,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache)   \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
   void Visit ## Name(HInvoke* invoke) OVERRIDE;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
@@ -60,7 +60,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache)   \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
   void Visit ## Name(HInvoke* invoke) OVERRIDE;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
diff --git a/compiler/optimizing/intrinsics_x86.h b/compiler/optimizing/intrinsics_x86.h
index fefe9c6..08bd197 100644
--- a/compiler/optimizing/intrinsics_x86.h
+++ b/compiler/optimizing/intrinsics_x86.h
@@ -36,7 +36,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache)   \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
   void Visit ## Name(HInvoke* invoke) OVERRIDE;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
@@ -61,7 +61,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache)   \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
   void Visit ## Name(HInvoke* invoke) OVERRIDE;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
diff --git a/compiler/optimizing/intrinsics_x86_64.h b/compiler/optimizing/intrinsics_x86_64.h
index 6894e1b..155ff65 100644
--- a/compiler/optimizing/intrinsics_x86_64.h
+++ b/compiler/optimizing/intrinsics_x86_64.h
@@ -36,7 +36,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache)   \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
   void Visit ## Name(HInvoke* invoke) OVERRIDE;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
@@ -61,7 +61,7 @@
 
   // Define visitor methods.
 
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache)   \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
   void Visit ## Name(HInvoke* invoke) OVERRIDE;
 #include "intrinsics_list.h"
 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index a37298c..a9a2493 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -2091,13 +2091,27 @@
 }
 
 void HInvoke::SetIntrinsic(Intrinsics intrinsic,
-                           IntrinsicNeedsEnvironmentOrCache needs_env_or_cache) {
+                           IntrinsicNeedsEnvironmentOrCache needs_env_or_cache,
+                           IntrinsicSideEffects side_effects,
+                           IntrinsicExceptions exceptions) {
   intrinsic_ = intrinsic;
   IntrinsicOptimizations opt(this);
   if (needs_env_or_cache == kNoEnvironmentOrCache) {
     opt.SetDoesNotNeedDexCache();
     opt.SetDoesNotNeedEnvironment();
   }
+  // Adjust method's side effects from intrinsic table.
+  switch (side_effects) {
+    case kNoSideEffects: SetSideEffects(SideEffects::None()); break;
+    case kReadSideEffects: SetSideEffects(SideEffects::AllReads()); break;
+    case kWriteSideEffects: SetSideEffects(SideEffects::AllWrites()); break;
+    case kAllSideEffects: SetSideEffects(SideEffects::AllExceptGCDependency()); break;
+  }
+  // Adjust method's exception status from intrinsic table.
+  switch (exceptions) {
+    case kNoThrow: SetCanThrow(false); break;
+    case kCanThrow: SetCanThrow(true); break;
+  }
 }
 
 bool HInvoke::NeedsEnvironment() const {
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index db3e969..ddd215d 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -2064,6 +2064,7 @@
  protected:
   virtual const HUserRecord<HInstruction*> InputRecordAt(size_t i) const = 0;
   virtual void SetRawInputRecordAt(size_t index, const HUserRecord<HInstruction*>& input) = 0;
+  void SetSideEffects(SideEffects other) { side_effects_ = other; }
 
  private:
   void RemoveEnvironmentUser(HUseListNode<HEnvironment*>* use_node) { env_uses_.Remove(use_node); }
@@ -3247,7 +3248,8 @@
 };
 
 enum class Intrinsics {
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache) k ## Name,
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+  k ## Name,
 #include "intrinsics_list.h"
   kNone,
   INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
@@ -3261,6 +3263,18 @@
   kNeedsEnvironmentOrCache      // Intrinsic requires an environment or requires a dex cache.
 };
 
+enum IntrinsicSideEffects {
+  kNoSideEffects,     // Intrinsic does not have any heap memory side effects.
+  kReadSideEffects,   // Intrinsic may read heap memory.
+  kWriteSideEffects,  // Intrinsic may write heap memory.
+  kAllSideEffects     // Intrinsic may read or write heap memory, or trigger GC.
+};
+
+enum IntrinsicExceptions {
+  kNoThrow,  // Intrinsic does not throw any exceptions.
+  kCanThrow  // Intrinsic may throw exceptions.
+};
+
 class HInvoke : public HInstruction {
  public:
   size_t InputCount() const OVERRIDE { return inputs_.size(); }
@@ -3279,7 +3293,6 @@
 
   Primitive::Type GetType() const OVERRIDE { return return_type_; }
 
-
   uint32_t GetDexMethodIndex() const { return dex_method_index_; }
   const DexFile& GetDexFile() const { return GetEnvironment()->GetDexFile(); }
 
@@ -3289,13 +3302,22 @@
     return intrinsic_;
   }
 
-  void SetIntrinsic(Intrinsics intrinsic, IntrinsicNeedsEnvironmentOrCache needs_env_or_cache);
+  void SetIntrinsic(Intrinsics intrinsic,
+                    IntrinsicNeedsEnvironmentOrCache needs_env_or_cache,
+                    IntrinsicSideEffects side_effects,
+                    IntrinsicExceptions exceptions);
 
   bool IsFromInlinedInvoke() const {
     return GetEnvironment()->IsFromInlinedInvoke();
   }
 
-  bool CanThrow() const OVERRIDE { return true; }
+  bool CanThrow() const OVERRIDE { return can_throw_; }
+
+  bool CanBeMoved() const OVERRIDE { return IsIntrinsic(); }
+
+  bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+    return intrinsic_ != Intrinsics::kNone && intrinsic_ == other->AsInvoke()->intrinsic_;
+  }
 
   uint32_t* GetIntrinsicOptimizations() {
     return &intrinsic_optimizations_;
@@ -3325,6 +3347,7 @@
       return_type_(return_type),
       dex_method_index_(dex_method_index),
       original_invoke_type_(original_invoke_type),
+      can_throw_(true),
       intrinsic_(Intrinsics::kNone),
       intrinsic_optimizations_(0) {
   }
@@ -3337,11 +3360,14 @@
     inputs_[index] = input;
   }
 
+  void SetCanThrow(bool can_throw) { can_throw_ = can_throw; }
+
   uint32_t number_of_arguments_;
   ArenaVector<HUserRecord<HInstruction*>> inputs_;
   const Primitive::Type return_type_;
   const uint32_t dex_method_index_;
   const InvokeType original_invoke_type_;
+  bool can_throw_;
   Intrinsics intrinsic_;
 
   // A magic word holding optimizations for intrinsics. See intrinsics.h.
diff --git a/test/445-checker-licm/src/Main.java b/test/445-checker-licm/src/Main.java
index 6ee8a4d..061fe6e 100644
--- a/test/445-checker-licm/src/Main.java
+++ b/test/445-checker-licm/src/Main.java
@@ -52,13 +52,13 @@
     return result;
   }
 
-  /// CHECK-START: int Main.innerDiv2() licm (before)
+  /// CHECK-START: int Main.innerMul() licm (before)
   /// CHECK-DAG: Mul loop:B4
 
-  /// CHECK-START: int Main.innerDiv2() licm (after)
+  /// CHECK-START: int Main.innerMul() licm (after)
   /// CHECK-DAG: Mul loop:B2
 
-  public static int innerDiv2() {
+  public static int innerMul() {
     int result = 0;
     for (int i = 0; i < 10; ++i) {
       for (int j = 0; j < 10; ++j) {
@@ -71,13 +71,13 @@
     return result;
   }
 
-  /// CHECK-START: int Main.innerDiv3(int, int) licm (before)
+  /// CHECK-START: int Main.divByA(int, int) licm (before)
   /// CHECK-DAG: Div loop:{{B\d+}}
 
-  /// CHECK-START: int Main.innerDiv3(int, int) licm (after)
+  /// CHECK-START: int Main.divByA(int, int) licm (after)
   /// CHECK-DAG: Div loop:{{B\d+}}
 
-  public static int innerDiv3(int a, int b) {
+  public static int divByA(int a, int b) {
     int result = 0;
     while (b < 5) {
       // a might be null, so we can't hoist the operation.
@@ -107,6 +107,63 @@
     return result;
   }
 
+  /// CHECK-START: int Main.divAndIntrinsic(int[]) licm (before)
+  /// CHECK-DAG: Div loop:{{B\d+}}
+
+  /// CHECK-START: int Main.divAndIntrinsic(int[]) licm (after)
+  /// CHECK-NOT: Div loop:{{B\d+}}
+
+  /// CHECK-START: int Main.divAndIntrinsic(int[]) licm (after)
+  /// CHECK-DAG: Div loop:none
+
+  public static int divAndIntrinsic(int[] array) {
+    int result = 0;
+    for (int i = 0; i < array.length; i++) {
+      // An intrinsic call, unlike a general method call, cannot modify the field value.
+      // As a result, the invariant division on the field can be moved out of the loop.
+      result += (staticField / 42) + Math.abs(array[i]);
+    }
+    return result;
+  }
+
+  /// CHECK-START: int Main.invariantBoundIntrinsic(int) licm (before)
+  /// CHECK-DAG: InvokeStaticOrDirect loop:{{B\d+}}
+
+  /// CHECK-START: int Main.invariantBoundIntrinsic(int) licm (after)
+  /// CHECK-NOT: InvokeStaticOrDirect loop:{{B\d+}}
+
+  /// CHECK-START: int Main.invariantBoundIntrinsic(int) licm (after)
+  /// CHECK-DAG: InvokeStaticOrDirect loop:none
+
+  public static int invariantBoundIntrinsic(int x) {
+    int result = 0;
+    // The intrinsic call to abs used as loop bound is invariant.
+    // As a result, the call itself can be moved out of the loop header.
+    for (int i = 0; i < Math.abs(x); i++) {
+      result += i;
+    }
+    return result;
+  }
+
+  /// CHECK-START: int Main.invariantBodyIntrinsic(int, int) licm (before)
+  /// CHECK-DAG: InvokeStaticOrDirect loop:{{B\d+}}
+
+  /// CHECK-START: int Main.invariantBodyIntrinsic(int, int) licm (after)
+  /// CHECK-NOT: InvokeStaticOrDirect loop:{{B\d+}}
+
+  /// CHECK-START: int Main.invariantBodyIntrinsic(int, int) licm (after)
+  /// CHECK-DAG: InvokeStaticOrDirect loop:none
+
+  public static int invariantBodyIntrinsic(int x, int y) {
+    int result = 0;
+    for (int i = 0; i < 10; i++) {
+      // The intrinsic call to max used inside the loop is invariant.
+      // As a result, the call itself can be moved out of the loop body.
+      result += Math.max(x, y);
+    }
+    return result;
+  }
+
   public static int staticField = 42;
 
   public static void assertEquals(int expected, int actual) {
@@ -118,6 +175,11 @@
   public static void main(String[] args) {
     assertEquals(10, div());
     assertEquals(100, innerDiv());
+    assertEquals(18900, innerMul());
+    assertEquals(105, divByA(2, 0));
     assertEquals(12, arrayLength(new int[] { 4, 8 }));
+    assertEquals(21, divAndIntrinsic(new int[] { 4, -2, 8, -3 }));
+    assertEquals(45, invariantBoundIntrinsic(-10));
+    assertEquals(30, invariantBodyIntrinsic(2, 3));
   }
 }
diff --git a/test/449-checker-bce/src/Main.java b/test/449-checker-bce/src/Main.java
index c3d2759..6e7ba40 100644
--- a/test/449-checker-bce/src/Main.java
+++ b/test/449-checker-bce/src/Main.java
@@ -616,6 +616,40 @@
     }
   }
 
+  static int[][] mA;
+
+  /// CHECK-START: void Main.dynamicBCEAndIntrinsic(int) BCE (before)
+  /// CHECK-DAG: NullCheck
+  /// CHECK-DAG: ArrayLength
+  /// CHECK-DAG: BoundsCheck
+  /// CHECK-DAG: ArrayGet
+  /// CHECK-DAG: NullCheck
+  /// CHECK-DAG: ArrayLength
+  /// CHECK-DAG: BoundsCheck
+  /// CHECK-DAG: ArrayGet
+  /// CHECK-DAG: InvokeStaticOrDirect
+  /// CHECK-DAG: ArraySet
+
+  /// CHECK-START: void Main.dynamicBCEAndIntrinsic(int) BCE (after)
+  /// CHECK-NOT: NullCheck
+  /// CHECK-NOT: ArrayLength
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK-DAG: ArrayGet
+  /// CHECK-NOT: ArrayGet
+  /// CHECK-DAG: InvokeStaticOrDirect
+  /// CHECK-DAG: ArraySet
+  /// CHECK-DAG: Exit
+  /// CHECK-DAG: Deoptimize
+
+  static void dynamicBCEAndIntrinsic(int n) {
+    for (int i = 0; i < n; i++) {
+      for (int j = 0; j < n; j++) {
+        // Since intrinsic call cannot modify fields or arrays,
+        // dynamic BCE and hoisting can be applied to the inner loop.
+        mA[i][j] = Math.abs(mA[i][j]);
+      }
+    }
+  }
 
   static int foo() {
     try {
@@ -1225,6 +1259,21 @@
       }
     }
 
+    mA = new int[4][4];
+    for (int i = 0; i < 4; i++) {
+      for (int j = 0; j < 4; j++) {
+        mA[i][j] = -1;
+      }
+    }
+    dynamicBCEAndIntrinsic(4);
+    for (int i = 0; i < 4; i++) {
+      for (int j = 0; j < 4; j++) {
+        if (mA[i][i] != 1) {
+          System.out.println("dynamic bce failed!");
+        }
+      }
+    }
+
     array = new int[7];
     pyramid1(array);
     if (!isPyramid(array)) {
diff --git a/test/455-checker-gvn/expected.txt b/test/455-checker-gvn/expected.txt
index 8351c19..c1679c7 100644
--- a/test/455-checker-gvn/expected.txt
+++ b/test/455-checker-gvn/expected.txt
@@ -1 +1,3 @@
 14
+0
+10
diff --git a/test/455-checker-gvn/src/Main.java b/test/455-checker-gvn/src/Main.java
index 9824f27..cea0959 100644
--- a/test/455-checker-gvn/src/Main.java
+++ b/test/455-checker-gvn/src/Main.java
@@ -15,8 +15,14 @@
  */
 
 public class Main {
+
+  private static int mX = 2;
+  private static int mY = -3;
+
   public static void main(String[] args) {
     System.out.println(foo(3, 4));
+    System.out.println(mulAndIntrinsic());
+    System.out.println(directIntrinsic(-5));
   }
 
   /// CHECK-START: int Main.foo(int, int) GVN (before)
@@ -35,7 +41,50 @@
     return sum1 + sum2;
   }
 
-  public static long bar(int i) {
-    return i;
+  /// CHECK-START: int Main.mulAndIntrinsic() GVN (before)
+  /// CHECK: StaticFieldGet
+  /// CHECK: StaticFieldGet
+  /// CHECK: Mul
+  /// CHECK: InvokeStaticOrDirect
+  /// CHECK: StaticFieldGet
+  /// CHECK: StaticFieldGet
+  /// CHECK: Mul
+  /// CHECK: Add
+
+  /// CHECK-START: int Main.mulAndIntrinsic() GVN (after)
+  /// CHECK: StaticFieldGet
+  /// CHECK: StaticFieldGet
+  /// CHECK: Mul
+  /// CHECK: InvokeStaticOrDirect
+  /// CHECK-NOT: StaticFieldGet
+  /// CHECK-NOT: StaticFieldGet
+  /// CHECK-NOT: Mul
+  /// CHECK: Add
+
+  public static int mulAndIntrinsic() {
+    // The intermediate call to abs() does not kill
+    // the common subexpression on the multiplication.
+    int mul1 = mX * mY;
+    int abs  = Math.abs(mul1);
+    int mul2 = mY * mX;
+    return abs + mul2;
   }
+
+  /// CHECK-START: int Main.directIntrinsic(int) GVN (before)
+  /// CHECK: InvokeStaticOrDirect
+  /// CHECK: InvokeStaticOrDirect
+  /// CHECK: Add
+
+  /// CHECK-START: int Main.directIntrinsic(int) GVN (after)
+  /// CHECK: InvokeStaticOrDirect
+  /// CHECK-NOT: InvokeStaticOrDirect
+  /// CHECK: Add
+
+  public static int directIntrinsic(int x) {
+    // Here, the two calls to abs() themselves can be replaced with just one.
+    int abs1 = Math.abs(x);
+    int abs2 = Math.abs(x);
+    return abs1 + abs2;
+  }
+
 }
diff --git a/test/530-checker-loops/src/Main.java b/test/530-checker-loops/src/Main.java
index e827b1e..e93ed8f 100644
--- a/test/530-checker-loops/src/Main.java
+++ b/test/530-checker-loops/src/Main.java
@@ -26,7 +26,7 @@
   //
 
   /// CHECK-START: int Main.linear(int[]) BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.linear(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -40,7 +40,7 @@
   }
 
   /// CHECK-START: int Main.linearDown(int[]) BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.linearDown(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -54,7 +54,7 @@
   }
 
   /// CHECK-START: int Main.linearObscure(int[]) BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.linearObscure(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -69,7 +69,7 @@
   }
 
   /// CHECK-START: int Main.linearVeryObscure(int[]) BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.linearVeryObscure(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -84,7 +84,7 @@
   }
 
   /// CHECK-START: int Main.hiddenStride(int[]) BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.hiddenStride(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -101,7 +101,7 @@
   }
 
   /// CHECK-START: int Main.linearWhile(int[]) BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.linearWhile(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -116,7 +116,7 @@
   }
 
   /// CHECK-START: int Main.linearThreeWayPhi(int[]) BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.linearThreeWayPhi(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -134,7 +134,7 @@
   }
 
   /// CHECK-START: int Main.linearFourWayPhi(int[]) BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.linearFourWayPhi(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -156,7 +156,7 @@
   }
 
   /// CHECK-START: int Main.wrapAroundThenLinear(int[]) BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.wrapAroundThenLinear(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -173,7 +173,7 @@
   }
 
   /// CHECK-START: int Main.wrapAroundThenLinearThreeWayPhi(int[]) BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.wrapAroundThenLinearThreeWayPhi(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -194,7 +194,7 @@
   }
 
   /// CHECK-START: int[] Main.linearWithParameter(int) BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int[] Main.linearWithParameter(int) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -208,7 +208,7 @@
   }
 
   /// CHECK-START: int[] Main.linearCopy(int[]) BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int[] Main.linearCopy(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -223,8 +223,8 @@
   }
 
   /// CHECK-START: int Main.linearByTwo(int[]) BCE (before)
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.linearByTwo(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -241,7 +241,7 @@
   }
 
   /// CHECK-START: int Main.linearByTwoSkip1(int[]) BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.linearByTwoSkip1(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -255,10 +255,10 @@
   }
 
   /// CHECK-START: int Main.linearByTwoSkip2(int[]) BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.linearByTwoSkip2(int[]) BCE (after)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   /// CHECK-NOT: Deoptimize
   private static int linearByTwoSkip2(int x[]) {
     int result = 0;
@@ -270,7 +270,7 @@
   }
 
   /// CHECK-START: int Main.linearWithCompoundStride() BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.linearWithCompoundStride() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -287,7 +287,7 @@
   }
 
   /// CHECK-START: int Main.linearWithLargePositiveStride() BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.linearWithLargePositiveStride() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -305,10 +305,10 @@
   }
 
   /// CHECK-START: int Main.linearWithVeryLargePositiveStride() BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.linearWithVeryLargePositiveStride() BCE (after)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   /// CHECK-NOT: Deoptimize
   private static int linearWithVeryLargePositiveStride() {
     int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
@@ -323,7 +323,7 @@
   }
 
   /// CHECK-START: int Main.linearWithLargeNegativeStride() BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.linearWithLargeNegativeStride() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -341,10 +341,10 @@
   }
 
   /// CHECK-START: int Main.linearWithVeryLargeNegativeStride() BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.linearWithVeryLargeNegativeStride() BCE (after)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   /// CHECK-NOT: Deoptimize
   private static int linearWithVeryLargeNegativeStride() {
     int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
@@ -359,7 +359,7 @@
   }
 
   /// CHECK-START: int Main.linearForNEUp() BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.linearForNEUp() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -374,7 +374,7 @@
   }
 
   /// CHECK-START: int Main.linearForNEDown() BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.linearForNEDown() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -389,7 +389,7 @@
   }
 
   /// CHECK-START: int Main.linearDoWhileUp() BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.linearDoWhileUp() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -405,7 +405,7 @@
   }
 
   /// CHECK-START: int Main.linearDoWhileDown() BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.linearDoWhileDown() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -421,10 +421,10 @@
   }
 
   /// CHECK-START: int Main.linearShort() BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.linearShort() BCE (after)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   /// CHECK-NOT: Deoptimize
   private static int linearShort() {
     int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
@@ -437,7 +437,7 @@
   }
 
   /// CHECK-START: int Main.invariantFromPreLoop(int[], int) BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.invariantFromPreLoop(int[], int) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -458,20 +458,20 @@
   }
 
   /// CHECK-START: void Main.linearTriangularOnTwoArrayLengths(int) BCE (before)
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: ArraySet
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: ArraySet
   //
   /// CHECK-START: void Main.linearTriangularOnTwoArrayLengths(int) BCE (after)
   /// CHECK-NOT: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: ArraySet
+  /// CHECK: ArrayGet
+  /// CHECK: ArraySet
   /// CHECK-NOT: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: ArraySet
+  /// CHECK: ArrayGet
+  /// CHECK: ArraySet
   /// CHECK-NOT: Deoptimize
   private static void linearTriangularOnTwoArrayLengths(int n) {
     int[] a = new int[n];
@@ -488,20 +488,20 @@
   }
 
   /// CHECK-START: void Main.linearTriangularOnOneArrayLength(int) BCE (before)
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: ArraySet
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: ArraySet
   //
   /// CHECK-START: void Main.linearTriangularOnOneArrayLength(int) BCE (after)
   /// CHECK-NOT: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: ArraySet
+  /// CHECK: ArrayGet
+  /// CHECK: ArraySet
   /// CHECK-NOT: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: ArraySet
+  /// CHECK: ArrayGet
+  /// CHECK: ArraySet
   /// CHECK-NOT: Deoptimize
   private static void linearTriangularOnOneArrayLength(int n) {
     int[] a = new int[n];
@@ -518,20 +518,20 @@
   }
 
   /// CHECK-START: void Main.linearTriangularOnParameter(int) BCE (before)
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: ArraySet
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: ArraySet
   //
   /// CHECK-START: void Main.linearTriangularOnParameter(int) BCE (after)
   /// CHECK-NOT: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: ArraySet
+  /// CHECK: ArrayGet
+  /// CHECK: ArraySet
   /// CHECK-NOT: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: ArraySet
+  /// CHECK: ArrayGet
+  /// CHECK: ArraySet
   /// CHECK-NOT: Deoptimize
   private static void linearTriangularOnParameter(int n) {
     int[] a = new int[n];
@@ -548,32 +548,32 @@
   }
 
   /// CHECK-START: void Main.linearTriangularVariations(int) BCE (before)
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: ArraySet
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: ArraySet
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: ArraySet
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: ArraySet
   //
   /// CHECK-START: void Main.linearTriangularVariations(int) BCE (after)
   /// CHECK-NOT: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: ArraySet
+  /// CHECK: ArrayGet
+  /// CHECK: ArraySet
   /// CHECK-NOT: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: ArraySet
+  /// CHECK: ArrayGet
+  /// CHECK: ArraySet
   /// CHECK-NOT: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: ArraySet
+  /// CHECK: ArrayGet
+  /// CHECK: ArraySet
   /// CHECK-NOT: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: ArraySet
+  /// CHECK: ArrayGet
+  /// CHECK: ArraySet
   /// CHECK-NOT: Deoptimize
   private static void linearTriangularVariations(int n) {
     int[] a = new int[n];
@@ -616,22 +616,22 @@
   }
 
   /// CHECK-START: void Main.bubble(int[]) BCE (before)
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: If
-  /// CHECK-DAG: ArraySet
-  /// CHECK-DAG: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: If
+  /// CHECK: ArraySet
+  /// CHECK: ArraySet
   //
   /// CHECK-START: void Main.bubble(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
-  /// CHECK-DAG: ArrayGet
+  /// CHECK: ArrayGet
   /// CHECK-NOT: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: If
-  /// CHECK-DAG: ArraySet
-  /// CHECK-DAG: ArraySet
+  /// CHECK: ArrayGet
+  /// CHECK: If
+  /// CHECK: ArraySet
+  /// CHECK: ArraySet
   /// CHECK-NOT: Deoptimize
   private static void bubble(int[] a) {
     for (int i = a.length; --i >= 0;) {
@@ -646,7 +646,7 @@
   }
 
   /// CHECK-START: int Main.periodicIdiom(int) BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.periodicIdiom(int) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -664,7 +664,7 @@
   }
 
   /// CHECK-START: int Main.periodicSequence2(int) BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.periodicSequence2(int) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -685,10 +685,10 @@
   }
 
   /// CHECK-START: int Main.periodicSequence4(int) BCE (before)
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
+  /// CHECK: BoundsCheck
+  /// CHECK: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.periodicSequence4(int) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -713,7 +713,7 @@
   }
 
   /// CHECK-START: int Main.justRightUp1() BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.justRightUp1() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -728,7 +728,7 @@
   }
 
   /// CHECK-START: int Main.justRightUp2() BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.justRightUp2() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -743,7 +743,7 @@
   }
 
   /// CHECK-START: int Main.justRightUp3() BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.justRightUp3() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -758,10 +758,10 @@
   }
 
   /// CHECK-START: int Main.justOOBUp() BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.justOOBUp() BCE (after)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   /// CHECK-NOT: Deoptimize
   private static int justOOBUp() {
     int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
@@ -774,7 +774,7 @@
   }
 
   /// CHECK-START: int Main.justRightDown1() BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.justRightDown1() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -789,7 +789,7 @@
   }
 
   /// CHECK-START: int Main.justRightDown2() BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.justRightDown2() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -804,7 +804,7 @@
   }
 
   /// CHECK-START: int Main.justRightDown3() BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.justRightDown3() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -819,10 +819,10 @@
   }
 
   /// CHECK-START: int Main.justOOBDown() BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.justOOBDown() BCE (after)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   /// CHECK-NOT: Deoptimize
   private static int justOOBDown() {
     int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
@@ -835,10 +835,10 @@
   }
 
   /// CHECK-START: void Main.lowerOOB(int[]) BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: void Main.lowerOOB(int[]) BCE (after)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   /// CHECK-NOT: Deoptimize
   private static void lowerOOB(int[] x) {
     for (int i = -1; i < x.length; i++) {
@@ -847,10 +847,10 @@
   }
 
   /// CHECK-START: void Main.upperOOB(int[]) BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: void Main.upperOOB(int[]) BCE (after)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   /// CHECK-NOT: Deoptimize
   private static void upperOOB(int[] x) {
     for (int i = 0; i <= x.length; i++) {
@@ -859,10 +859,10 @@
   }
 
   /// CHECK-START: void Main.doWhileUpOOB() BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: void Main.doWhileUpOOB() BCE (after)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   /// CHECK-NOT: Deoptimize
   private static void doWhileUpOOB() {
     int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
@@ -873,10 +873,10 @@
   }
 
   /// CHECK-START: void Main.doWhileDownOOB() BCE (before)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: void Main.doWhileDownOOB() BCE (after)
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: BoundsCheck
   /// CHECK-NOT: Deoptimize
   private static void doWhileDownOOB() {
     int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
@@ -887,14 +887,14 @@
   }
 
   /// CHECK-START: int[] Main.multiply1() BCE (before)
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: ArraySet
   //
   /// CHECK-START: int[] Main.multiply1() BCE (after)
   /// CHECK-NOT: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: ArraySet
+  /// CHECK: ArrayGet
+  /// CHECK: ArraySet
   /// CHECK-NOT: Deoptimize
   private static int[] multiply1() {
     int[] a = new int[10];
@@ -912,14 +912,14 @@
   }
 
   /// CHECK-START: int[] Main.multiply2() BCE (before)
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: ArraySet
   //
   /// CHECK-START: int[] Main.multiply2() BCE (after)
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: ArraySet
   static int[] multiply2() {
     int[] a = new int[10];
     try {
@@ -936,24 +936,24 @@
   }
 
   /// CHECK-START: int Main.linearDynamicBCE1(int[], int, int) BCE (before)
-  /// CHECK-DAG: StaticFieldGet
-  /// CHECK-DAG: NullCheck
-  /// CHECK-DAG: ArrayLength
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: StaticFieldSet
+  /// CHECK: StaticFieldGet
+  /// CHECK: NullCheck
+  /// CHECK: ArrayLength
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: StaticFieldSet
   //
   /// CHECK-START: int Main.linearDynamicBCE1(int[], int, int) BCE (after)
-  /// CHECK-DAG: StaticFieldGet
+  /// CHECK: StaticFieldGet
   /// CHECK-NOT: NullCheck
   /// CHECK-NOT: ArrayLength
   /// CHECK-NOT: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: StaticFieldSet
-  /// CHECK-DAG: Exit
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
+  /// CHECK: ArrayGet
+  /// CHECK: StaticFieldSet
+  /// CHECK: Exit
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
   private static int linearDynamicBCE1(int[] x, int lo, int hi) {
     int result = 0;
     for (int i = lo; i < hi; i++) {
@@ -963,24 +963,24 @@
   }
 
   /// CHECK-START: int Main.linearDynamicBCE2(int[], int, int, int) BCE (before)
-  /// CHECK-DAG: StaticFieldGet
-  /// CHECK-DAG: NullCheck
-  /// CHECK-DAG: ArrayLength
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: StaticFieldSet
+  /// CHECK: StaticFieldGet
+  /// CHECK: NullCheck
+  /// CHECK: ArrayLength
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: StaticFieldSet
   //
   /// CHECK-START: int Main.linearDynamicBCE2(int[], int, int, int) BCE (after)
-  /// CHECK-DAG: StaticFieldGet
+  /// CHECK: StaticFieldGet
   /// CHECK-NOT: NullCheck
   /// CHECK-NOT: ArrayLength
   /// CHECK-NOT: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: StaticFieldSet
-  /// CHECK-DAG: Exit
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
+  /// CHECK: ArrayGet
+  /// CHECK: StaticFieldSet
+  /// CHECK: Exit
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
   private static int linearDynamicBCE2(int[] x, int lo, int hi, int offset) {
     int result = 0;
     for (int i = lo; i < hi; i++) {
@@ -990,19 +990,19 @@
   }
 
   /// CHECK-START: int Main.wrapAroundDynamicBCE(int[]) BCE (before)
-  /// CHECK-DAG: NullCheck
-  /// CHECK-DAG: ArrayLength
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
+  /// CHECK: NullCheck
+  /// CHECK: ArrayLength
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
   //
   /// CHECK-START: int Main.wrapAroundDynamicBCE(int[]) BCE (after)
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
   /// CHECK-NOT: NullCheck
   /// CHECK-NOT: ArrayLength
   /// CHECK-NOT: BoundsCheck
-  /// CHECK-DAG: ArrayGet
+  /// CHECK: ArrayGet
   private static int wrapAroundDynamicBCE(int[] x) {
     int w = 9;
     int result = 0;
@@ -1014,19 +1014,19 @@
   }
 
   /// CHECK-START: int Main.periodicDynamicBCE(int[]) BCE (before)
-  /// CHECK-DAG: NullCheck
-  /// CHECK-DAG: ArrayLength
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
+  /// CHECK: NullCheck
+  /// CHECK: ArrayLength
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
   //
   /// CHECK-START: int Main.periodicDynamicBCE(int[]) BCE (after)
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
   /// CHECK-NOT: NullCheck
   /// CHECK-NOT: ArrayLength
   /// CHECK-NOT: BoundsCheck
-  /// CHECK-DAG: ArrayGet
+  /// CHECK: ArrayGet
   private static int periodicDynamicBCE(int[] x) {
     int k = 0;
     int result = 0;
@@ -1038,20 +1038,20 @@
   }
 
   /// CHECK-START: int Main.dynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (before)
-  /// CHECK-DAG: NullCheck
-  /// CHECK-DAG: ArrayLength
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
+  /// CHECK: NullCheck
+  /// CHECK: ArrayLength
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
   //
   /// CHECK-START: int Main.dynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after)
   /// CHECK-NOT: NullCheck
   /// CHECK-NOT: ArrayLength
   /// CHECK-NOT: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: Exit
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
+  /// CHECK: ArrayGet
+  /// CHECK: Exit
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
   static int dynamicBCEPossiblyInfiniteLoop(int[] x, int lo, int hi) {
     // This loop could be infinite for hi = max int. Since i is also used
     // as subscript, however, dynamic bce can proceed.
@@ -1063,16 +1063,16 @@
   }
 
   /// CHECK-START: int Main.noDynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (before)
-  /// CHECK-DAG: NullCheck
-  /// CHECK-DAG: ArrayLength
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
+  /// CHECK: NullCheck
+  /// CHECK: ArrayLength
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
   //
   /// CHECK-START: int Main.noDynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after)
-  /// CHECK-DAG: NullCheck
-  /// CHECK-DAG: ArrayLength
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
+  /// CHECK: NullCheck
+  /// CHECK: ArrayLength
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
   /// CHECK-NOT: Deoptimize
   static int noDynamicBCEPossiblyInfiniteLoop(int[] x, int lo, int hi) {
     // As above, but now the index is not used as subscript,
@@ -1085,16 +1085,16 @@
   }
 
   /// CHECK-START: int Main.noDynamicBCEMixedInductionTypes(int[], long, long) BCE (before)
-  /// CHECK-DAG: NullCheck
-  /// CHECK-DAG: ArrayLength
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
+  /// CHECK: NullCheck
+  /// CHECK: ArrayLength
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
   //
   /// CHECK-START: int Main.noDynamicBCEMixedInductionTypes(int[], long, long) BCE (after)
-  /// CHECK-DAG: NullCheck
-  /// CHECK-DAG: ArrayLength
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
+  /// CHECK: NullCheck
+  /// CHECK: ArrayLength
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
   /// CHECK-NOT: Deoptimize
   static int noDynamicBCEMixedInductionTypes(int[] x, long lo, long hi) {
     int result = 0;
@@ -1107,41 +1107,41 @@
   }
 
   /// CHECK-START: int Main.dynamicBCEAndConstantIndices(int[], int[][], int, int) BCE (before)
-  /// CHECK-DAG: NullCheck
-  /// CHECK-DAG: ArrayLength
-  /// CHECK-DAG: NotEqual
-  /// CHECK-DAG: If
-  /// CHECK-DAG: If
-  /// CHECK-DAG: NullCheck
-  /// CHECK-DAG: ArrayLength
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: If
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: NullCheck
+  /// CHECK: ArrayLength
+  /// CHECK: NotEqual
+  /// CHECK: If
+  /// CHECK: If
+  /// CHECK: NullCheck
+  /// CHECK: ArrayLength
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: If
+  /// CHECK: BoundsCheck
+  /// CHECK: BoundsCheck
+  /// CHECK: BoundsCheck
+  /// CHECK: BoundsCheck
+  /// CHECK: BoundsCheck
+  /// CHECK: BoundsCheck
   //
   /// CHECK-START: int Main.dynamicBCEAndConstantIndices(int[], int[][], int, int) BCE (after)
-  /// CHECK-DAG: NullCheck
-  /// CHECK-DAG: ArrayLength
-  /// CHECK-DAG: NotEqual
-  /// CHECK-DAG: If
-  /// CHECK-DAG: If
+  /// CHECK: NullCheck
+  /// CHECK: ArrayLength
+  /// CHECK: NotEqual
+  /// CHECK: If
+  /// CHECK: If
   /// CHECK-NOT: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: If
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: If
+  /// CHECK: Deoptimize
+  /// CHECK: BoundsCheck
+  /// CHECK: BoundsCheck
+  /// CHECK: BoundsCheck
   /// CHECK-NOT: BoundsCheck
-  /// CHECK-DAG: Exit
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
+  /// CHECK: Exit
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
   /// CHECK-NOT: ArrayGet
   static int dynamicBCEAndConstantIndices(int[] x, int[][] a, int lo, int hi) {
     // Deliberately test array length on a before the loop so that only bounds checks
@@ -1167,65 +1167,65 @@
   }
 
   /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], java.lang.Integer[], int, int) BCE (before)
-  /// CHECK-DAG: If
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
+  /// CHECK: If
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
   //
   /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], java.lang.Integer[], int, int) BCE (after)
-  /// CHECK-DAG: If
+  /// CHECK: If
   /// CHECK-NOT: BoundsCheck
-  /// CHECK-DAG: ArrayGet
+  /// CHECK: ArrayGet
   /// CHECK-NOT: BoundsCheck
   /// CHECK-NOT: ArrayGet
-  /// CHECK-DAG: Exit
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: ArrayGet
+  /// CHECK: Exit
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: ArrayGet
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: ArrayGet
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: ArrayGet
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: ArrayGet
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: ArrayGet
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: ArrayGet
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: ArrayGet
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: ArrayGet
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: ArrayGet
   static int dynamicBCEAndConstantIndicesAllTypes(int[] q,
                                                   boolean[] r,
                                                   byte[] s,