Revert "Revert "Add support for long-to-int in the optimizing compiler.""

This reverts commit 3adfd1b4fb20ac2b0217b5d2737bfe30ad90257a.

Change-Id: Iacf0c6492d49267e24f1b727dbf6379b21fd02db
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 8418ab0..e95dbb8 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -922,6 +922,11 @@
       break;
     }
 
+    case Instruction::LONG_TO_INT: {
+      Conversion_12x(instruction, Primitive::kPrimLong, Primitive::kPrimInt);
+      break;
+    }
+
     case Instruction::ADD_INT: {
       Binop_23x<HAdd>(instruction, Primitive::kPrimInt);
       break;
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 467c2a6..0269746 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -22,9 +22,9 @@
 #include "mirror/art_method.h"
 #include "mirror/class.h"
 #include "thread.h"
-#include "utils/assembler.h"
 #include "utils/arm/assembler_arm.h"
 #include "utils/arm/managed_register_arm.h"
+#include "utils/assembler.h"
 #include "utils/stack_checks.h"
 
 namespace art {
@@ -1333,6 +1333,26 @@
   Primitive::Type result_type = conversion->GetResultType();
   Primitive::Type input_type = conversion->GetInputType();
   switch (result_type) {
+    case Primitive::kPrimInt:
+      switch (input_type) {
+        case Primitive::kPrimLong:
+          // long-to-int conversion.
+          locations->SetInAt(0, Location::Any());
+          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+          break;
+
+        case Primitive::kPrimFloat:
+        case Primitive::kPrimDouble:
+          LOG(FATAL) << "Type conversion from " << input_type
+                     << " to " << result_type << " not yet implemented";
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
     case Primitive::kPrimLong:
       switch (input_type) {
         case Primitive::kPrimByte:
@@ -1356,7 +1376,6 @@
       }
       break;
 
-    case Primitive::kPrimInt:
     case Primitive::kPrimFloat:
     case Primitive::kPrimDouble:
       LOG(FATAL) << "Type conversion from " << input_type
@@ -1376,6 +1395,35 @@
   Primitive::Type result_type = conversion->GetResultType();
   Primitive::Type input_type = conversion->GetInputType();
   switch (result_type) {
+    case Primitive::kPrimInt:
+      switch (input_type) {
+        case Primitive::kPrimLong:
+          // long-to-int conversion.
+          DCHECK(out.IsRegister());
+          if (in.IsRegisterPair()) {
+            __ Mov(out.As<Register>(), in.AsRegisterPairLow<Register>());
+          } else if (in.IsDoubleStackSlot()) {
+            __ LoadFromOffset(kLoadWord, out.As<Register>(), SP, in.GetStackIndex());
+          } else {
+            DCHECK(in.IsConstant());
+            DCHECK(in.GetConstant()->IsLongConstant());
+            int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
+            __ LoadImmediate(out.As<Register>(), static_cast<int32_t>(value));
+          }
+          break;
+
+        case Primitive::kPrimFloat:
+        case Primitive::kPrimDouble:
+          LOG(FATAL) << "Type conversion from " << input_type
+                     << " to " << result_type << " not yet implemented";
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
     case Primitive::kPrimLong:
       switch (input_type) {
         case Primitive::kPrimByte:
@@ -1404,7 +1452,6 @@
       }
       break;
 
-    case Primitive::kPrimInt:
     case Primitive::kPrimFloat:
     case Primitive::kPrimDouble:
       LOG(FATAL) << "Type conversion from " << input_type
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index d66180b..985ce8d 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -1261,6 +1261,26 @@
   Primitive::Type result_type = conversion->GetResultType();
   Primitive::Type input_type = conversion->GetInputType();
   switch (result_type) {
+    case Primitive::kPrimInt:
+      switch (input_type) {
+        case Primitive::kPrimLong:
+          // long-to-int conversion.
+          locations->SetInAt(0, Location::Any());
+          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+          break;
+
+        case Primitive::kPrimFloat:
+        case Primitive::kPrimDouble:
+          LOG(FATAL) << "Type conversion from " << input_type
+                     << " to " << result_type << " not yet implemented";
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
     case Primitive::kPrimLong:
       switch (input_type) {
         case Primitive::kPrimByte:
@@ -1284,7 +1304,6 @@
       }
       break;
 
-    case Primitive::kPrimInt:
     case Primitive::kPrimFloat:
     case Primitive::kPrimDouble:
       LOG(FATAL) << "Type conversion from " << input_type
@@ -1304,6 +1323,34 @@
   Primitive::Type result_type = conversion->GetResultType();
   Primitive::Type input_type = conversion->GetInputType();
   switch (result_type) {
+    case Primitive::kPrimInt:
+      switch (input_type) {
+        case Primitive::kPrimLong:
+          // long-to-int conversion.
+          if (in.IsRegisterPair()) {
+            __ movl(out.As<Register>(), in.AsRegisterPairLow<Register>());
+          } else if (in.IsDoubleStackSlot()) {
+            __ movl(out.As<Register>(), Address(ESP, in.GetStackIndex()));
+          } else {
+            DCHECK(in.IsConstant());
+            DCHECK(in.GetConstant()->IsLongConstant());
+            int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
+            __ movl(out.As<Register>(), Immediate(static_cast<int32_t>(value)));
+          }
+          break;
+
+        case Primitive::kPrimFloat:
+        case Primitive::kPrimDouble:
+          LOG(FATAL) << "Type conversion from " << input_type
+                     << " to " << result_type << " not yet implemented";
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
     case Primitive::kPrimLong:
       switch (input_type) {
         case Primitive::kPrimByte:
@@ -1329,7 +1376,6 @@
       }
       break;
 
-    case Primitive::kPrimInt:
     case Primitive::kPrimFloat:
     case Primitive::kPrimDouble:
       LOG(FATAL) << "Type conversion from " << input_type
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index e09b6ca..9a2a745 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -1259,6 +1259,26 @@
   Primitive::Type result_type = conversion->GetResultType();
   Primitive::Type input_type = conversion->GetInputType();
   switch (result_type) {
+    case Primitive::kPrimInt:
+      switch (input_type) {
+        case Primitive::kPrimLong:
+          // long-to-int conversion.
+          locations->SetInAt(0, Location::Any());
+          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+          break;
+
+        case Primitive::kPrimFloat:
+        case Primitive::kPrimDouble:
+          LOG(FATAL) << "Type conversion from " << input_type
+                     << " to " << result_type << " not yet implemented";
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
     case Primitive::kPrimLong:
       switch (input_type) {
         case Primitive::kPrimByte:
@@ -1284,7 +1304,6 @@
       }
       break;
 
-    case Primitive::kPrimInt:
     case Primitive::kPrimFloat:
     case Primitive::kPrimDouble:
       LOG(FATAL) << "Type conversion from " << input_type
@@ -1304,6 +1323,35 @@
   Primitive::Type result_type = conversion->GetResultType();
   Primitive::Type input_type = conversion->GetInputType();
   switch (result_type) {
+    case Primitive::kPrimInt:
+      switch (input_type) {
+        case Primitive::kPrimLong:
+          // long-to-int conversion.
+          if (in.IsRegister()) {
+            __ movl(out.As<CpuRegister>(), in.As<CpuRegister>());
+          } else if (in.IsDoubleStackSlot()) {
+            __ movl(out.As<CpuRegister>(),
+                    Address(CpuRegister(RSP), in.GetStackIndex()));
+          } else {
+            DCHECK(in.IsConstant());
+            DCHECK(in.GetConstant()->IsLongConstant());
+            int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
+            __ movl(out.As<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
+          }
+          break;
+
+        case Primitive::kPrimFloat:
+        case Primitive::kPrimDouble:
+          LOG(FATAL) << "Type conversion from " << input_type
+                     << " to " << result_type << " not yet implemented";
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
     case Primitive::kPrimLong:
       switch (input_type) {
         DCHECK(out.IsRegister());
@@ -1328,7 +1376,6 @@
       }
       break;
 
-    case Primitive::kPrimInt:
     case Primitive::kPrimFloat:
     case Primitive::kPrimDouble:
       LOG(FATAL) << "Type conversion from " << input_type
diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc
index ecee443..9752b1d 100644
--- a/compiler/optimizing/codegen_test.cc
+++ b/compiler/optimizing/codegen_test.cc
@@ -362,6 +362,27 @@
 
 #undef NOT_LONG_TEST
 
+#if defined(__aarch64__)
+TEST(CodegenTest, DISABLED_IntToLongOfLongToInt) {
+#else
+TEST(CodegenTest, IntToLongOfLongToInt) {
+#endif
+  const int64_t input = INT64_C(4294967296);             // 2^32
+  const uint16_t word0 = Low16Bits(Low32Bits(input));    // LSW.
+  const uint16_t word1 = High16Bits(Low32Bits(input));
+  const uint16_t word2 = Low16Bits(High32Bits(input));
+  const uint16_t word3 = High16Bits(High32Bits(input));  // MSW.
+  const uint16_t data[] = FIVE_REGISTERS_CODE_ITEM(
+      Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,
+      Instruction::CONST_WIDE | 2 << 8, 1, 0, 0, 0,
+      Instruction::ADD_LONG | 0, 0 << 8 | 2,             // v0 <- 2^32 + 1
+      Instruction::LONG_TO_INT | 4 << 8 | 0 << 12,
+      Instruction::INT_TO_LONG | 2 << 8 | 4 << 12,
+      Instruction::RETURN_WIDE | 2 << 8);
+
+  TestCodeLong(data, true, 1);
+}
+
 TEST(CodegenTest, ReturnAdd1) {
   const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 3 << 12 | 0,
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index 5b70658..af2dc95 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -120,6 +120,7 @@
 
 
 void X86_64Assembler::movl(CpuRegister dst, const Immediate& imm) {
+  CHECK(imm.is_int32());
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitOptionalRex32(dst);
   EmitUint8(0xB8 + dst.LowBits());
diff --git a/test/415-optimizing-arith-neg/src/Main.java b/test/415-optimizing-arith-neg/src/Main.java
index e2850ca..d9f8bcf 100644
--- a/test/415-optimizing-arith-neg/src/Main.java
+++ b/test/415-optimizing-arith-neg/src/Main.java
@@ -71,8 +71,8 @@
     assertEquals(0, $opt$NegInt(0));
     assertEquals(51, $opt$NegInt(-51));
     assertEquals(-51, $opt$NegInt(51));
-    assertEquals(2147483647, $opt$NegInt(-2147483647));  // (2^31 - 1)
-    assertEquals(-2147483647, $opt$NegInt(2147483647));  // -(2^31 - 1)
+    assertEquals(2147483647, $opt$NegInt(-2147483647));  // -(2^31 - 1)
+    assertEquals(-2147483647, $opt$NegInt(2147483647));  // 2^31 - 1
     // From the Java 7 SE Edition specification:
     // http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.15.4
     //
@@ -98,13 +98,13 @@
     assertEquals(51L, $opt$NegLong(-51L));
     assertEquals(-51L, $opt$NegLong(51L));
 
-    assertEquals(2147483647L, $opt$NegLong(-2147483647L));  // (2^31 - 1)
-    assertEquals(-2147483647L, $opt$NegLong(2147483647L));  // -(2^31 - 1)
-    assertEquals(2147483648L, $opt$NegLong(-2147483648L));  // 2^31
-    assertEquals(-2147483648L, $opt$NegLong(2147483648L));  // -(2^31)
+    assertEquals(2147483647L, $opt$NegLong(-2147483647L));  // -(2^31 - 1)
+    assertEquals(-2147483647L, $opt$NegLong(2147483647L));  // (2^31 - 1)
+    assertEquals(2147483648L, $opt$NegLong(-2147483648L));  // -(2^31)
+    assertEquals(-2147483648L, $opt$NegLong(2147483648L));  // 2^31
 
-    assertEquals(9223372036854775807L, $opt$NegLong(-9223372036854775807L));  // (2^63 - 1)
-    assertEquals(-9223372036854775807L, $opt$NegLong(9223372036854775807L));  // -(2^63 - 1)
+    assertEquals(9223372036854775807L, $opt$NegLong(-9223372036854775807L));  // -(2^63 - 1)
+    assertEquals(-9223372036854775807L, $opt$NegLong(9223372036854775807L));  // 2^63 - 1
     // See remark regarding the negation of the maximum negative
     // (long) value in negInt().
     assertEquals(-9223372036854775808L, $opt$NegLong(-9223372036854775808L)); // -(2^63)
diff --git a/test/416-optimizing-arith-not/src/Main.java b/test/416-optimizing-arith-not/src/Main.java
index 26e206c..44c7d3c 100644
--- a/test/416-optimizing-arith-not/src/Main.java
+++ b/test/416-optimizing-arith-not/src/Main.java
@@ -40,10 +40,10 @@
     expectEquals(0, smaliNotInt(-1));
     expectEquals(-1, smaliNotInt(0));
     expectEquals(-2, smaliNotInt(1));
-    expectEquals(2147483647, smaliNotInt(-2147483648));  // (2^31) - 1
-    expectEquals(2147483646, smaliNotInt(-2147483647));  // (2^31) - 2
-    expectEquals(-2147483647, smaliNotInt(2147483646));  // -(2^31) - 1
-    expectEquals(-2147483648, smaliNotInt(2147483647));  // -(2^31)
+    expectEquals(2147483647, smaliNotInt(-2147483648));  // -(2^31)
+    expectEquals(2147483646, smaliNotInt(-2147483647));  // -(2^31 - 1)
+    expectEquals(-2147483647, smaliNotInt(2147483646));  // 2^31 - 2
+    expectEquals(-2147483648, smaliNotInt(2147483647));  // 2^31 - 1
   }
 
   private static void notLong() throws Exception {
@@ -51,14 +51,14 @@
     expectEquals(0L, smaliNotLong(-1L));
     expectEquals(-1L, smaliNotLong(0L));
     expectEquals(-2L, smaliNotLong(1L));
-    expectEquals(2147483647L, smaliNotLong(-2147483648L));  // (2^31) - 1
-    expectEquals(2147483646L, smaliNotLong(-2147483647L));  // (2^31) - 2
-    expectEquals(-2147483647L, smaliNotLong(2147483646L));  // -(2^31) - 1
-    expectEquals(-2147483648L, smaliNotLong(2147483647L));  // -(2^31)
-    expectEquals(9223372036854775807L, smaliNotLong(-9223372036854775808L));  // (2^63) - 1
-    expectEquals(9223372036854775806L, smaliNotLong(-9223372036854775807L));  // (2^63) - 2
-    expectEquals(-9223372036854775807L, smaliNotLong(9223372036854775806L));  // -(2^63) - 1
-    expectEquals(-9223372036854775808L, smaliNotLong(9223372036854775807L));  // -(2^63)
+    expectEquals(2147483647L, smaliNotLong(-2147483648L));  // -(2^31)
+    expectEquals(2147483646L, smaliNotLong(-2147483647L));  // -(2^31 - 1)
+    expectEquals(-2147483647L, smaliNotLong(2147483646L));  // 2^31 - 2
+    expectEquals(-2147483648L, smaliNotLong(2147483647L));  // 2^31 - 1
+    expectEquals(9223372036854775807L, smaliNotLong(-9223372036854775808L));  // -(2^63)
+    expectEquals(9223372036854775806L, smaliNotLong(-9223372036854775807L));  // -(2^63 - 1)
+    expectEquals(-9223372036854775807L, smaliNotLong(9223372036854775806L));  // 2^63 - 2
+    expectEquals(-9223372036854775808L, smaliNotLong(9223372036854775807L));  // 2^63 - 1
   }
 
   // Wrappers around methods located in file not.smali.
diff --git a/test/422-type-conversion/src/Main.java b/test/422-type-conversion/src/Main.java
index d61f255..a4232ed 100644
--- a/test/422-type-conversion/src/Main.java
+++ b/test/422-type-conversion/src/Main.java
@@ -18,7 +18,13 @@
 // it does compile the method.
 public class Main {
 
-  public static void assertEquals(long expected, long result) {
+  public static void assertIntEquals(int expected, int result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void assertLongEquals(long expected, long result) {
     if (expected != result) {
       throw new Error("Expected: " + expected + ", found: " + result);
     }
@@ -26,63 +32,96 @@
 
   public static void main(String[] args) {
     byteToLong();
-    charToLong();
     shortToLong();
     intToLong();
+    charToLong();
+
+    longToInt();
   }
 
   private static void byteToLong() {
-    assertEquals(1L, $opt$ByteToLong((byte)1));
-    assertEquals(0L, $opt$ByteToLong((byte)0));
-    assertEquals(-1L, $opt$ByteToLong((byte)-1));
-    assertEquals(51L, $opt$ByteToLong((byte)51));
-    assertEquals(-51L, $opt$ByteToLong((byte)-51));
-    assertEquals(127L, $opt$ByteToLong((byte)127));  // (2^7) - 1
-    assertEquals(-127L, $opt$ByteToLong((byte)-127));  // -(2^7) - 1
-    assertEquals(-128L, $opt$ByteToLong((byte)-128));  // -(2^7)
+    assertLongEquals(1L, $opt$ByteToLong((byte)1));
+    assertLongEquals(0L, $opt$ByteToLong((byte)0));
+    assertLongEquals(-1L, $opt$ByteToLong((byte)-1));
+    assertLongEquals(51L, $opt$ByteToLong((byte)51));
+    assertLongEquals(-51L, $opt$ByteToLong((byte)-51));
+    assertLongEquals(127L, $opt$ByteToLong((byte)127));  // 2^7 - 1
+    assertLongEquals(-127L, $opt$ByteToLong((byte)-127));  // -(2^7 - 1)
+    assertLongEquals(-128L, $opt$ByteToLong((byte)-128));  // -(2^7)
   }
 
   private static void shortToLong() {
-    assertEquals(1L, $opt$ShortToLong((short)1));
-    assertEquals(0L, $opt$ShortToLong((short)0));
-    assertEquals(-1L, $opt$ShortToLong((short)-1));
-    assertEquals(51L, $opt$ShortToLong((short)51));
-    assertEquals(-51L, $opt$ShortToLong((short)-51));
-    assertEquals(32767L, $opt$ShortToLong((short)32767));  // (2^15) - 1
-    assertEquals(-32767L, $opt$ShortToLong((short)-32767));  // -(2^15) - 1
-    assertEquals(-32768L, $opt$ShortToLong((short)-32768));  // -(2^15)
+    assertLongEquals(1L, $opt$ShortToLong((short)1));
+    assertLongEquals(0L, $opt$ShortToLong((short)0));
+    assertLongEquals(-1L, $opt$ShortToLong((short)-1));
+    assertLongEquals(51L, $opt$ShortToLong((short)51));
+    assertLongEquals(-51L, $opt$ShortToLong((short)-51));
+    assertLongEquals(32767L, $opt$ShortToLong((short)32767));  // 2^15 - 1
+    assertLongEquals(-32767L, $opt$ShortToLong((short)-32767));  // -(2^15 - 1)
+    assertLongEquals(-32768L, $opt$ShortToLong((short)-32768));  // -(2^15)
   }
 
   private static void intToLong() {
-    assertEquals(1L, $opt$IntToLong(1));
-    assertEquals(0L, $opt$IntToLong(0));
-    assertEquals(-1L, $opt$IntToLong(-1));
-    assertEquals(51L, $opt$IntToLong(51));
-    assertEquals(-51L, $opt$IntToLong(-51));
-    assertEquals(2147483647L, $opt$IntToLong(2147483647));  // (2^31) - 1
-    assertEquals(-2147483647L, $opt$IntToLong(-2147483647));  // -(2^31) - 1
-    assertEquals(-2147483648L, $opt$IntToLong(-2147483648));  // -(2^31)
+    assertLongEquals(1L, $opt$IntToLong(1));
+    assertLongEquals(0L, $opt$IntToLong(0));
+    assertLongEquals(-1L, $opt$IntToLong(-1));
+    assertLongEquals(51L, $opt$IntToLong(51));
+    assertLongEquals(-51L, $opt$IntToLong(-51));
+    assertLongEquals(2147483647L, $opt$IntToLong(2147483647));  // 2^31 - 1
+    assertLongEquals(-2147483647L, $opt$IntToLong(-2147483647));  // -(2^31 - 1)
+    assertLongEquals(-2147483648L, $opt$IntToLong(-2147483648));  // -(2^31)
   }
 
   private static void charToLong() {
-    assertEquals(1L, $opt$CharToLong((char)1));
-    assertEquals(0L, $opt$CharToLong((char)0));
-    assertEquals(51L, $opt$CharToLong((char)51));
-    assertEquals(32767L, $opt$CharToLong((char)32767));  // (2^15) - 1
-    assertEquals(65535L, $opt$CharToLong((char)65535));  // (2^16) - 1
+    assertLongEquals(1L, $opt$CharToLong((char)1));
+    assertLongEquals(0L, $opt$CharToLong((char)0));
+    assertLongEquals(51L, $opt$CharToLong((char)51));
+    assertLongEquals(32767L, $opt$CharToLong((char)32767));  // 2^15 - 1
+    assertLongEquals(65535L, $opt$CharToLong((char)65535));  // 2^16 - 1
 
-    assertEquals(0L, $opt$CharToLong('\u0000'));
-    assertEquals(65535L, $opt$CharToLong('\uFFFF'));  // (2^16) - 1
+    assertLongEquals(0L, $opt$CharToLong('\u0000'));
+    assertLongEquals(65535L, $opt$CharToLong('\uFFFF'));  // 2^16 - 1
 
-    assertEquals(65535L, $opt$CharToLong((char)-1));
-    assertEquals(65485L, $opt$CharToLong((char)-51));
-    assertEquals(32769L, $opt$CharToLong((char)-32767));  // -(2^15) - 1
-    assertEquals(32768L, $opt$CharToLong((char)-32768));  // -(2^15)
+    assertLongEquals(65535L, $opt$CharToLong((char)-1));
+    assertLongEquals(65485L, $opt$CharToLong((char)-51));
+    assertLongEquals(32769L, $opt$CharToLong((char)-32767));  // -(2^15 - 1)
+    assertLongEquals(32768L, $opt$CharToLong((char)-32768));  // -(2^15)
   }
 
-  // All these methods produce an int-to-long Dex instruction.
+  private static void longToInt() {
+    assertIntEquals(1, $opt$LongToInt(1L));
+    assertIntEquals(0, $opt$LongToInt(0L));
+    assertIntEquals(-1, $opt$LongToInt(-1L));
+    assertIntEquals(51, $opt$LongToInt(51L));
+    assertIntEquals(-51, $opt$LongToInt(-51L));
+    assertIntEquals(2147483647, $opt$LongToInt(2147483647L));  // 2^31 - 1
+    assertIntEquals(-2147483647, $opt$LongToInt(-2147483647L));  // -(2^31 - 1)
+    assertIntEquals(-2147483648, $opt$LongToInt(-2147483648L));  // -(2^31)
+    assertIntEquals(-2147483648, $opt$LongToInt(2147483648L));  // (2^31)
+    assertIntEquals(2147483647, $opt$LongToInt(-2147483649L));  // -(2^31 + 1)
+    assertIntEquals(-1, $opt$LongToInt(9223372036854775807L));  // 2^63 - 1
+    assertIntEquals(1, $opt$LongToInt(-9223372036854775807L));  // -(2^63 - 1)
+    assertIntEquals(0, $opt$LongToInt(-9223372036854775808L));  // -(2^63)
+
+    assertIntEquals(42, $opt$LongLiteralToInt());
+
+    // Ensure long-to-int conversions truncates values as expected.
+    assertLongEquals(1L, $opt$IntToLong($opt$LongToInt(4294967297L)));  // 2^32 + 1
+    assertLongEquals(0L, $opt$IntToLong($opt$LongToInt(4294967296L)));  // 2^32
+    assertLongEquals(-1L, $opt$IntToLong($opt$LongToInt(4294967295L)));  // 2^32 - 1
+    assertLongEquals(0L, $opt$IntToLong($opt$LongToInt(0L)));
+    assertLongEquals(1L, $opt$IntToLong($opt$LongToInt(-4294967295L)));  // -(2^32 - 1)
+    assertLongEquals(0L, $opt$IntToLong($opt$LongToInt(-4294967296L)));  // -(2^32)
+    assertLongEquals(-1, $opt$IntToLong($opt$LongToInt(-4294967297L)));  // -(2^32 + 1)
+  }
+
+  // These methods produce int-to-long Dex instructions.
   static long $opt$ByteToLong(byte a) { return a; }
   static long $opt$ShortToLong(short a) { return a; }
   static long $opt$IntToLong(int a) { return a; }
   static long $opt$CharToLong(int a) { return a; }
+
+  // These methods produce long-to-int Dex instructions.
+  static int $opt$LongToInt(long a){ return (int)a; }
+  static int $opt$LongLiteralToInt(){ return (int)42L; }
 }