diff options
author | Roland Levillain <rpl@google.com> | 2014-11-11 12:26:26 +0000 |
---|---|---|
committer | Roland Levillain <rpl@google.com> | 2014-11-11 12:26:26 +0000 |
commit | 647b96f29cb81832e698f863884fdba06674c9de (patch) | |
tree | 1a4b5d9c2dc0cec47387838eb33b55b01838b615 | |
parent | 666c732cfa211abf44ed90120a87bf8c18138e55 (diff) | |
download | art-647b96f29cb81832e698f863884fdba06674c9de.zip art-647b96f29cb81832e698f863884fdba06674c9de.tar.gz art-647b96f29cb81832e698f863884fdba06674c9de.tar.bz2 |
Add support for long-to-int in the optimizing compiler.
- Add support for the long-to-int Dex instruction in the
optimizing compiler.
- Generate x86, x86-64 and ARM (but not ARM64) code for
long-to-int HTypeConversion nodes.
- Add related tests to test/422-type-conversion.
- Also fix comments in test/415-optimizing-arith-neg and
in test/416-optimizing-arith-not.
Change-Id: I3084af30f2a495d178362ae1154dc7ceb7bf3a58
-rw-r--r-- | compiler/optimizing/builder.cc | 5 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 54 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 51 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 52 | ||||
-rw-r--r-- | compiler/optimizing/codegen_test.cc | 17 | ||||
-rw-r--r-- | test/415-optimizing-arith-neg/src/Main.java | 16 | ||||
-rw-r--r-- | test/416-optimizing-arith-not/src/Main.java | 24 | ||||
-rw-r--r-- | test/422-type-conversion/src/Main.java | 119 |
8 files changed, 271 insertions, 67 deletions
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 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 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..7f3ebf4 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -22,9 +22,10 @@ #include "mirror/art_method.h" #include "mirror/class.h" #include "thread.h" -#include "utils/assembler.h" +#include "utils.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 +1334,26 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { 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 +1377,6 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { } break; - case Primitive::kPrimInt: case Primitive::kPrimFloat: case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type @@ -1376,6 +1396,35 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio 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()); + __ LoadImmediate(out.As<Register>(), + Low32Bits(in.GetConstant()->AsLongConstant()->GetValue())); + } + 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 +1453,6 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio } 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..4706274 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -22,6 +22,7 @@ #include "mirror/art_method.h" #include "mirror/class.h" #include "thread.h" +#include "utils.h" #include "utils/assembler.h" #include "utils/stack_checks.h" #include "utils/x86/assembler_x86.h" @@ -1261,6 +1262,26 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { 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 +1305,6 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { } break; - case Primitive::kPrimInt: case Primitive::kPrimFloat: case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type @@ -1304,6 +1324,34 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio 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()); + __ movl(out.As<Register>(), + Immediate(Low32Bits(in.GetConstant()->AsLongConstant()->GetValue()))); + } + 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 +1377,6 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio } 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..304a008 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -23,6 +23,7 @@ #include "mirror/class.h" #include "mirror/object_reference.h" #include "thread.h" +#include "utils.h" #include "utils/assembler.h" #include "utils/stack_checks.h" #include "utils/x86_64/assembler_x86_64.h" @@ -1259,6 +1260,26 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) { 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 +1305,6 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) { } break; - case Primitive::kPrimInt: case Primitive::kPrimFloat: case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type @@ -1304,6 +1324,35 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver 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()); + __ movl(out.As<CpuRegister>(), + Immediate(Low32Bits(in.GetConstant()->AsLongConstant()->GetValue()))); + } + 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 +1377,6 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver } 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..de2253b 100644 --- a/compiler/optimizing/codegen_test.cc +++ b/compiler/optimizing/codegen_test.cc @@ -362,6 +362,23 @@ NOT_LONG_TEST(ReturnNotLongINT64_MAX, #undef NOT_LONG_TEST +TEST(CodegenTest, IntToLongOfLongToInt) { + 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/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 @@ public class Main { 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 @@ public class Main { 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 @@ public class Main { 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 @@ public class Main { 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 class Main { 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 - - assertEquals(0L, $opt$CharToLong('\u0000')); - assertEquals(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(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 + + assertLongEquals(0L, $opt$CharToLong('\u0000')); + assertLongEquals(65535L, $opt$CharToLong('\uFFFF')); // 2^16 - 1 + + 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; } } |