summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/Android.common_build.mk21
-rw-r--r--compiler/dex/quick/arm/arm_lir.h1
-rw-r--r--compiler/dex/quick/arm/assemble_arm.cc4
-rw-r--r--compiler/dex/quick/arm/codegen_arm.h9
-rw-r--r--compiler/dex/quick/arm/int_arm.cc1
-rw-r--r--compiler/dex/quick/arm/utility_arm.cc90
-rw-r--r--compiler/optimizing/builder.cc5
-rw-r--r--compiler/optimizing/code_generator.h3
-rw-r--r--compiler/optimizing/code_generator_arm.cc16
-rw-r--r--compiler/optimizing/code_generator_x86.cc32
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc32
-rw-r--r--test/422-type-conversion/src/Main.java32
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; }