diff options
-rw-r--r-- | compiler/optimizing/builder.cc | 5 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 45 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 53 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 54 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm.h | 3 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm32.cc | 19 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm32.h | 2 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm32_test.cc | 36 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_thumb2.cc | 21 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_thumb2.h | 2 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_thumb2_test.cc | 36 | ||||
-rw-r--r-- | test/422-type-conversion/src/Main.java | 57 |
12 files changed, 315 insertions, 18 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index df3d57ebdf..b51b6e7d25 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -1007,6 +1007,11 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::INT_TO_CHAR: { + Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimChar); + 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 7444506771..09e1b97570 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -1356,7 +1356,7 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { case Primitive::kPrimShort: case Primitive::kPrimInt: case Primitive::kPrimChar: - // int-to-byte conversion. + // Processing a Dex `int-to-byte' instruction. locations->SetInAt(0, Location::RequiresRegister()); locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); break; @@ -1370,7 +1370,7 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { case Primitive::kPrimInt: switch (input_type) { case Primitive::kPrimLong: - // long-to-int conversion. + // Processing a Dex `long-to-int' instruction. locations->SetInAt(0, Location::Any()); locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); break; @@ -1393,7 +1393,7 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { case Primitive::kPrimShort: case Primitive::kPrimInt: case Primitive::kPrimChar: - // int-to-long conversion. + // Processing a Dex `int-to-long' instruction. locations->SetInAt(0, Location::RequiresRegister()); locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); break; @@ -1410,6 +1410,23 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { } break; + case Primitive::kPrimChar: + switch (input_type) { + case Primitive::kPrimByte: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimChar: + // Processing a Dex `int-to-char' instruction. + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + break; + + default: + LOG(FATAL) << "Unexpected type conversion from " << input_type + << " to " << result_type; + } + break; + case Primitive::kPrimFloat: case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type @@ -1434,7 +1451,7 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio case Primitive::kPrimShort: case Primitive::kPrimInt: case Primitive::kPrimChar: - // int-to-byte conversion. + // Processing a Dex `int-to-byte' instruction. __ sbfx(out.As<Register>(), in.As<Register>(), 0, 8); break; @@ -1447,7 +1464,7 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio case Primitive::kPrimInt: switch (input_type) { case Primitive::kPrimLong: - // long-to-int conversion. + // Processing a Dex `long-to-int' instruction. DCHECK(out.IsRegister()); if (in.IsRegisterPair()) { __ Mov(out.As<Register>(), in.AsRegisterPairLow<Register>()); @@ -1479,7 +1496,7 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio case Primitive::kPrimShort: case Primitive::kPrimInt: case Primitive::kPrimChar: - // int-to-long conversion. + // Processing a Dex `int-to-long' instruction. DCHECK(out.IsRegisterPair()); DCHECK(in.IsRegister()); __ Mov(out.AsRegisterPairLow<Register>(), in.As<Register>()); @@ -1501,6 +1518,22 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio } break; + case Primitive::kPrimChar: + switch (input_type) { + case Primitive::kPrimByte: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimChar: + // Processing a Dex `int-to-char' instruction. + __ ubfx(out.As<Register>(), in.As<Register>(), 0, 16); + break; + + default: + LOG(FATAL) << "Unexpected type conversion from " << input_type + << " to " << result_type; + } + break; + 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 6e1abbf076..8a8fec2609 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -1295,7 +1295,7 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { case Primitive::kPrimShort: case Primitive::kPrimInt: case Primitive::kPrimChar: - // int-to-byte conversion. + // Processing a Dex `int-to-byte' instruction. locations->SetInAt(0, Location::Any()); locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); break; @@ -1309,7 +1309,7 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { case Primitive::kPrimInt: switch (input_type) { case Primitive::kPrimLong: - // long-to-int conversion. + // Processing a Dex `long-to-int' instruction. locations->SetInAt(0, Location::Any()); locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); break; @@ -1332,7 +1332,7 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { case Primitive::kPrimShort: case Primitive::kPrimInt: case Primitive::kPrimChar: - // int-to-long conversion. + // Processing a Dex `int-to-long' instruction. locations->SetInAt(0, Location::RegisterLocation(EAX)); locations->SetOut(Location::RegisterPairLocation(EAX, EDX)); break; @@ -1349,6 +1349,23 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { } break; + case Primitive::kPrimChar: + switch (input_type) { + case Primitive::kPrimByte: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimChar: + // Processing a Dex `int-to-char' instruction. + locations->SetInAt(0, Location::Any()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + break; + + default: + LOG(FATAL) << "Unexpected type conversion from " << input_type + << " to " << result_type; + } + break; + case Primitive::kPrimFloat: case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type @@ -1373,7 +1390,7 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio case Primitive::kPrimShort: case Primitive::kPrimInt: case Primitive::kPrimChar: - // int-to-byte conversion. + // Processing a Dex `int-to-byte' instruction. if (in.IsRegister()) { __ movsxb(out.As<Register>(), in.As<ByteRegister>()); } else if (in.IsStackSlot()) { @@ -1394,7 +1411,7 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio case Primitive::kPrimInt: switch (input_type) { case Primitive::kPrimLong: - // long-to-int conversion. + // Processing a Dex `long-to-int' instruction. if (in.IsRegisterPair()) { __ movl(out.As<Register>(), in.AsRegisterPairLow<Register>()); } else if (in.IsDoubleStackSlot()) { @@ -1425,7 +1442,7 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio case Primitive::kPrimShort: case Primitive::kPrimInt: case Primitive::kPrimChar: - // int-to-long conversion. + // Processing a Dex `int-to-long' instruction. DCHECK_EQ(out.AsRegisterPairLow<Register>(), EAX); DCHECK_EQ(out.AsRegisterPairHigh<Register>(), EDX); DCHECK_EQ(in.As<Register>(), EAX); @@ -1444,6 +1461,30 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio } break; + case Primitive::kPrimChar: + switch (input_type) { + case Primitive::kPrimByte: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimChar: + // Processing a Dex `Process a Dex `int-to-char'' instruction. + if (in.IsRegister()) { + __ movzxw(out.As<Register>(), in.As<Register>()); + } else if (in.IsStackSlot()) { + __ movzxw(out.As<Register>(), Address(ESP, in.GetStackIndex())); + } else { + DCHECK(in.GetConstant()->IsIntConstant()); + int32_t value = in.GetConstant()->AsIntConstant()->GetValue(); + __ movl(out.As<Register>(), Immediate(static_cast<uint16_t>(value))); + } + break; + + default: + LOG(FATAL) << "Unexpected type conversion from " << input_type + << " to " << result_type; + } + break; + 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 2393fb5119..5aa1c4a6c8 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -1293,7 +1293,7 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) { case Primitive::kPrimShort: case Primitive::kPrimInt: case Primitive::kPrimChar: - // int-to-byte conversion. + // Processing a Dex `int-to-byte' instruction. locations->SetInAt(0, Location::Any()); locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); break; @@ -1307,7 +1307,7 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) { case Primitive::kPrimInt: switch (input_type) { case Primitive::kPrimLong: - // long-to-int conversion. + // Processing a Dex `long-to-int' instruction. locations->SetInAt(0, Location::Any()); locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); break; @@ -1330,7 +1330,7 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) { case Primitive::kPrimShort: case Primitive::kPrimInt: case Primitive::kPrimChar: - // int-to-long conversion. + // Processing a Dex `int-to-long' instruction. // TODO: We would benefit from a (to-be-implemented) // Location::RegisterOrStackSlot requirement for this input. locations->SetInAt(0, Location::RequiresRegister()); @@ -1349,6 +1349,23 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) { } break; + case Primitive::kPrimChar: + switch (input_type) { + case Primitive::kPrimByte: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimChar: + // Processing a Dex `int-to-char' instruction. + locations->SetInAt(0, Location::Any()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + break; + + default: + LOG(FATAL) << "Unexpected type conversion from " << input_type + << " to " << result_type; + } + break; + case Primitive::kPrimFloat: case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type @@ -1373,7 +1390,7 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver case Primitive::kPrimShort: case Primitive::kPrimInt: case Primitive::kPrimChar: - // int-to-byte conversion. + // Processing a Dex `int-to-byte' instruction. if (in.IsRegister()) { __ movsxb(out.As<CpuRegister>(), in.As<CpuRegister>()); } else if (in.IsStackSlot()) { @@ -1395,7 +1412,7 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver case Primitive::kPrimInt: switch (input_type) { case Primitive::kPrimLong: - // long-to-int conversion. + // Processing a Dex `long-to-int' instruction. if (in.IsRegister()) { __ movl(out.As<CpuRegister>(), in.As<CpuRegister>()); } else if (in.IsDoubleStackSlot()) { @@ -1428,7 +1445,7 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver case Primitive::kPrimShort: case Primitive::kPrimInt: case Primitive::kPrimChar: - // int-to-long conversion. + // Processing a Dex `int-to-long' instruction. DCHECK(in.IsRegister()); __ movsxd(out.As<CpuRegister>(), in.As<CpuRegister>()); break; @@ -1445,6 +1462,31 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver } break; + case Primitive::kPrimChar: + switch (input_type) { + case Primitive::kPrimByte: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimChar: + // Processing a Dex `int-to-char' instruction. + if (in.IsRegister()) { + __ movzxw(out.As<CpuRegister>(), in.As<CpuRegister>()); + } else if (in.IsStackSlot()) { + __ movzxw(out.As<CpuRegister>(), + Address(CpuRegister(RSP), in.GetStackIndex())); + } else { + DCHECK(in.GetConstant()->IsIntConstant()); + __ movl(out.As<CpuRegister>(), + Immediate(static_cast<uint16_t>(in.GetConstant()->AsIntConstant()->GetValue()))); + } + break; + + default: + LOG(FATAL) << "Unexpected type conversion from " << input_type + << " to " << result_type; + } + break; + case Primitive::kPrimFloat: case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h index 911000aee8..d288b700ed 100644 --- a/compiler/utils/arm/assembler_arm.h +++ b/compiler/utils/arm/assembler_arm.h @@ -421,8 +421,11 @@ class ArmAssembler : public Assembler { virtual void sdiv(Register rd, Register rn, Register rm, Condition cond = AL) = 0; virtual void udiv(Register rd, Register rn, Register rm, Condition cond = AL) = 0; + // Bit field extract instructions. virtual void sbfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond = AL) = 0; + virtual void ubfx(Register rd, Register rn, uint32_t lsb, uint32_t width, + Condition cond = AL) = 0; // Load/store instructions. virtual void ldr(Register rd, const Address& ad, Condition cond = AL) = 0; diff --git a/compiler/utils/arm/assembler_arm32.cc b/compiler/utils/arm/assembler_arm32.cc index 29cbf5851f..39ebf6803c 100644 --- a/compiler/utils/arm/assembler_arm32.cc +++ b/compiler/utils/arm/assembler_arm32.cc @@ -227,6 +227,25 @@ void Arm32Assembler::sbfx(Register rd, Register rn, uint32_t lsb, uint32_t width } +void Arm32Assembler::ubfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond) { + CHECK_NE(rd, kNoRegister); + CHECK_NE(rn, kNoRegister); + CHECK_NE(cond, kNoCondition); + CHECK_LE(lsb, 31U); + CHECK(1U <= width && width <= 32U) << width; + uint32_t widthminus1 = width - 1; + + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B26 | B25 | B24 | B23 | B22 | B21 | + (widthminus1 << 16) | + (static_cast<uint32_t>(rd) << 12) | + (lsb << 7) | + B6 | B4 | + static_cast<uint32_t>(rn); + Emit(encoding); +} + + void Arm32Assembler::ldr(Register rd, const Address& ad, Condition cond) { EmitMemOp(cond, true, false, rd, ad); } diff --git a/compiler/utils/arm/assembler_arm32.h b/compiler/utils/arm/assembler_arm32.h index b582e9e5ab..0b009e16d9 100644 --- a/compiler/utils/arm/assembler_arm32.h +++ b/compiler/utils/arm/assembler_arm32.h @@ -96,7 +96,9 @@ class Arm32Assembler FINAL : public ArmAssembler { void sdiv(Register rd, Register rn, Register rm, Condition cond = AL) OVERRIDE; void udiv(Register rd, Register rn, Register rm, Condition cond = AL) OVERRIDE; + // Bit field extract instructions. void sbfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond = AL) OVERRIDE; + void ubfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond = AL) OVERRIDE; // Load/store instructions. void ldr(Register rd, const Address& ad, Condition cond = AL) OVERRIDE; diff --git a/compiler/utils/arm/assembler_arm32_test.cc b/compiler/utils/arm/assembler_arm32_test.cc index 4f5d4c36a1..277a9eb0fa 100644 --- a/compiler/utils/arm/assembler_arm32_test.cc +++ b/compiler/utils/arm/assembler_arm32_test.cc @@ -116,4 +116,40 @@ TEST_F(AssemblerArm32Test, Sbfx) { DriverStr(expected, "sbfx"); } +TEST_F(AssemblerArm32Test, Ubfx) { + GetAssembler()->ubfx(arm::R0, arm::R1, 0, 1); + GetAssembler()->ubfx(arm::R0, arm::R1, 0, 8); + GetAssembler()->ubfx(arm::R0, arm::R1, 0, 16); + GetAssembler()->ubfx(arm::R0, arm::R1, 0, 32); + + GetAssembler()->ubfx(arm::R0, arm::R1, 8, 1); + GetAssembler()->ubfx(arm::R0, arm::R1, 8, 8); + GetAssembler()->ubfx(arm::R0, arm::R1, 8, 16); + GetAssembler()->ubfx(arm::R0, arm::R1, 8, 24); + + GetAssembler()->ubfx(arm::R0, arm::R1, 16, 1); + GetAssembler()->ubfx(arm::R0, arm::R1, 16, 8); + GetAssembler()->ubfx(arm::R0, arm::R1, 16, 16); + + GetAssembler()->ubfx(arm::R0, arm::R1, 31, 1); + + const char* expected = + "ubfx r0, r1, #0, #1\n" + "ubfx r0, r1, #0, #8\n" + "ubfx r0, r1, #0, #16\n" + "ubfx r0, r1, #0, #32\n" + + "ubfx r0, r1, #8, #1\n" + "ubfx r0, r1, #8, #8\n" + "ubfx r0, r1, #8, #16\n" + "ubfx r0, r1, #8, #24\n" + + "ubfx r0, r1, #16, #1\n" + "ubfx r0, r1, #16, #8\n" + "ubfx r0, r1, #16, #16\n" + + "ubfx r0, r1, #31, #1\n"; + DriverStr(expected, "ubfx"); +} + } // namespace art diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc index a309e187df..3ab9b2ba03 100644 --- a/compiler/utils/arm/assembler_thumb2.cc +++ b/compiler/utils/arm/assembler_thumb2.cc @@ -285,6 +285,27 @@ void Thumb2Assembler::sbfx(Register rd, Register rn, uint32_t lsb, uint32_t widt } +void Thumb2Assembler::ubfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond) { + CheckCondition(cond); + CHECK_LE(lsb, 31U); + CHECK(1U <= width && width <= 32U) << width; + uint32_t widthminus1 = width - 1; + uint32_t imm2 = lsb & (B1 | B0); // Bits 0-1 of `lsb`. + uint32_t imm3 = (lsb & (B4 | B3 | B2)) >> 2; // Bits 2-4 of `lsb`. + + uint32_t op = 28U /* 0b11100 */; + int32_t encoding = B31 | B30 | B29 | B28 | B25 | + op << 20 | + static_cast<uint32_t>(rn) << 16 | + imm3 << 12 | + static_cast<uint32_t>(rd) << 8 | + imm2 << 6 | + widthminus1; + + Emit32(encoding); +} + + void Thumb2Assembler::ldr(Register rd, const Address& ad, Condition cond) { EmitLoadStore(cond, true, false, false, false, rd, ad); } diff --git a/compiler/utils/arm/assembler_thumb2.h b/compiler/utils/arm/assembler_thumb2.h index 1fc842cf56..cfa251acf2 100644 --- a/compiler/utils/arm/assembler_thumb2.h +++ b/compiler/utils/arm/assembler_thumb2.h @@ -118,7 +118,9 @@ class Thumb2Assembler FINAL : public ArmAssembler { void sdiv(Register rd, Register rn, Register rm, Condition cond = AL) OVERRIDE; void udiv(Register rd, Register rn, Register rm, Condition cond = AL) OVERRIDE; + // Bit field extract instructions. void sbfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond = AL) OVERRIDE; + void ubfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond = AL) OVERRIDE; // Load/store instructions. void ldr(Register rd, const Address& ad, Condition cond = AL) OVERRIDE; diff --git a/compiler/utils/arm/assembler_thumb2_test.cc b/compiler/utils/arm/assembler_thumb2_test.cc index 57ba0ca5ee..65d6d45296 100644 --- a/compiler/utils/arm/assembler_thumb2_test.cc +++ b/compiler/utils/arm/assembler_thumb2_test.cc @@ -120,4 +120,40 @@ TEST_F(AssemblerThumb2Test, Sbfx) { DriverStr(expected, "sbfx"); } +TEST_F(AssemblerThumb2Test, Ubfx) { + GetAssembler()->ubfx(arm::R0, arm::R1, 0, 1); + GetAssembler()->ubfx(arm::R0, arm::R1, 0, 8); + GetAssembler()->ubfx(arm::R0, arm::R1, 0, 16); + GetAssembler()->ubfx(arm::R0, arm::R1, 0, 32); + + GetAssembler()->ubfx(arm::R0, arm::R1, 8, 1); + GetAssembler()->ubfx(arm::R0, arm::R1, 8, 8); + GetAssembler()->ubfx(arm::R0, arm::R1, 8, 16); + GetAssembler()->ubfx(arm::R0, arm::R1, 8, 24); + + GetAssembler()->ubfx(arm::R0, arm::R1, 16, 1); + GetAssembler()->ubfx(arm::R0, arm::R1, 16, 8); + GetAssembler()->ubfx(arm::R0, arm::R1, 16, 16); + + GetAssembler()->ubfx(arm::R0, arm::R1, 31, 1); + + const char* expected = + "ubfx r0, r1, #0, #1\n" + "ubfx r0, r1, #0, #8\n" + "ubfx r0, r1, #0, #16\n" + "ubfx r0, r1, #0, #32\n" + + "ubfx r0, r1, #8, #1\n" + "ubfx r0, r1, #8, #8\n" + "ubfx r0, r1, #8, #16\n" + "ubfx r0, r1, #8, #24\n" + + "ubfx r0, r1, #16, #1\n" + "ubfx r0, r1, #16, #8\n" + "ubfx r0, r1, #16, #16\n" + + "ubfx r0, r1, #31, #1\n"; + DriverStr(expected, "ubfx"); +} + } // namespace art diff --git a/test/422-type-conversion/src/Main.java b/test/422-type-conversion/src/Main.java index 7c5ddbab13..88b45280ac 100644 --- a/test/422-type-conversion/src/Main.java +++ b/test/422-type-conversion/src/Main.java @@ -36,6 +36,14 @@ public class Main { } } + public static void assertCharEquals(char expected, char result) { + if (expected != result) { + // Values are cast to int to display numeric values instead of + // (Unicode) characters. + throw new Error("Expected: " + (int)expected + ", found: " + (int)result); + } + } + public static void main(String[] args) { byteToLong(); shortToLong(); @@ -47,6 +55,10 @@ public class Main { shortToByte(); intToByte(); charToByte(); + + byteToChar(); + shortToChar(); + intToChar(); } private static void byteToLong() { @@ -174,6 +186,46 @@ public class Main { assertByteEquals((byte)127, $opt$CharToByte((char)-129)); // -(2^7 + 1) } + private static void byteToChar() { + assertCharEquals((char)1, $opt$ByteToChar((byte)1)); + assertCharEquals((char)0, $opt$ByteToChar((byte)0)); + assertCharEquals((char)65535, $opt$ByteToChar((byte)-1)); + assertCharEquals((char)51, $opt$ByteToChar((byte)51)); + assertCharEquals((char)65485, $opt$ByteToChar((byte)-51)); + assertCharEquals((char)127, $opt$ByteToChar((byte)127)); // 2^7 - 1 + assertCharEquals((char)65409, $opt$ByteToChar((byte)-127)); // -(2^7 - 1) + assertCharEquals((char)65408, $opt$ByteToChar((byte)-128)); // -(2^7) + } + + private static void shortToChar() { + assertCharEquals((char)1, $opt$ShortToChar((short)1)); + assertCharEquals((char)0, $opt$ShortToChar((short)0)); + assertCharEquals((char)65535, $opt$ShortToChar((short)-1)); + assertCharEquals((char)51, $opt$ShortToChar((short)51)); + assertCharEquals((char)65485, $opt$ShortToChar((short)-51)); + assertCharEquals((char)32767, $opt$ShortToChar((short)32767)); // 2^15 - 1 + assertCharEquals((char)32769, $opt$ShortToChar((short)-32767)); // -(2^15 - 1) + assertCharEquals((char)32768, $opt$ShortToChar((short)-32768)); // -(2^15) + } + + private static void intToChar() { + assertCharEquals((char)1, $opt$IntToChar(1)); + assertCharEquals((char)0, $opt$IntToChar(0)); + assertCharEquals((char)65535, $opt$IntToChar(-1)); + assertCharEquals((char)51, $opt$IntToChar(51)); + assertCharEquals((char)65485, $opt$IntToChar(-51)); + assertCharEquals((char)32767, $opt$IntToChar(32767)); // 2^15 - 1 + assertCharEquals((char)32769, $opt$IntToChar(-32767)); // -(2^15 - 1) + assertCharEquals((char)32768, $opt$IntToChar(32768)); // 2^15 + assertCharEquals((char)32768, $opt$IntToChar(-32768)); // -(2^15) + assertCharEquals((char)65535, $opt$IntToChar(65535)); // 2^16 - 1 + assertCharEquals((char)1, $opt$IntToChar(-65535)); // -(2^16 - 1) + assertCharEquals((char)0, $opt$IntToChar(65536)); // 2^16 + assertCharEquals((char)0, $opt$IntToChar(-65536)); // -(2^16) + assertCharEquals((char)65535, $opt$IntToChar(2147483647)); // 2^31 - 1 + assertCharEquals((char)0, $opt$IntToChar(-2147483648)); // -(2^31) + } + // These methods produce int-to-long Dex instructions. static long $opt$ByteToLong(byte a) { return a; } @@ -189,4 +241,9 @@ public class Main { static byte $opt$ShortToByte(short a){ return (byte)a; } static byte $opt$IntToByte(int a){ return (byte)a; } static byte $opt$CharToByte(char a){ return (byte)a; } + + // These methods produce int-to-char Dex instructions. + static char $opt$ByteToChar(byte a){ return (char)a; } + static char $opt$ShortToChar(short a){ return (char)a; } + static char $opt$IntToChar(int a){ return (char)a; } } |