ART: Bit intrinsics for Mterp interpreter

Another batch of interpreter intrinisics, mostly around bit
manipulation.  Also some formatting changes and inclusion of a
comprehensive list of recognized intrinisics (to assist with
telling what's left to do).

Bug: 30933338

Benchmarks:
   20% Improvement for Reversi
   10% Improvement for Scimark2
    3% Improvement for ChessBench

Test: ART_TEST_INTERPRETER=true m test-art-host
Test: art/tools/run-libcore-tests --host (edited for force -Xint)

Note: Added intrinsics have existing test coverage via
082-inline-execute, 123-inline-execute2, 565-checker-rotate,
564-checker-bitcount, 566-checker-signum & 567-checker-compare

Change-Id: I29f0386e28eddba37c44f9ced44e7d5f8206bb47
diff --git a/runtime/base/bit_utils.h b/runtime/base/bit_utils.h
index 4041f5e..f536c72 100644
--- a/runtime/base/bit_utils.h
+++ b/runtime/base/bit_utils.h
@@ -27,6 +27,22 @@
 
 namespace art {
 
+// Like sizeof, but count how many bits a type takes. Pass type explicitly.
+template <typename T>
+constexpr size_t BitSizeOf() {
+  static_assert(std::is_integral<T>::value, "T must be integral");
+  using unsigned_type = typename std::make_unsigned<T>::type;
+  static_assert(sizeof(T) == sizeof(unsigned_type), "Unexpected type size mismatch!");
+  static_assert(std::numeric_limits<unsigned_type>::radix == 2, "Unexpected radix!");
+  return std::numeric_limits<unsigned_type>::digits;
+}
+
+// Like sizeof, but count how many bits a type takes. Infers type from parameter.
+template <typename T>
+constexpr size_t BitSizeOf(T /*x*/) {
+  return BitSizeOf<T>();
+}
+
 template<typename T>
 constexpr int CLZ(T x) {
   static_assert(std::is_integral<T>::value, "T must be integral");
@@ -37,6 +53,14 @@
   return (sizeof(T) == sizeof(uint32_t)) ? __builtin_clz(x) : __builtin_clzll(x);
 }
 
+// Similar to CLZ except that on zero input it returns bitwidth and supports signed integers.
+template<typename T>
+constexpr int JAVASTYLE_CLZ(T x) {
+  static_assert(std::is_integral<T>::value, "T must be integral");
+  using unsigned_type = typename std::make_unsigned<T>::type;
+  return (x == 0) ? BitSizeOf<T>() : CLZ(static_cast<unsigned_type>(x));
+}
+
 template<typename T>
 constexpr int CTZ(T x) {
   static_assert(std::is_integral<T>::value, "T must be integral");
@@ -48,12 +72,32 @@
   return (sizeof(T) == sizeof(uint32_t)) ? __builtin_ctz(x) : __builtin_ctzll(x);
 }
 
+// Similar to CTZ except that on zero input it returns bitwidth and supports signed integers.
+template<typename T>
+constexpr int JAVASTYLE_CTZ(T x) {
+  static_assert(std::is_integral<T>::value, "T must be integral");
+  using unsigned_type = typename std::make_unsigned<T>::type;
+  return (x == 0) ? BitSizeOf<T>() : CTZ(static_cast<unsigned_type>(x));
+}
+
 // Return the number of 1-bits in `x`.
 template<typename T>
 constexpr int POPCOUNT(T x) {
   return (sizeof(T) == sizeof(uint32_t)) ? __builtin_popcount(x) : __builtin_popcountll(x);
 }
 
+// Swap bytes.
+template<typename T>
+constexpr T BSWAP(T x) {
+  if (sizeof(T) == sizeof(uint16_t)) {
+    return __builtin_bswap16(x);
+  } else if (sizeof(T) == sizeof(uint32_t)) {
+    return __builtin_bswap32(x);
+  } else {
+    return __builtin_bswap64(x);
+  }
+}
+
 // Find the bit position of the most significant bit (0-based), or -1 if there were no bits set.
 template <typename T>
 constexpr ssize_t MostSignificantBit(T value) {
@@ -169,22 +213,6 @@
 #define DCHECK_ALIGNED_PARAM(value, alignment) \
   DCHECK(::art::IsAlignedParam(value, alignment)) << reinterpret_cast<const void*>(value)
 
-// Like sizeof, but count how many bits a type takes. Pass type explicitly.
-template <typename T>
-constexpr size_t BitSizeOf() {
-  static_assert(std::is_integral<T>::value, "T must be integral");
-  using unsigned_type = typename std::make_unsigned<T>::type;
-  static_assert(sizeof(T) == sizeof(unsigned_type), "Unexpected type size mismatch!");
-  static_assert(std::numeric_limits<unsigned_type>::radix == 2, "Unexpected radix!");
-  return std::numeric_limits<unsigned_type>::digits;
-}
-
-// Like sizeof, but count how many bits a type takes. Infers type from parameter.
-template <typename T>
-constexpr size_t BitSizeOf(T /*x*/) {
-  return BitSizeOf<T>();
-}
-
 inline uint16_t Low16Bits(uint32_t value) {
   return static_cast<uint16_t>(value);
 }
@@ -363,6 +391,59 @@
       HighToLowBitIterator<T>(bits), HighToLowBitIterator<T>());
 }
 
+// Returns value with bit set in lowest one-bit position or 0 if 0.  (java.lang.X.lowestOneBit).
+template <typename kind>
+inline static kind LowestOneBitValue(kind opnd) {
+  // Hacker's Delight, Section 2-1
+  return opnd & -opnd;
+}
+
+// Returns value with bit set in hightest one-bit position or 0 if 0.  (java.lang.X.highestOneBit).
+template <typename T>
+inline static T HighestOneBitValue(T opnd) {
+  using unsigned_type = typename std::make_unsigned<T>::type;
+  T res;
+  if (opnd == 0) {
+    res = 0;
+  } else {
+    int bit_position = BitSizeOf<T>() - (CLZ(static_cast<unsigned_type>(opnd)) + 1);
+    res = static_cast<T>(UINT64_C(1) << bit_position);
+  }
+  return res;
+}
+
+// Rotate bits.
+template <typename T, bool left>
+inline static T Rot(T opnd, int distance) {
+  int mask = BitSizeOf<T>() - 1;
+  int unsigned_right_shift = left ? (-distance & mask) : (distance & mask);
+  int signed_left_shift = left ? (distance & mask) : (-distance & mask);
+  using unsigned_type = typename std::make_unsigned<T>::type;
+  return (static_cast<unsigned_type>(opnd) >> unsigned_right_shift) | (opnd << signed_left_shift);
+}
+
+// TUNING: use rbit for arm/arm64
+inline static uint32_t ReverseBits32(uint32_t opnd) {
+  // Hacker's Delight 7-1
+  opnd = ((opnd >>  1) & 0x55555555) | ((opnd & 0x55555555) <<  1);
+  opnd = ((opnd >>  2) & 0x33333333) | ((opnd & 0x33333333) <<  2);
+  opnd = ((opnd >>  4) & 0x0F0F0F0F) | ((opnd & 0x0F0F0F0F) <<  4);
+  opnd = ((opnd >>  8) & 0x00FF00FF) | ((opnd & 0x00FF00FF) <<  8);
+  opnd = ((opnd >> 16)) | ((opnd) << 16);
+  return opnd;
+}
+
+// TUNING: use rbit for arm/arm64
+inline static uint64_t ReverseBits64(uint64_t opnd) {
+  // Hacker's Delight 7-1
+  opnd = (opnd & 0x5555555555555555L) << 1 | ((opnd >> 1) & 0x5555555555555555L);
+  opnd = (opnd & 0x3333333333333333L) << 2 | ((opnd >> 2) & 0x3333333333333333L);
+  opnd = (opnd & 0x0f0f0f0f0f0f0f0fL) << 4 | ((opnd >> 4) & 0x0f0f0f0f0f0f0f0fL);
+  opnd = (opnd & 0x00ff00ff00ff00ffL) << 8 | ((opnd >> 8) & 0x00ff00ff00ff00ffL);
+  opnd = (opnd << 48) | ((opnd & 0xffff0000L) << 16) | ((opnd >> 16) & 0xffff0000L) | (opnd >> 48);
+  return opnd;
+}
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_BASE_BIT_UTILS_H_
diff --git a/runtime/interpreter/interpreter_intrinsics.cc b/runtime/interpreter/interpreter_intrinsics.cc
index ff0c20e..0ae7307 100644
--- a/runtime/interpreter/interpreter_intrinsics.cc
+++ b/runtime/interpreter/interpreter_intrinsics.cc
@@ -20,19 +20,29 @@
 namespace art {
 namespace interpreter {
 
-#define BINARY_SIMPLE_INTRINSIC(name, op, get, set, offset)  \
-static ALWAYS_INLINE bool name(ShadowFrame* shadow_frame,    \
-                               const Instruction* inst,      \
-                               uint16_t inst_data,           \
-                               JValue* result_register)      \
-    REQUIRES_SHARED(Locks::mutator_lock_) {                  \
-  uint32_t arg[Instruction::kMaxVarArgRegs] = {};            \
-  inst->GetVarArgs(arg, inst_data);                          \
-  result_register->set(op(shadow_frame->get(arg[0]), shadow_frame->get(arg[offset]))); \
-  return true;                                               \
+
+#define BINARY_INTRINSIC(name, op, get1, get2, set)                 \
+static ALWAYS_INLINE bool name(ShadowFrame* shadow_frame,           \
+                               const Instruction* inst,             \
+                               uint16_t inst_data,                  \
+                               JValue* result_register)             \
+    REQUIRES_SHARED(Locks::mutator_lock_) {                         \
+  uint32_t arg[Instruction::kMaxVarArgRegs] = {};                   \
+  inst->GetVarArgs(arg, inst_data);                                 \
+  result_register->set(op(shadow_frame->get1, shadow_frame->get2)); \
+  return true;                                                      \
 }
 
-#define UNARY_SIMPLE_INTRINSIC(name, op, get, set)           \
+#define BINARY_II_INTRINSIC(name, op, set) \
+    BINARY_INTRINSIC(name, op, GetVReg(arg[0]), GetVReg(arg[1]), set)
+
+#define BINARY_JJ_INTRINSIC(name, op, set) \
+    BINARY_INTRINSIC(name, op, GetVRegLong(arg[0]), GetVRegLong(arg[2]), set)
+
+#define BINARY_JI_INTRINSIC(name, op, set) \
+    BINARY_INTRINSIC(name, op, GetVRegLong(arg[0]), GetVReg(arg[2]), set)
+
+#define UNARY_INTRINSIC(name, op, get, set)                  \
 static ALWAYS_INLINE bool name(ShadowFrame* shadow_frame,    \
                                const Instruction* inst,      \
                                uint16_t inst_data,           \
@@ -44,40 +54,126 @@
   return true;                                               \
 }
 
+
+// java.lang.Integer.reverse(I)I
+UNARY_INTRINSIC(MterpIntegerReverse, ReverseBits32, GetVReg, SetI);
+
+// java.lang.Integer.reverseBytes(I)I
+UNARY_INTRINSIC(MterpIntegerReverseBytes, BSWAP, GetVReg, SetI);
+
+// java.lang.Integer.bitCount(I)I
+UNARY_INTRINSIC(MterpIntegerBitCount, POPCOUNT, GetVReg, SetI);
+
+// java.lang.Integer.compare(II)I
+BINARY_II_INTRINSIC(MterpIntegerCompare, Compare, SetI);
+
+// java.lang.Integer.highestOneBit(I)I
+UNARY_INTRINSIC(MterpIntegerHighestOneBit, HighestOneBitValue, GetVReg, SetI);
+
+// java.lang.Integer.LowestOneBit(I)I
+UNARY_INTRINSIC(MterpIntegerLowestOneBit, LowestOneBitValue, GetVReg, SetI);
+
+// java.lang.Integer.numberOfLeadingZeros(I)I
+UNARY_INTRINSIC(MterpIntegerNumberOfLeadingZeros, JAVASTYLE_CLZ, GetVReg, SetI);
+
+// java.lang.Integer.numberOfTrailingZeros(I)I
+UNARY_INTRINSIC(MterpIntegerNumberOfTrailingZeros, JAVASTYLE_CTZ, GetVReg, SetI);
+
+// java.lang.Integer.rotateRight(II)I
+BINARY_II_INTRINSIC(MterpIntegerRotateRight, (Rot<int32_t, false>), SetI);
+
+// java.lang.Integer.rotateLeft(II)I
+BINARY_II_INTRINSIC(MterpIntegerRotateLeft, (Rot<int32_t, true>), SetI);
+
+// java.lang.Integer.signum(I)I
+UNARY_INTRINSIC(MterpIntegerSignum, Signum, GetVReg, SetI);
+
+// java.lang.Long.reverse(I)I
+UNARY_INTRINSIC(MterpLongReverse, ReverseBits64, GetVRegLong, SetJ);
+
+// java.lang.Long.reverseBytes(J)J
+UNARY_INTRINSIC(MterpLongReverseBytes, BSWAP, GetVRegLong, SetJ);
+
+// java.lang.Long.bitCount(J)I
+UNARY_INTRINSIC(MterpLongBitCount, POPCOUNT, GetVRegLong, SetI);
+
+// java.lang.Long.compare(JJ)I
+BINARY_JJ_INTRINSIC(MterpLongCompare, Compare, SetI);
+
+// java.lang.Long.highestOneBit(J)J
+UNARY_INTRINSIC(MterpLongHighestOneBit, HighestOneBitValue, GetVRegLong, SetJ);
+
+// java.lang.Long.lowestOneBit(J)J
+UNARY_INTRINSIC(MterpLongLowestOneBit, LowestOneBitValue, GetVRegLong, SetJ);
+
+// java.lang.Long.numberOfLeadingZeros(J)I
+UNARY_INTRINSIC(MterpLongNumberOfLeadingZeros, JAVASTYLE_CLZ, GetVRegLong, SetJ);
+
+// java.lang.Long.numberOfTrailingZeros(J)I
+UNARY_INTRINSIC(MterpLongNumberOfTrailingZeros, JAVASTYLE_CTZ, GetVRegLong, SetJ);
+
+// java.lang.Long.rotateRight(JI)J
+BINARY_JJ_INTRINSIC(MterpLongRotateRight, (Rot<int64_t, false>), SetJ);
+
+// java.lang.Long.rotateLeft(JI)J
+BINARY_JJ_INTRINSIC(MterpLongRotateLeft, (Rot<int64_t, true>), SetJ);
+
+// java.lang.Long.signum(J)I
+UNARY_INTRINSIC(MterpLongSignum, Signum, GetVRegLong, SetI);
+
+// java.lang.Short.reverseBytes(S)S
+UNARY_INTRINSIC(MterpShortReverseBytes, BSWAP, GetVRegShort, SetS);
+
 // java.lang.Math.min(II)I
-BINARY_SIMPLE_INTRINSIC(MterpMathMinIntInt, std::min, GetVReg, SetI, 1);
+BINARY_II_INTRINSIC(MterpMathMinIntInt, std::min, SetI);
+
 // java.lang.Math.min(JJ)J
-BINARY_SIMPLE_INTRINSIC(MterpMathMinLongLong, std::min, GetVRegLong, SetJ, 2);
+BINARY_JJ_INTRINSIC(MterpMathMinLongLong, std::min, SetJ);
+
 // java.lang.Math.max(II)I
-BINARY_SIMPLE_INTRINSIC(MterpMathMaxIntInt, std::max, GetVReg, SetI, 1);
+BINARY_II_INTRINSIC(MterpMathMaxIntInt, std::max, SetI);
+
 // java.lang.Math.max(JJ)J
-BINARY_SIMPLE_INTRINSIC(MterpMathMaxLongLong, std::max, GetVRegLong, SetJ, 2);
+BINARY_JJ_INTRINSIC(MterpMathMaxLongLong, std::max, SetJ);
+
 // java.lang.Math.abs(I)I
-UNARY_SIMPLE_INTRINSIC(MterpMathAbsInt, std::abs, GetVReg, SetI);
+UNARY_INTRINSIC(MterpMathAbsInt, std::abs, GetVReg, SetI);
+
 // java.lang.Math.abs(J)J
-UNARY_SIMPLE_INTRINSIC(MterpMathAbsLong, std::abs, GetVRegLong, SetJ);
+UNARY_INTRINSIC(MterpMathAbsLong, std::abs, GetVRegLong, SetJ);
+
 // java.lang.Math.abs(F)F
-UNARY_SIMPLE_INTRINSIC(MterpMathAbsFloat, 0x7fffffff&, GetVReg, SetI);
+UNARY_INTRINSIC(MterpMathAbsFloat, 0x7fffffff&, GetVReg, SetI);
+
 // java.lang.Math.abs(D)D
-UNARY_SIMPLE_INTRINSIC(MterpMathAbsDouble, INT64_C(0x7fffffffffffffff)&, GetVRegLong, SetJ);
+UNARY_INTRINSIC(MterpMathAbsDouble, INT64_C(0x7fffffffffffffff)&, GetVRegLong, SetJ);
+
 // java.lang.Math.sqrt(D)D
-UNARY_SIMPLE_INTRINSIC(MterpMathSqrt, std::sqrt, GetVRegDouble, SetD);
+UNARY_INTRINSIC(MterpMathSqrt, std::sqrt, GetVRegDouble, SetD);
+
 // java.lang.Math.ceil(D)D
-UNARY_SIMPLE_INTRINSIC(MterpMathCeil, std::ceil, GetVRegDouble, SetD);
+UNARY_INTRINSIC(MterpMathCeil, std::ceil, GetVRegDouble, SetD);
+
 // java.lang.Math.floor(D)D
-UNARY_SIMPLE_INTRINSIC(MterpMathFloor, std::floor, GetVRegDouble, SetD);
+UNARY_INTRINSIC(MterpMathFloor, std::floor, GetVRegDouble, SetD);
+
 // java.lang.Math.sin(D)D
-UNARY_SIMPLE_INTRINSIC(MterpMathSin, std::sin, GetVRegDouble, SetD);
+UNARY_INTRINSIC(MterpMathSin, std::sin, GetVRegDouble, SetD);
+
 // java.lang.Math.cos(D)D
-UNARY_SIMPLE_INTRINSIC(MterpMathCos, std::cos, GetVRegDouble, SetD);
+UNARY_INTRINSIC(MterpMathCos, std::cos, GetVRegDouble, SetD);
+
 // java.lang.Math.tan(D)D
-UNARY_SIMPLE_INTRINSIC(MterpMathTan, std::tan, GetVRegDouble, SetD);
+UNARY_INTRINSIC(MterpMathTan, std::tan, GetVRegDouble, SetD);
+
 // java.lang.Math.asin(D)D
-UNARY_SIMPLE_INTRINSIC(MterpMathAsin, std::asin, GetVRegDouble, SetD);
+UNARY_INTRINSIC(MterpMathAsin, std::asin, GetVRegDouble, SetD);
+
 // java.lang.Math.acos(D)D
-UNARY_SIMPLE_INTRINSIC(MterpMathAcos, std::acos, GetVRegDouble, SetD);
+UNARY_INTRINSIC(MterpMathAcos, std::acos, GetVRegDouble, SetD);
+
 // java.lang.Math.atan(D)D
-UNARY_SIMPLE_INTRINSIC(MterpMathAtan, std::atan, GetVRegDouble, SetD);
+UNARY_INTRINSIC(MterpMathAtan, std::atan, GetVRegDouble, SetD);
 
 // java.lang.String.charAt(I)C
 static ALWAYS_INLINE bool MterpStringCharAt(ShadowFrame* shadow_frame,
@@ -224,6 +320,12 @@
   return true;
 }
 
+// Macro to help keep track of what's left to implement.
+#define UNIMPLEMENTED_CASE(name)    \
+    case Intrinsics::k##name:       \
+      res = false;                  \
+      break;
+
 #define INTRINSIC_CASE(name)                                           \
     case Intrinsics::k##name:                                          \
       res = Mterp##name(shadow_frame, inst, inst_data, result_register); \
@@ -238,34 +340,136 @@
   Intrinsics intrinsic = static_cast<Intrinsics>(called_method->GetIntrinsic());
   bool res = false;  // Assume failure
   switch (intrinsic) {
-    INTRINSIC_CASE(MathMinIntInt)
-    INTRINSIC_CASE(MathMinLongLong)
-    INTRINSIC_CASE(MathMaxIntInt)
-    INTRINSIC_CASE(MathMaxLongLong)
-    INTRINSIC_CASE(MathAbsInt)
-    INTRINSIC_CASE(MathAbsLong)
-    INTRINSIC_CASE(MathAbsFloat)
+    UNIMPLEMENTED_CASE(DoubleDoubleToRawLongBits /* (D)J */)
+    UNIMPLEMENTED_CASE(DoubleDoubleToLongBits /* (D)J */)
+    UNIMPLEMENTED_CASE(DoubleIsInfinite /* (D)Z */)
+    UNIMPLEMENTED_CASE(DoubleIsNaN /* (D)Z */)
+    UNIMPLEMENTED_CASE(DoubleLongBitsToDouble /* (J)D */)
+    UNIMPLEMENTED_CASE(FloatFloatToRawIntBits /* (F)I */)
+    UNIMPLEMENTED_CASE(FloatFloatToIntBits /* (F)I */)
+    UNIMPLEMENTED_CASE(FloatIsInfinite /* (F)Z */)
+    UNIMPLEMENTED_CASE(FloatIsNaN /* (F)Z */)
+    UNIMPLEMENTED_CASE(FloatIntBitsToFloat /* (I)F */)
+    INTRINSIC_CASE(IntegerReverse)
+    INTRINSIC_CASE(IntegerReverseBytes)
+    INTRINSIC_CASE(IntegerBitCount)
+    INTRINSIC_CASE(IntegerCompare)
+    INTRINSIC_CASE(IntegerHighestOneBit)
+    INTRINSIC_CASE(IntegerLowestOneBit)
+    INTRINSIC_CASE(IntegerNumberOfLeadingZeros)
+    INTRINSIC_CASE(IntegerNumberOfTrailingZeros)
+    INTRINSIC_CASE(IntegerRotateRight)
+    INTRINSIC_CASE(IntegerRotateLeft)
+    INTRINSIC_CASE(IntegerSignum)
+    INTRINSIC_CASE(LongReverse)
+    INTRINSIC_CASE(LongReverseBytes)
+    INTRINSIC_CASE(LongBitCount)
+    INTRINSIC_CASE(LongCompare)
+    INTRINSIC_CASE(LongHighestOneBit)
+    INTRINSIC_CASE(LongLowestOneBit)
+    INTRINSIC_CASE(LongNumberOfLeadingZeros)
+    INTRINSIC_CASE(LongNumberOfTrailingZeros)
+    INTRINSIC_CASE(LongRotateRight)
+    INTRINSIC_CASE(LongRotateLeft)
+    INTRINSIC_CASE(LongSignum)
+    INTRINSIC_CASE(ShortReverseBytes)
     INTRINSIC_CASE(MathAbsDouble)
+    INTRINSIC_CASE(MathAbsFloat)
+    INTRINSIC_CASE(MathAbsLong)
+    INTRINSIC_CASE(MathAbsInt)
+    UNIMPLEMENTED_CASE(MathMinDoubleDouble /* (DD)D */)
+    UNIMPLEMENTED_CASE(MathMinFloatFloat /* (FF)F */)
+    INTRINSIC_CASE(MathMinLongLong)
+    INTRINSIC_CASE(MathMinIntInt)
+    UNIMPLEMENTED_CASE(MathMaxDoubleDouble /* (DD)D */)
+    UNIMPLEMENTED_CASE(MathMaxFloatFloat /* (FF)F */)
+    INTRINSIC_CASE(MathMaxLongLong)
+    INTRINSIC_CASE(MathMaxIntInt)
+    INTRINSIC_CASE(MathCos)
+    INTRINSIC_CASE(MathSin)
+    INTRINSIC_CASE(MathAcos)
+    INTRINSIC_CASE(MathAsin)
+    INTRINSIC_CASE(MathAtan)
+    UNIMPLEMENTED_CASE(MathAtan2 /* (DD)D */)
+    UNIMPLEMENTED_CASE(MathCbrt /* (D)D */)
+    UNIMPLEMENTED_CASE(MathCosh /* (D)D */)
+    UNIMPLEMENTED_CASE(MathExp /* (D)D */)
+    UNIMPLEMENTED_CASE(MathExpm1 /* (D)D */)
+    UNIMPLEMENTED_CASE(MathHypot /* (DD)D */)
+    UNIMPLEMENTED_CASE(MathLog /* (D)D */)
+    UNIMPLEMENTED_CASE(MathLog10 /* (D)D */)
+    UNIMPLEMENTED_CASE(MathNextAfter /* (DD)D */)
+    UNIMPLEMENTED_CASE(MathSinh /* (D)D */)
+    INTRINSIC_CASE(MathTan)
+    UNIMPLEMENTED_CASE(MathTanh /* (D)D */)
     INTRINSIC_CASE(MathSqrt)
     INTRINSIC_CASE(MathCeil)
     INTRINSIC_CASE(MathFloor)
-    INTRINSIC_CASE(MathSin)
-    INTRINSIC_CASE(MathCos)
-    INTRINSIC_CASE(MathTan)
-    INTRINSIC_CASE(MathAsin)
-    INTRINSIC_CASE(MathAcos)
-    INTRINSIC_CASE(MathAtan)
+    UNIMPLEMENTED_CASE(MathRint /* (D)D */)
+    UNIMPLEMENTED_CASE(MathRoundDouble /* (D)J */)
+    UNIMPLEMENTED_CASE(MathRoundFloat /* (F)I */)
+    UNIMPLEMENTED_CASE(SystemArrayCopyChar /* ([CI[CII)V */)
+    UNIMPLEMENTED_CASE(SystemArrayCopy /* (Ljava/lang/Object;ILjava/lang/Object;II)V */)
+    UNIMPLEMENTED_CASE(ThreadCurrentThread /* ()Ljava/lang/Thread; */)
+    UNIMPLEMENTED_CASE(MemoryPeekByte /* (J)B */)
+    UNIMPLEMENTED_CASE(MemoryPeekIntNative /* (J)I */)
+    UNIMPLEMENTED_CASE(MemoryPeekLongNative /* (J)J */)
+    UNIMPLEMENTED_CASE(MemoryPeekShortNative /* (J)S */)
+    UNIMPLEMENTED_CASE(MemoryPokeByte /* (JB)V */)
+    UNIMPLEMENTED_CASE(MemoryPokeIntNative /* (JI)V */)
+    UNIMPLEMENTED_CASE(MemoryPokeLongNative /* (JJ)V */)
+    UNIMPLEMENTED_CASE(MemoryPokeShortNative /* (JS)V */)
     INTRINSIC_CASE(StringCharAt)
     INTRINSIC_CASE(StringCompareTo)
-    INTRINSIC_CASE(StringIndexOf)
-    INTRINSIC_CASE(StringIndexOfAfter)
     INTRINSIC_CASE(StringEquals)
     INTRINSIC_CASE(StringGetCharsNoCheck)
+    INTRINSIC_CASE(StringIndexOf)
+    INTRINSIC_CASE(StringIndexOfAfter)
+    UNIMPLEMENTED_CASE(StringStringIndexOf /* (Ljava/lang/String;)I */)
+    UNIMPLEMENTED_CASE(StringStringIndexOfAfter /* (Ljava/lang/String;I)I */)
     INTRINSIC_CASE(StringIsEmpty)
     INTRINSIC_CASE(StringLength)
-    default:
-      res = false;  // Punt
+    UNIMPLEMENTED_CASE(StringNewStringFromBytes /* ([BIII)Ljava/lang/String; */)
+    UNIMPLEMENTED_CASE(StringNewStringFromChars /* (II[C)Ljava/lang/String; */)
+    UNIMPLEMENTED_CASE(StringNewStringFromString /* (Ljava/lang/String;)Ljava/lang/String; */)
+    UNIMPLEMENTED_CASE(StringBufferAppend /* (Ljava/lang/String;)Ljava/lang/StringBuffer; */)
+    UNIMPLEMENTED_CASE(StringBufferLength /* ()I */)
+    UNIMPLEMENTED_CASE(StringBufferToString /* ()Ljava/lang/String; */)
+    UNIMPLEMENTED_CASE(StringBuilderAppend /* (Ljava/lang/String;)Ljava/lang/StringBuilder; */)
+    UNIMPLEMENTED_CASE(StringBuilderLength /* ()I */)
+    UNIMPLEMENTED_CASE(StringBuilderToString /* ()Ljava/lang/String; */)
+    UNIMPLEMENTED_CASE(UnsafeCASInt /* (Ljava/lang/Object;JII)Z */)
+    UNIMPLEMENTED_CASE(UnsafeCASLong /* (Ljava/lang/Object;JJJ)Z */)
+    UNIMPLEMENTED_CASE(UnsafeCASObject /* (Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z */)
+    UNIMPLEMENTED_CASE(UnsafeGet /* (Ljava/lang/Object;J)I */)
+    UNIMPLEMENTED_CASE(UnsafeGetVolatile /* (Ljava/lang/Object;J)I */)
+    UNIMPLEMENTED_CASE(UnsafeGetObject /* (Ljava/lang/Object;J)Ljava/lang/Object; */)
+    UNIMPLEMENTED_CASE(UnsafeGetObjectVolatile /* (Ljava/lang/Object;J)Ljava/lang/Object; */)
+    UNIMPLEMENTED_CASE(UnsafeGetLong /* (Ljava/lang/Object;J)J */)
+    UNIMPLEMENTED_CASE(UnsafeGetLongVolatile /* (Ljava/lang/Object;J)J */)
+    UNIMPLEMENTED_CASE(UnsafePut /* (Ljava/lang/Object;JI)V */)
+    UNIMPLEMENTED_CASE(UnsafePutOrdered /* (Ljava/lang/Object;JI)V */)
+    UNIMPLEMENTED_CASE(UnsafePutVolatile /* (Ljava/lang/Object;JI)V */)
+    UNIMPLEMENTED_CASE(UnsafePutObject /* (Ljava/lang/Object;JLjava/lang/Object;)V */)
+    UNIMPLEMENTED_CASE(UnsafePutObjectOrdered /* (Ljava/lang/Object;JLjava/lang/Object;)V */)
+    UNIMPLEMENTED_CASE(UnsafePutObjectVolatile /* (Ljava/lang/Object;JLjava/lang/Object;)V */)
+    UNIMPLEMENTED_CASE(UnsafePutLong /* (Ljava/lang/Object;JJ)V */)
+    UNIMPLEMENTED_CASE(UnsafePutLongOrdered /* (Ljava/lang/Object;JJ)V */)
+    UNIMPLEMENTED_CASE(UnsafePutLongVolatile /* (Ljava/lang/Object;JJ)V */)
+    UNIMPLEMENTED_CASE(UnsafeGetAndAddInt /* (Ljava/lang/Object;JI)I */)
+    UNIMPLEMENTED_CASE(UnsafeGetAndAddLong /* (Ljava/lang/Object;JJ)J */)
+    UNIMPLEMENTED_CASE(UnsafeGetAndSetInt /* (Ljava/lang/Object;JI)I */)
+    UNIMPLEMENTED_CASE(UnsafeGetAndSetLong /* (Ljava/lang/Object;JJ)J */)
+    UNIMPLEMENTED_CASE(UnsafeGetAndSetObject /* (Ljava/lang/Object;JLjava/lang/Object;)Ljava/lang/Object; */)
+    UNIMPLEMENTED_CASE(UnsafeLoadFence /* ()V */)
+    UNIMPLEMENTED_CASE(UnsafeStoreFence /* ()V */)
+    UNIMPLEMENTED_CASE(UnsafeFullFence /* ()V */)
+    UNIMPLEMENTED_CASE(ReferenceGetReferent /* ()Ljava/lang/Object; */)
+    UNIMPLEMENTED_CASE(IntegerValueOf /* (I)Ljava/lang/Integer; */)
+    case Intrinsics::kNone:
+      res = false;
       break;
+    // Note: no default case to ensure we catch any newly added intrinsics.
   }
   return res;
 }
diff --git a/runtime/stack.h b/runtime/stack.h
index 90a0aee..5c9614a 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -197,6 +197,11 @@
     return *reinterpret_cast<const int32_t*>(vreg);
   }
 
+  // Shorts are extended to Ints in VRegs.  Interpreter intrinsics needs them as shorts.
+  int16_t GetVRegShort(size_t i) const {
+    return static_cast<int16_t>(GetVReg(i));
+  }
+
   uint32_t* GetVRegAddr(size_t i) {
     return &vregs_[i];
   }
diff --git a/runtime/utils.h b/runtime/utils.h
index 96e5bfa..24fd205 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -325,6 +325,18 @@
   return size;
 }
 
+// Return -1 if <, 0 if ==, 1 if >.
+template <typename T>
+inline static int32_t Compare(T lhs, T rhs) {
+  return (lhs < rhs) ? -1 : ((lhs == rhs) ? 0 : 1);
+}
+
+// Return -1 if < 0, 0 if == 0, 1 if > 0.
+template <typename T>
+inline static int32_t Signum(T opnd) {
+  return (opnd < 0) ? -1 : ((opnd == 0) ? 0 : 1);
+}
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_UTILS_H_