diff options
| -rw-r--r-- | build/Android.common_build.mk | 21 | ||||
| -rw-r--r-- | compiler/dex/quick/arm/arm_lir.h | 1 | ||||
| -rw-r--r-- | compiler/dex/quick/arm/assemble_arm.cc | 4 | ||||
| -rw-r--r-- | compiler/dex/quick/arm/codegen_arm.h | 9 | ||||
| -rw-r--r-- | compiler/dex/quick/arm/int_arm.cc | 1 | ||||
| -rw-r--r-- | compiler/dex/quick/arm/utility_arm.cc | 90 | ||||
| -rw-r--r-- | compiler/optimizing/builder.cc | 5 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator.h | 3 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 16 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 32 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 32 | ||||
| -rw-r--r-- | test/422-type-conversion/src/Main.java | 32 |
12 files changed, 207 insertions, 39 deletions
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk index 5dd9f1534c..63469703f2 100644 --- a/build/Android.common_build.mk +++ b/build/Android.common_build.mk @@ -259,16 +259,21 @@ ifeq ($(HOST_OS),linux) art_target_non_debug_cflags += -Wframe-larger-than=1728 endif -ifndef LIBART_IMG_HOST_BASE_ADDRESS - $(error LIBART_IMG_HOST_BASE_ADDRESS unset) -endif -ART_HOST_CFLAGS += $(art_cflags) -DART_BASE_ADDRESS=$(LIBART_IMG_HOST_BASE_ADDRESS) -ART_HOST_CFLAGS += -DART_DEFAULT_INSTRUCTION_SET_FEATURES=default +# DALVIK_VM_LIB will be empty for VM-less builds. Avoid $(error) calls here because +# LIBART_IMG_XXX variables won't be defined. +ifneq ($(DALVIK_VM_LIB),) + ifndef LIBART_IMG_HOST_BASE_ADDRESS + $(error LIBART_IMG_HOST_BASE_ADDRESS unset) + endif + ART_HOST_CFLAGS += $(art_cflags) -DART_BASE_ADDRESS=$(LIBART_IMG_HOST_BASE_ADDRESS) + ART_HOST_CFLAGS += -DART_DEFAULT_INSTRUCTION_SET_FEATURES=default -ifndef LIBART_IMG_TARGET_BASE_ADDRESS - $(error LIBART_IMG_TARGET_BASE_ADDRESS unset) + ifndef LIBART_IMG_TARGET_BASE_ADDRESS + $(error LIBART_IMG_TARGET_BASE_ADDRESS unset) + endif + ART_TARGET_CFLAGS += $(art_cflags) \ + -DART_TARGET -DART_BASE_ADDRESS=$(LIBART_IMG_TARGET_BASE_ADDRESS) endif -ART_TARGET_CFLAGS += $(art_cflags) -DART_TARGET -DART_BASE_ADDRESS=$(LIBART_IMG_TARGET_BASE_ADDRESS) ART_HOST_NON_DEBUG_CFLAGS := $(art_host_non_debug_cflags) ART_TARGET_NON_DEBUG_CFLAGS := $(art_target_non_debug_cflags) diff --git a/compiler/dex/quick/arm/arm_lir.h b/compiler/dex/quick/arm/arm_lir.h index 4c7f87433d..b9d9a1111d 100644 --- a/compiler/dex/quick/arm/arm_lir.h +++ b/compiler/dex/quick/arm/arm_lir.h @@ -488,6 +488,7 @@ enum ArmOpcode { kThumb2BicRRI8M, // bic rd, rn, #<const> [11110] i [000010] rn[19..16] [0] imm3[14..12] rd[11..8] imm8[7..0]. kThumb2AndRRI8M, // and rd, rn, #<const> [11110] i [000000] rn[19..16] [0] imm3[14..12] rd[11..8] imm8[7..0]. kThumb2OrrRRI8M, // orr rd, rn, #<const> [11110] i [000100] rn[19..16] [0] imm3[14..12] rd[11..8] imm8[7..0]. + kThumb2OrnRRI8M, // orn rd, rn, #<const> [11110] i [000110] rn[19..16] [0] imm3[14..12] rd[11..8] imm8[7..0]. kThumb2EorRRI8M, // eor rd, rn, #<const> [11110] i [001000] rn[19..16] [0] imm3[14..12] rd[11..8] imm8[7..0]. kThumb2AddRRI8M, // add rd, rn, #<const> [11110] i [010001] rn[19..16] [0] imm3[14..12] rd[11..8] imm8[7..0]. kThumb2AdcRRI8M, // adc rd, rn, #<const> [11110] i [010101] rn[19..16] [0] imm3[14..12] rd[11..8] imm8[7..0]. diff --git a/compiler/dex/quick/arm/assemble_arm.cc b/compiler/dex/quick/arm/assemble_arm.cc index 76ec9dfbc5..de93e2602b 100644 --- a/compiler/dex/quick/arm/assemble_arm.cc +++ b/compiler/dex/quick/arm/assemble_arm.cc @@ -788,6 +788,10 @@ const ArmEncodingMap ArmMir2Lir::EncodingMap[kArmLast] = { kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1, "orr", "!0C, !1C, #!2m", 4, kFixupNone), + ENCODING_MAP(kThumb2OrnRRI8M, 0xf0600000, + kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, + kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1, + "orn", "!0C, !1C, #!2m", 4, kFixupNone), ENCODING_MAP(kThumb2EorRRI8M, 0xf0800000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1, diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h index e8d0c32ffd..0bc4c3b7bf 100644 --- a/compiler/dex/quick/arm/codegen_arm.h +++ b/compiler/dex/quick/arm/codegen_arm.h @@ -250,10 +250,11 @@ class ArmMir2Lir FINAL : public Mir2Lir { int EncodeShift(int code, int amount); int ModifiedImmediate(uint32_t value); ArmConditionCode ArmConditionEncoding(ConditionCode code); - bool InexpensiveConstantInt(int32_t value); - bool InexpensiveConstantFloat(int32_t value); - bool InexpensiveConstantLong(int64_t value); - bool InexpensiveConstantDouble(int64_t value); + bool InexpensiveConstantInt(int32_t value) OVERRIDE; + bool InexpensiveConstantInt(int32_t value, Instruction::Code opcode) OVERRIDE; + bool InexpensiveConstantFloat(int32_t value) OVERRIDE; + bool InexpensiveConstantLong(int64_t value) OVERRIDE; + bool InexpensiveConstantDouble(int64_t value) OVERRIDE; RegStorage AllocPreservedDouble(int s_reg); RegStorage AllocPreservedSingle(int s_reg); diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc index 4aedbafcfb..1a7b4395d8 100644 --- a/compiler/dex/quick/arm/int_arm.cc +++ b/compiler/dex/quick/arm/int_arm.cc @@ -592,7 +592,6 @@ bool ArmMir2Lir::GetEasyMultiplyOp(int lit, ArmMir2Lir::EasyMultiplyOp* op) { // Try to convert *lit to 1~2 RegRegRegShift/RegRegShift forms. bool ArmMir2Lir::GetEasyMultiplyTwoOps(int lit, EasyMultiplyOp* ops) { - GetEasyMultiplyOp(lit, &ops[0]); if (GetEasyMultiplyOp(lit, &ops[0])) { ops[1].op = kOpInvalid; ops[1].shift = 0; diff --git a/compiler/dex/quick/arm/utility_arm.cc b/compiler/dex/quick/arm/utility_arm.cc index 7168b9f30b..117d8f016d 100644 --- a/compiler/dex/quick/arm/utility_arm.cc +++ b/compiler/dex/quick/arm/utility_arm.cc @@ -97,31 +97,11 @@ LIR* ArmMir2Lir::LoadFPConstantValue(int r_dest, int value) { return load_pc_rel; } -static int LeadingZeros(uint32_t val) { - uint32_t alt; - int32_t n; - int32_t count; - - count = 16; - n = 32; - do { - alt = val >> count; - if (alt != 0) { - n = n - count; - val = alt; - } - count >>= 1; - } while (count); - return n - val; -} - /* * Determine whether value can be encoded as a Thumb2 modified * immediate. If not, return -1. If so, return i:imm3:a:bcdefgh form. */ int ArmMir2Lir::ModifiedImmediate(uint32_t value) { - int32_t z_leading; - int32_t z_trailing; uint32_t b0 = value & 0xff; /* Note: case of value==0 must use 0:000:0:0000000 encoding */ @@ -135,8 +115,8 @@ int ArmMir2Lir::ModifiedImmediate(uint32_t value) { if (value == ((b0 << 24) | (b0 << 8))) return (0x2 << 8) | b0; /* 0:010:a:bcdefgh */ /* Can we do it with rotation? */ - z_leading = LeadingZeros(value); - z_trailing = 32 - LeadingZeros(~value & (value - 1)); + int z_leading = CLZ(value); + int z_trailing = CTZ(value); /* A run of eight or fewer active bits? */ if ((z_leading + z_trailing) < 24) return -1; /* No - bail */ @@ -152,6 +132,64 @@ bool ArmMir2Lir::InexpensiveConstantInt(int32_t value) { return (ModifiedImmediate(value) >= 0) || (ModifiedImmediate(~value) >= 0); } +bool ArmMir2Lir::InexpensiveConstantInt(int32_t value, Instruction::Code opcode) { + switch (opcode) { + case Instruction::ADD_INT: + case Instruction::ADD_INT_2ADDR: + case Instruction::SUB_INT: + case Instruction::SUB_INT_2ADDR: + if ((value >> 12) == (value >> 31)) { // Signed 12-bit, RRI12 versions of ADD/SUB. + return true; + } + FALLTHROUGH_INTENDED; + case Instruction::IF_EQ: + case Instruction::IF_NE: + case Instruction::IF_LT: + case Instruction::IF_GE: + case Instruction::IF_GT: + case Instruction::IF_LE: + return (ModifiedImmediate(value) >= 0) || (ModifiedImmediate(-value) >= 0); + case Instruction::SHL_INT: + case Instruction::SHL_INT_2ADDR: + case Instruction::SHR_INT: + case Instruction::SHR_INT_2ADDR: + case Instruction::USHR_INT: + case Instruction::USHR_INT_2ADDR: + return true; + case Instruction::AND_INT: + case Instruction::AND_INT_2ADDR: + case Instruction::AND_INT_LIT16: + case Instruction::AND_INT_LIT8: + case Instruction::OR_INT: + case Instruction::OR_INT_2ADDR: + case Instruction::OR_INT_LIT16: + case Instruction::OR_INT_LIT8: + return (ModifiedImmediate(value) >= 0) || (ModifiedImmediate(~value) >= 0); + case Instruction::XOR_INT: + case Instruction::XOR_INT_2ADDR: + case Instruction::XOR_INT_LIT16: + case Instruction::XOR_INT_LIT8: + return (ModifiedImmediate(value) >= 0); + case Instruction::MUL_INT: + case Instruction::MUL_INT_2ADDR: + case Instruction::MUL_INT_LIT8: + case Instruction::MUL_INT_LIT16: + case Instruction::DIV_INT: + case Instruction::DIV_INT_2ADDR: + case Instruction::DIV_INT_LIT8: + case Instruction::DIV_INT_LIT16: + case Instruction::REM_INT: + case Instruction::REM_INT_2ADDR: + case Instruction::REM_INT_LIT8: + case Instruction::REM_INT_LIT16: { + EasyMultiplyOp ops[2]; + return GetEasyMultiplyTwoOps(value, ops); + } + default: + return false; + } +} + bool ArmMir2Lir::InexpensiveConstantFloat(int32_t value) { return EncodeImmSingle(value) >= 0; } @@ -510,7 +548,7 @@ LIR* ArmMir2Lir::OpRegRegImm(OpKind op, RegStorage r_dest, RegStorage r_src1, in op = (op == kOpAdd) ? kOpSub : kOpAdd; } } - if (mod_imm < 0 && (abs_value & 0x3ff) == abs_value) { + if (mod_imm < 0 && (abs_value >> 12) == 0) { // This is deliberately used only if modified immediate encoding is inadequate since // we sometimes actually use the flags for small values but not necessarily low regs. if (op == kOpAdd) @@ -542,6 +580,12 @@ LIR* ArmMir2Lir::OpRegRegImm(OpKind op, RegStorage r_dest, RegStorage r_src1, in case kOpOr: opcode = kThumb2OrrRRI8M; alt_opcode = kThumb2OrrRRR; + if (mod_imm < 0) { + mod_imm = ModifiedImmediate(~value); + if (mod_imm >= 0) { + opcode = kThumb2OrnRRI8M; + } + } break; case kOpAnd: if (mod_imm < 0) { diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 23c3b390c0..eb6181c711 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -1108,6 +1108,11 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::FLOAT_TO_INT: { + Conversion_12x(instruction, Primitive::kPrimFloat, Primitive::kPrimInt); + break; + } + case Instruction::INT_TO_BYTE: { Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimByte); break; diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index 4c0d3ea960..7c8f6a2d29 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -35,6 +35,9 @@ static int64_t constexpr k2Pow32EncodingForDouble = INT64_C(0x41F0000000000000); // Binary encoding of 2^31 for type double. static int64_t constexpr k2Pow31EncodingForDouble = INT64_C(0x41E0000000000000); +// Maximum value for a primitive integer. +static int32_t constexpr kPrimIntMax = 0x7fffffff; + class Assembler; class CodeGenerator; class DexCompilationUnit; diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 5b2be2e9a1..448a5a0707 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -1406,6 +1406,12 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { break; case Primitive::kPrimFloat: + // Processing a Dex `float-to-int' instruction. + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetOut(Location::RequiresRegister()); + locations->AddTemp(Location::RequiresFpuRegister()); + break; + case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type << " to " << result_type << " not yet implemented"; @@ -1580,7 +1586,15 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio } break; - case Primitive::kPrimFloat: + case Primitive::kPrimFloat: { + // Processing a Dex `float-to-int' instruction. + SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>(); + __ vmovs(temp, in.AsFpuRegister<SRegister>()); + __ vcvtis(temp, temp); + __ vmovrs(out.AsRegister<Register>(), temp); + break; + } + case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type << " to " << result_type << " not yet implemented"; diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index fd794f95d1..6f83d9faf4 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -1373,6 +1373,12 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { break; case Primitive::kPrimFloat: + // Processing a Dex `float-to-int' instruction. + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetOut(Location::RequiresRegister()); + locations->AddTemp(Location::RequiresFpuRegister()); + break; + case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type << " to " << result_type << " not yet implemented"; @@ -1559,7 +1565,31 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio } break; - case Primitive::kPrimFloat: + case Primitive::kPrimFloat: { + // Processing a Dex `float-to-int' instruction. + XmmRegister input = in.AsFpuRegister<XmmRegister>(); + Register output = out.AsRegister<Register>(); + XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>(); + Label done, nan; + + __ movl(output, Immediate(kPrimIntMax)); + // temp = int-to-float(output) + __ cvtsi2ss(temp, output); + // if input >= temp goto done + __ comiss(input, temp); + __ j(kAboveEqual, &done); + // if input == NaN goto nan + __ j(kUnordered, &nan); + // output = float-to-int-truncate(input) + __ cvttss2si(output, input); + __ jmp(&done); + __ Bind(&nan); + // output = 0 + __ xorl(output, output); + __ Bind(&done); + break; + } + case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type << " to " << result_type << " not yet implemented"; diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 4d70efcf38..47fd304969 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -1363,6 +1363,12 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) { break; case Primitive::kPrimFloat: + // Processing a Dex `float-to-int' instruction. + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetOut(Location::RequiresRegister()); + locations->AddTemp(Location::RequiresFpuRegister()); + break; + case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type << " to " << result_type << " not yet implemented"; @@ -1550,7 +1556,31 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver } break; - case Primitive::kPrimFloat: + case Primitive::kPrimFloat: { + // Processing a Dex `float-to-int' instruction. + XmmRegister input = in.AsFpuRegister<XmmRegister>(); + CpuRegister output = out.AsRegister<CpuRegister>(); + XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>(); + Label done, nan; + + __ movl(output, Immediate(kPrimIntMax)); + // temp = int-to-float(output) + __ cvtsi2ss(temp, output); + // if input >= temp goto done + __ comiss(input, temp); + __ j(kAboveEqual, &done); + // if input == NaN goto nan + __ j(kUnordered, &nan); + // output = float-to-int-truncate(input) + __ cvttss2si(output, input); + __ jmp(&done); + __ Bind(&nan); + // output = 0 + __ xorl(output, output); + __ Bind(&done); + break; + } + case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type << " to " << result_type << " not yet implemented"; diff --git a/test/422-type-conversion/src/Main.java b/test/422-type-conversion/src/Main.java index c434db37c9..e7dbe2463f 100644 --- a/test/422-type-conversion/src/Main.java +++ b/test/422-type-conversion/src/Main.java @@ -91,6 +91,9 @@ public class Main { // Generate, compile and check long-to-double Dex instructions. longToDouble(); + // Generate, compile and check float-to-int Dex instructions. + floatToInt(); + // Generate, compile and check int-to-byte Dex instructions. shortToByte(); intToByte(); @@ -313,6 +316,32 @@ public class Main { assertDoubleEquals(-9223372036854775808D, $opt$LongToDouble(-9223372036854775808L)); // -(2^63) } + private static void floatToInt() { + assertIntEquals(1, $opt$FloatToInt(1F)); + assertIntEquals(0, $opt$FloatToInt(0F)); + assertIntEquals(0, $opt$FloatToInt(-0F)); + assertIntEquals(-1, $opt$FloatToInt(-1F)); + assertIntEquals(51, $opt$FloatToInt(51F)); + assertIntEquals(-51, $opt$FloatToInt(-51F)); + assertIntEquals(0, $opt$FloatToInt(0.5F)); + assertIntEquals(0, $opt$FloatToInt(0.4999999F)); + assertIntEquals(0, $opt$FloatToInt(-0.4999999F)); + assertIntEquals(0, $opt$FloatToInt(-0.5F)); + assertIntEquals(42, $opt$FloatToInt(42.199F)); + assertIntEquals(-42, $opt$FloatToInt(-42.199F)); + assertIntEquals(2147483647, $opt$FloatToInt(2147483647F)); // 2^31 - 1 + assertIntEquals(-2147483648, $opt$FloatToInt(-2147483647F)); // -(2^31 - 1) + assertIntEquals(-2147483648, $opt$FloatToInt(-2147483648F)); // -(2^31) + assertIntEquals(2147483647, $opt$FloatToInt(2147483648F)); // (2^31) + assertIntEquals(-2147483648, $opt$FloatToInt(-2147483649F)); // -(2^31 + 1) + assertIntEquals(2147483647, $opt$FloatToInt(9223372036854775807F)); // 2^63 - 1 + assertIntEquals(-2147483648, $opt$FloatToInt(-9223372036854775807F)); // -(2^63 - 1) + assertIntEquals(-2147483648, $opt$FloatToInt(-9223372036854775808F)); // -(2^63) + assertIntEquals(0, $opt$FloatToInt(Float.NaN)); + assertIntEquals(2147483647, $opt$FloatToInt(Float.POSITIVE_INFINITY)); + assertIntEquals(-2147483648, $opt$FloatToInt(Float.NEGATIVE_INFINITY)); + } + private static void shortToByte() { assertByteEquals((byte)1, $opt$ShortToByte((short)1)); assertByteEquals((byte)0, $opt$ShortToByte((short)0)); @@ -468,6 +497,9 @@ public class Main { // This method produces a long-to-double Dex instruction. static double $opt$LongToDouble(long a){ return (double)a; } + // This method produces a float-to-int Dex instruction. + static int $opt$FloatToInt(float a){ return (int)a; } + // These methods produce int-to-byte Dex instructions. static byte $opt$ShortToByte(short a){ return (byte)a; } static byte $opt$IntToByte(int a){ return (byte)a; } |