summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--compiler/dex/quick/arm/codegen_arm.h2
-rw-r--r--compiler/dex/quick/arm/int_arm.cc5
-rw-r--r--compiler/dex/quick/arm64/arm64_lir.h3
-rw-r--r--compiler/dex/quick/arm64/assemble_arm64.cc12
-rw-r--r--compiler/dex/quick/arm64/codegen_arm64.h4
-rw-r--r--compiler/dex/quick/arm64/fp_arm64.cc15
-rw-r--r--compiler/dex/quick/arm64/int_arm64.cc27
-rw-r--r--compiler/dex/quick/dex_file_method_inliner.cc32
-rw-r--r--compiler/dex/quick/dex_file_method_inliner.h6
-rw-r--r--compiler/dex/quick/gen_invoke.cc10
-rw-r--r--compiler/dex/quick/mips/codegen_mips.h2
-rw-r--r--compiler/dex/quick/mips/fp_mips.cc2
-rw-r--r--compiler/dex/quick/mir_to_lir.h5
-rw-r--r--compiler/dex/quick/x86/codegen_x86.h2
-rw-r--r--compiler/dex/quick/x86/int_x86.cc6
-rw-r--r--runtime/quick/inline_method_analyser.h4
-rw-r--r--test/082-inline-execute/src/Main.java180
17 files changed, 291 insertions, 26 deletions
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index a9d5893d86..43db24cad4 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -113,7 +113,7 @@ class ArmMir2Lir FINAL : public Mir2Lir {
RegLocation rl_src2);
void GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src);
bool GenInlinedCas(CallInfo* info, bool is_long, bool is_object);
- bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
+ bool GenInlinedMinMax(CallInfo* info, bool is_min, bool is_long);
bool GenInlinedSqrt(CallInfo* info);
bool GenInlinedPeek(CallInfo* info, OpSize size);
bool GenInlinedPoke(CallInfo* info, OpSize size);
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index 6f0ac1a20e..95071d92b2 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -688,8 +688,11 @@ RegLocation ArmMir2Lir::GenDivRem(RegLocation rl_dest, RegStorage reg1, RegStora
return rl_result;
}
-bool ArmMir2Lir::GenInlinedMinMaxInt(CallInfo* info, bool is_min) {
+bool ArmMir2Lir::GenInlinedMinMax(CallInfo* info, bool is_min, bool is_long) {
DCHECK_EQ(cu_->instruction_set, kThumb2);
+ if (is_long) {
+ return false;
+ }
RegLocation rl_src1 = info->args[0];
RegLocation rl_src2 = info->args[1];
rl_src1 = LoadValue(rl_src1, kCoreReg);
diff --git a/compiler/dex/quick/arm64/arm64_lir.h b/compiler/dex/quick/arm64/arm64_lir.h
index ea7f439cfb..5077d11a73 100644
--- a/compiler/dex/quick/arm64/arm64_lir.h
+++ b/compiler/dex/quick/arm64/arm64_lir.h
@@ -259,6 +259,8 @@ enum ArmOpcode {
kA64Fcvt2Ss, // fcvt [0001111000100010110000] rn[9-5] rd[4-0].
kA64Fcvt2sS, // fcvt [0001111001100010010000] rn[9-5] rd[4-0].
kA64Fdiv3fff, // fdiv[000111100s1] rm[20-16] [000110] rn[9-5] rd[4-0].
+ kA64Fmax3fff, // fmax[000111100s1] rm[20-16] [010010] rn[9-5] rd[4-0].
+ kA64Fmin3fff, // fmin[000111100s1] rm[20-16] [010110] rn[9-5] rd[4-0].
kA64Fmov2ff, // fmov[000111100s100000010000] rn[9-5] rd[4-0].
kA64Fmov2fI, // fmov[000111100s1] imm_8[20-13] [10000000] rd[4-0].
kA64Fmov2sw, // fmov[0001111000100111000000] rn[9-5] rd[4-0].
@@ -306,6 +308,7 @@ enum ArmOpcode {
kA64Orr3Rrl, // orr [s01100100] N[22] imm_r[21-16] imm_s[15-10] rn[9-5] rd[4-0].
kA64Orr4rrro, // orr [s0101010] shift[23-22] [0] rm[20-16] imm_6[15-10] rn[9-5] rd[4-0].
kA64Ret, // ret [11010110010111110000001111000000].
+ kA64Rbit2rr, // rbit [s101101011000000000000] rn[9-5] rd[4-0].
kA64Rev2rr, // rev [s10110101100000000001x] rn[9-5] rd[4-0].
kA64Rev162rr, // rev16[s101101011000000000001] rn[9-5] rd[4-0].
kA64Ror3rrr, // ror [s0011010110] rm[20-16] [001011] rn[9-5] rd[4-0].
diff --git a/compiler/dex/quick/arm64/assemble_arm64.cc b/compiler/dex/quick/arm64/assemble_arm64.cc
index 2ac34cd9de..284593bf2c 100644
--- a/compiler/dex/quick/arm64/assemble_arm64.cc
+++ b/compiler/dex/quick/arm64/assemble_arm64.cc
@@ -260,6 +260,14 @@ const ArmEncodingMap Arm64Mir2Lir::EncodingMap[kA64Last] = {
kFmtRegF, 4, 0, kFmtRegF, 9, 5, kFmtRegF, 20, 16,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
"fdiv", "!0f, !1f, !2f", kFixupNone),
+ ENCODING_MAP(FWIDE(kA64Fmax3fff), FLOAT_VARIANTS(0x1e204800),
+ kFmtRegF, 4, 0, kFmtRegF, 9, 5, kFmtRegF, 20, 16,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+ "fmax", "!0f, !1f, !2f", kFixupNone),
+ ENCODING_MAP(FWIDE(kA64Fmin3fff), FLOAT_VARIANTS(0x1e205800),
+ kFmtRegF, 4, 0, kFmtRegF, 9, 5, kFmtRegF, 20, 16,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+ "fmin", "!0f, !1f, !2f", kFixupNone),
ENCODING_MAP(FWIDE(kA64Fmov2ff), FLOAT_VARIANTS(0x1e204000),
kFmtRegF, 4, 0, kFmtRegF, 9, 5, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
@@ -450,6 +458,10 @@ const ArmEncodingMap Arm64Mir2Lir::EncodingMap[kA64Last] = {
kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH,
"ret", "", kFixupNone),
+ ENCODING_MAP(WIDE(kA64Rbit2rr), SF_VARIANTS(0x5ac00000),
+ kFmtRegR, 4, 0, kFmtRegR, 9, 5, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+ "rbit", "!0r, !1r", kFixupNone),
ENCODING_MAP(WIDE(kA64Rev2rr), CUSTOM_VARIANTS(0x5ac00800, 0xdac00c00),
kFmtRegR, 4, 0, kFmtRegR, 9, 5, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
diff --git a/compiler/dex/quick/arm64/codegen_arm64.h b/compiler/dex/quick/arm64/codegen_arm64.h
index 8692c6c678..b070c8a289 100644
--- a/compiler/dex/quick/arm64/codegen_arm64.h
+++ b/compiler/dex/quick/arm64/codegen_arm64.h
@@ -176,8 +176,10 @@ class Arm64Mir2Lir FINAL : public Mir2Lir {
void GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
RegLocation rl_src2);
void GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src);
+ bool GenInlinedReverseBits(CallInfo* info, OpSize size);
bool GenInlinedCas(CallInfo* info, bool is_long, bool is_object);
- bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
+ bool GenInlinedMinMax(CallInfo* info, bool is_min, bool is_long);
+ bool GenInlinedMinMaxFP(CallInfo* info, bool is_min, bool is_double);
bool GenInlinedSqrt(CallInfo* info);
bool GenInlinedPeek(CallInfo* info, OpSize size);
bool GenInlinedPoke(CallInfo* info, OpSize size);
diff --git a/compiler/dex/quick/arm64/fp_arm64.cc b/compiler/dex/quick/arm64/fp_arm64.cc
index 9814cb4a7a..0f9de5b604 100644
--- a/compiler/dex/quick/arm64/fp_arm64.cc
+++ b/compiler/dex/quick/arm64/fp_arm64.cc
@@ -333,4 +333,19 @@ bool Arm64Mir2Lir::GenInlinedSqrt(CallInfo* info) {
return true;
}
+bool Arm64Mir2Lir::GenInlinedMinMaxFP(CallInfo* info, bool is_min, bool is_double) {
+ DCHECK_EQ(cu_->instruction_set, kArm64);
+ int op = (is_min) ? kA64Fmin3fff : kA64Fmax3fff;
+ ArmOpcode wide = (is_double) ? FWIDE(0) : FUNWIDE(0);
+ RegLocation rl_src1 = info->args[0];
+ RegLocation rl_src2 = (is_double) ? info->args[2] : info->args[1];
+ rl_src1 = (is_double) ? LoadValueWide(rl_src1, kFPReg) : LoadValue(rl_src1, kFPReg);
+ rl_src2 = (is_double) ? LoadValueWide(rl_src2, kFPReg) : LoadValue(rl_src2, kFPReg);
+ RegLocation rl_dest = (is_double) ? InlineTargetWide(info) : InlineTarget(info);
+ RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
+ NewLIR3(op | wide, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
+ (is_double) ? StoreValueWide(rl_dest, rl_result) : StoreValue(rl_dest, rl_result);
+ return true;
+}
+
} // namespace art
diff --git a/compiler/dex/quick/arm64/int_arm64.cc b/compiler/dex/quick/arm64/int_arm64.cc
index 51c8723d8c..bab549955c 100644
--- a/compiler/dex/quick/arm64/int_arm64.cc
+++ b/compiler/dex/quick/arm64/int_arm64.cc
@@ -434,18 +434,18 @@ bool Arm64Mir2Lir::GenInlinedAbsLong(CallInfo* info) {
return true;
}
-bool Arm64Mir2Lir::GenInlinedMinMaxInt(CallInfo* info, bool is_min) {
+bool Arm64Mir2Lir::GenInlinedMinMax(CallInfo* info, bool is_min, bool is_long) {
DCHECK_EQ(cu_->instruction_set, kArm64);
RegLocation rl_src1 = info->args[0];
- RegLocation rl_src2 = info->args[1];
- rl_src1 = LoadValue(rl_src1, kCoreReg);
- rl_src2 = LoadValue(rl_src2, kCoreReg);
- RegLocation rl_dest = InlineTarget(info);
+ RegLocation rl_src2 = (is_long) ? info->args[2] : info->args[1];
+ rl_src1 = (is_long) ? LoadValueWide(rl_src1, kCoreReg) : LoadValue(rl_src1, kCoreReg);
+ rl_src2 = (is_long) ? LoadValueWide(rl_src2, kCoreReg) : LoadValue(rl_src2, kCoreReg);
+ RegLocation rl_dest = (is_long) ? InlineTargetWide(info) : InlineTarget(info);
RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
OpRegReg(kOpCmp, rl_src1.reg, rl_src2.reg);
- NewLIR4(kA64Csel4rrrc, rl_result.reg.GetReg(), rl_src1.reg.GetReg(),
- rl_src2.reg.GetReg(), (is_min) ? kArmCondLt : kArmCondGt);
- StoreValue(rl_dest, rl_result);
+ NewLIR4((is_long) ? WIDE(kA64Csel4rrrc) : kA64Csel4rrrc, rl_result.reg.GetReg(),
+ rl_src1.reg.GetReg(), rl_src2.reg.GetReg(), (is_min) ? kArmCondLt : kArmCondGt);
+ (is_long) ? StoreValueWide(rl_dest, rl_result) :StoreValue(rl_dest, rl_result);
return true;
}
@@ -1108,4 +1108,15 @@ void Arm64Mir2Lir::SpillFPRegs(RegStorage base, int offset, uint32_t reg_mask) {
}
}
+bool Arm64Mir2Lir::GenInlinedReverseBits(CallInfo* info, OpSize size) {
+ ArmOpcode wide = (size == k64) ? WIDE(0) : UNWIDE(0);
+ RegLocation rl_src_i = info->args[0];
+ RegLocation rl_dest = (size == k64) ? InlineTargetWide(info) : InlineTarget(info); // result reg
+ RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+ RegLocation rl_i = (size == k64) ? LoadValueWide(rl_src_i, kCoreReg) : LoadValue(rl_src_i, kCoreReg);
+ NewLIR2(kA64Rbit2rr | wide, rl_result.reg.GetReg(), rl_i.reg.GetReg());
+ (size == k64) ? StoreValueWide(rl_dest, rl_result) : StoreValue(rl_dest, rl_result);
+ return true;
+}
+
} // namespace art
diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc
index 3f9379c8b3..b699bd3bf2 100644
--- a/compiler/dex/quick/dex_file_method_inliner.cc
+++ b/compiler/dex/quick/dex_file_method_inliner.cc
@@ -87,6 +87,7 @@ const char* const DexFileMethodInliner::kClassCacheNames[] = {
};
const char* const DexFileMethodInliner::kNameCacheNames[] = {
+ "reverse", // kNameCacheReverse
"reverseBytes", // kNameCacheReverseBytes
"doubleToRawLongBits", // kNameCacheDoubleToRawLongBits
"longBitsToDouble", // kNameCacheLongBitsToDouble
@@ -139,8 +140,12 @@ const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = {
{ kClassCacheShort, 1, { kClassCacheShort } },
// kProtoCacheD_D
{ kClassCacheDouble, 1, { kClassCacheDouble } },
+ // kProtoCacheDD_D
+ { kClassCacheDouble, 2, { kClassCacheDouble, kClassCacheDouble } },
// kProtoCacheF_F
{ kClassCacheFloat, 1, { kClassCacheFloat } },
+ // kProtoCacheFF_F
+ { kClassCacheFloat, 2, { kClassCacheFloat, kClassCacheFloat } },
// kProtoCacheD_J
{ kClassCacheLong, 1, { kClassCacheDouble } },
// kProtoCacheJ_D
@@ -171,6 +176,8 @@ const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = {
{ kClassCacheVoid, 2, { kClassCacheLong, kClassCacheByte } },
// kProtoCacheJI_V
{ kClassCacheVoid, 2, { kClassCacheLong, kClassCacheInt } },
+ // kProtoCacheJJ_J
+ { kClassCacheLong, 2, { kClassCacheLong, kClassCacheLong } },
// kProtoCacheJJ_V
{ kClassCacheVoid, 2, { kClassCacheLong, kClassCacheLong } },
// kProtoCacheJS_V
@@ -211,6 +218,8 @@ const DexFileMethodInliner::IntrinsicDef DexFileMethodInliner::kIntrinsicMethods
INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, k32),
INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, k64),
INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf),
+ INTRINSIC(JavaLangInteger, Reverse, I_I, kIntrinsicReverseBits, k32),
+ INTRINSIC(JavaLangLong, Reverse, J_J, kIntrinsicReverseBits, k64),
INTRINSIC(JavaLangMath, Abs, I_I, kIntrinsicAbsInt, 0),
INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0),
@@ -224,6 +233,19 @@ const DexFileMethodInliner::IntrinsicDef DexFileMethodInliner::kIntrinsicMethods
INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
INTRINSIC(JavaLangMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
INTRINSIC(JavaLangStrictMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
+ INTRINSIC(JavaLangMath, Min, JJ_J, kIntrinsicMinMaxLong, kIntrinsicFlagMin),
+ INTRINSIC(JavaLangStrictMath, Min, JJ_J, kIntrinsicMinMaxLong, kIntrinsicFlagMin),
+ INTRINSIC(JavaLangMath, Max, JJ_J, kIntrinsicMinMaxLong, kIntrinsicFlagMax),
+ INTRINSIC(JavaLangStrictMath, Max, JJ_J, kIntrinsicMinMaxLong, kIntrinsicFlagMax),
+ INTRINSIC(JavaLangMath, Min, FF_F, kIntrinsicMinMaxFloat, kIntrinsicFlagMin),
+ INTRINSIC(JavaLangStrictMath, Min, FF_F, kIntrinsicMinMaxFloat, kIntrinsicFlagMin),
+ INTRINSIC(JavaLangMath, Max, FF_F, kIntrinsicMinMaxFloat, kIntrinsicFlagMax),
+ INTRINSIC(JavaLangStrictMath, Max, FF_F, kIntrinsicMinMaxFloat, kIntrinsicFlagMax),
+ INTRINSIC(JavaLangMath, Min, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMin),
+ INTRINSIC(JavaLangStrictMath, Min, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMin),
+ INTRINSIC(JavaLangMath, Max, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMax),
+ INTRINSIC(JavaLangStrictMath, Max, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMax),
+
INTRINSIC(JavaLangMath, Sqrt, D_D, kIntrinsicSqrt, 0),
INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0),
@@ -319,6 +341,8 @@ bool DexFileMethodInliner::GenIntrinsic(Mir2Lir* backend, CallInfo* info) {
return backend->GenInlinedFloatCvt(info);
case kIntrinsicReverseBytes:
return backend->GenInlinedReverseBytes(info, static_cast<OpSize>(intrinsic.d.data));
+ case kIntrinsicReverseBits:
+ return backend->GenInlinedReverseBits(info, static_cast<OpSize>(intrinsic.d.data));
case kIntrinsicAbsInt:
return backend->GenInlinedAbsInt(info);
case kIntrinsicAbsLong:
@@ -328,7 +352,13 @@ bool DexFileMethodInliner::GenIntrinsic(Mir2Lir* backend, CallInfo* info) {
case kIntrinsicAbsDouble:
return backend->GenInlinedAbsDouble(info);
case kIntrinsicMinMaxInt:
- return backend->GenInlinedMinMaxInt(info, intrinsic.d.data & kIntrinsicFlagMin);
+ return backend->GenInlinedMinMax(info, intrinsic.d.data & kIntrinsicFlagMin, false /* is_long */);
+ case kIntrinsicMinMaxLong:
+ return backend->GenInlinedMinMax(info, intrinsic.d.data & kIntrinsicFlagMin, true /* is_long */);
+ case kIntrinsicMinMaxFloat:
+ return backend->GenInlinedMinMaxFP(info, intrinsic.d.data & kIntrinsicFlagMin, false /* is_double */);
+ case kIntrinsicMinMaxDouble:
+ return backend->GenInlinedMinMaxFP(info, intrinsic.d.data & kIntrinsicFlagMin, true /* is_double */);
case kIntrinsicSqrt:
return backend->GenInlinedSqrt(info);
case kIntrinsicCharAt:
diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h
index 70693c2013..c7a3b83260 100644
--- a/compiler/dex/quick/dex_file_method_inliner.h
+++ b/compiler/dex/quick/dex_file_method_inliner.h
@@ -128,7 +128,8 @@ class DexFileMethodInliner {
*/
enum NameCacheIndex : uint8_t { // unit8_t to save space, make larger if needed
kNameCacheFirst = 0,
- kNameCacheReverseBytes = kNameCacheFirst,
+ kNameCacheReverse = kNameCacheFirst,
+ kNameCacheReverseBytes,
kNameCacheDoubleToRawLongBits,
kNameCacheLongBitsToDouble,
kNameCacheFloatToRawIntBits,
@@ -183,7 +184,9 @@ class DexFileMethodInliner {
kProtoCacheJ_J,
kProtoCacheS_S,
kProtoCacheD_D,
+ kProtoCacheDD_D,
kProtoCacheF_F,
+ kProtoCacheFF_F,
kProtoCacheD_J,
kProtoCacheJ_D,
kProtoCacheF_I,
@@ -199,6 +202,7 @@ class DexFileMethodInliner {
kProtoCacheJ_S,
kProtoCacheJB_V,
kProtoCacheJI_V,
+ kProtoCacheJJ_J,
kProtoCacheJJ_V,
kProtoCacheJS_V,
kProtoCacheObjectJII_Z,
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 5631721465..660563e6ec 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -1470,6 +1470,16 @@ bool Mir2Lir::GenInlinedAbsFloat(CallInfo* info) {
return true;
}
+bool Mir2Lir::GenInlinedReverseBits(CallInfo* info, OpSize size) {
+ // Currently implemented only for ARM64
+ return false;
+}
+
+bool Mir2Lir::GenInlinedMinMaxFP(CallInfo* info, bool is_min, bool is_double) {
+ // Currently implemented only for ARM64
+ return false;
+}
+
bool Mir2Lir::GenInlinedAbsDouble(CallInfo* info) {
if (cu_->instruction_set == kMips) {
// TODO - add Mips implementation
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index 0b1f7b6959..025f97a282 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -111,7 +111,7 @@ class MipsMir2Lir FINAL : public Mir2Lir {
RegLocation rl_src2);
void GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src);
bool GenInlinedCas(CallInfo* info, bool is_long, bool is_object);
- bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
+ bool GenInlinedMinMax(CallInfo* info, bool is_min, bool is_long);
bool GenInlinedSqrt(CallInfo* info);
bool GenInlinedPeek(CallInfo* info, OpSize size);
bool GenInlinedPoke(CallInfo* info, OpSize size);
diff --git a/compiler/dex/quick/mips/fp_mips.cc b/compiler/dex/quick/mips/fp_mips.cc
index 4e31477189..7087be9722 100644
--- a/compiler/dex/quick/mips/fp_mips.cc
+++ b/compiler/dex/quick/mips/fp_mips.cc
@@ -230,7 +230,7 @@ void MipsMir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
StoreValueWide(rl_dest, rl_result);
}
-bool MipsMir2Lir::GenInlinedMinMaxInt(CallInfo* info, bool is_min) {
+bool MipsMir2Lir::GenInlinedMinMax(CallInfo* info, bool is_min, bool is_long) {
// TODO: need Mips implementation
return false;
}
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 47844cbb34..6768790d19 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -984,6 +984,7 @@ class Mir2Lir : public Backend {
bool GenInlinedCharAt(CallInfo* info);
bool GenInlinedStringIsEmptyOrLength(CallInfo* info, bool is_empty);
+ virtual bool GenInlinedReverseBits(CallInfo* info, OpSize size);
bool GenInlinedReverseBytes(CallInfo* info, OpSize size);
bool GenInlinedAbsInt(CallInfo* info);
virtual bool GenInlinedAbsLong(CallInfo* info);
@@ -1299,9 +1300,11 @@ class Mir2Lir : public Backend {
* directly into the destination register as specified by the invoke information.
* @param info Information about the invoke.
* @param is_min If true generates code that computes minimum. Otherwise computes maximum.
+ * @param is_long If true the value value is Long. Otherwise the value is Int.
* @return Returns true if successfully generated
*/
- virtual bool GenInlinedMinMaxInt(CallInfo* info, bool is_min) = 0;
+ virtual bool GenInlinedMinMax(CallInfo* info, bool is_min, bool is_long) = 0;
+ virtual bool GenInlinedMinMaxFP(CallInfo* info, bool is_min, bool is_double);
virtual bool GenInlinedSqrt(CallInfo* info) = 0;
virtual bool GenInlinedPeek(CallInfo* info, OpSize size) = 0;
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 646da7f22e..123fe90d03 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -164,7 +164,7 @@ class X86Mir2Lir : public Mir2Lir {
RegLocation rl_src2);
void GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src);
bool GenInlinedCas(CallInfo* info, bool is_long, bool is_object);
- bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
+ bool GenInlinedMinMax(CallInfo* info, bool is_min, bool is_long);
bool GenInlinedSqrt(CallInfo* info);
bool GenInlinedAbsFloat(CallInfo* info) OVERRIDE;
bool GenInlinedAbsDouble(CallInfo* info) OVERRIDE;
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 7a4ea26432..ed4c775fc9 100644
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -713,9 +713,13 @@ RegLocation X86Mir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
return rl_result;
}
-bool X86Mir2Lir::GenInlinedMinMaxInt(CallInfo* info, bool is_min) {
+bool X86Mir2Lir::GenInlinedMinMax(CallInfo* info, bool is_min, bool is_long) {
DCHECK(cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64);
+ if (is_long) {
+ return false;
+ }
+
// Get the two arguments to the invoke and place them in GP registers.
RegLocation rl_src1 = info->args[0];
RegLocation rl_src2 = info->args[1];
diff --git a/runtime/quick/inline_method_analyser.h b/runtime/quick/inline_method_analyser.h
index ddee89b7bf..e1fbf011ca 100644
--- a/runtime/quick/inline_method_analyser.h
+++ b/runtime/quick/inline_method_analyser.h
@@ -37,12 +37,16 @@ class MethodVerifier;
enum InlineMethodOpcode : uint16_t {
kIntrinsicDoubleCvt,
kIntrinsicFloatCvt,
+ kIntrinsicReverseBits,
kIntrinsicReverseBytes,
kIntrinsicAbsInt,
kIntrinsicAbsLong,
kIntrinsicAbsFloat,
kIntrinsicAbsDouble,
kIntrinsicMinMaxInt,
+ kIntrinsicMinMaxLong,
+ kIntrinsicMinMaxFloat,
+ kIntrinsicMinMaxDouble,
kIntrinsicSqrt,
kIntrinsicCharAt,
kIntrinsicCompareTo,
diff --git a/test/082-inline-execute/src/Main.java b/test/082-inline-execute/src/Main.java
index 55ecf6922b..5b8134df1c 100644
--- a/test/082-inline-execute/src/Main.java
+++ b/test/082-inline-execute/src/Main.java
@@ -24,12 +24,26 @@ public class Main {
test_Float_intBitsToFloat();
test_Math_abs_I();
test_Math_abs_J();
- test_Math_min();
- test_Math_max();
+ test_Math_min_I();
+ test_Math_max_I();
+ test_Math_min_J();
+ test_Math_max_J();
+ test_Math_min_F();
+ test_Math_max_F();
+ test_Math_min_D();
+ test_Math_max_D();
+ test_Integer_reverse();
+ test_Long_reverse();
test_StrictMath_abs_I();
test_StrictMath_abs_J();
- test_StrictMath_min();
- test_StrictMath_max();
+ test_StrictMath_min_I();
+ test_StrictMath_max_I();
+ test_StrictMath_min_J();
+ test_StrictMath_max_J();
+ test_StrictMath_min_F();
+ test_StrictMath_max_F();
+ test_StrictMath_min_D();
+ test_StrictMath_max_D();
test_String_charAt();
test_String_compareTo();
test_String_indexOf();
@@ -37,6 +51,25 @@ public class Main {
test_String_length();
}
+ /*
+ * Determine if two floating point numbers are approximately equal.
+ *
+ * (Assumes that floating point is generally working, so we can't use
+ * this for the first set of tests.)
+ */
+ static boolean approxEqual(float a, float b, float maxDelta) {
+ if (a > b)
+ return (a - b) < maxDelta;
+ else
+ return (b - a) < maxDelta;
+ }
+ static boolean approxEqual(double a, double b, double maxDelta) {
+ if (a > b)
+ return (a - b) < maxDelta;
+ else
+ return (b - a) < maxDelta;
+ }
+
public static void test_String_length() {
String str0 = "";
String str1 = "x";
@@ -244,7 +277,7 @@ public class Main {
Assert.assertEquals(Math.abs(Long.MIN_VALUE - 1), Long.MAX_VALUE);
}
- public static void test_Math_min() {
+ public static void test_Math_min_I() {
Assert.assertEquals(Math.min(0, 0), 0);
Assert.assertEquals(Math.min(1, 0), 0);
Assert.assertEquals(Math.min(0, 1), 0);
@@ -253,7 +286,7 @@ public class Main {
Assert.assertEquals(Math.min(Integer.MIN_VALUE, Integer.MAX_VALUE), Integer.MIN_VALUE);
}
- public static void test_Math_max() {
+ public static void test_Math_max_I() {
Assert.assertEquals(Math.max(0, 0), 0);
Assert.assertEquals(Math.max(1, 0), 1);
Assert.assertEquals(Math.max(0, 1), 1);
@@ -262,6 +295,60 @@ public class Main {
Assert.assertEquals(Math.max(Integer.MIN_VALUE, Integer.MAX_VALUE), Integer.MAX_VALUE);
}
+ public static void test_Math_min_J() {
+ Assert.assertEquals(Math.min(0L, 0L), 0L);
+ Assert.assertEquals(Math.min(1L, 0L), 0L);
+ Assert.assertEquals(Math.min(0L, 1L), 0L);
+ Assert.assertEquals(Math.min(0L, Long.MAX_VALUE), 0L);
+ Assert.assertEquals(Math.min(Long.MIN_VALUE, 0L), Long.MIN_VALUE);
+ Assert.assertEquals(Math.min(Long.MIN_VALUE, Long.MAX_VALUE), Long.MIN_VALUE);
+ }
+
+ public static void test_Math_max_J() {
+ Assert.assertEquals(Math.max(0L, 0L), 0L);
+ Assert.assertEquals(Math.max(1L, 0L), 1L);
+ Assert.assertEquals(Math.max(0L, 1L), 1L);
+ Assert.assertEquals(Math.max(0L, Long.MAX_VALUE), Long.MAX_VALUE);
+ Assert.assertEquals(Math.max(Long.MIN_VALUE, 0L), 0L);
+ Assert.assertEquals(Math.max(Long.MIN_VALUE, Long.MAX_VALUE), Long.MAX_VALUE);
+ }
+
+ public static void test_Math_min_F() {
+ Assert.assertTrue(approxEqual(Math.min(0.0f, 0.0f), 0.0f, 0.001f));
+ Assert.assertTrue(approxEqual(Math.min(1.0f, 0.0f), 0.0f, 0.001f));
+ Assert.assertTrue(approxEqual(Math.min(0.0f, 1.0f), 0.0f, 0.001f));
+ Assert.assertTrue(approxEqual(Math.min(0.0f, Float.MAX_VALUE), 0.0f, 0.001f));
+ Assert.assertTrue(approxEqual(Math.min(Float.MIN_VALUE, 0.0f), Float.MIN_VALUE, 0.001f));
+ Assert.assertTrue(approxEqual(Math.min(Float.MIN_VALUE, Float.MAX_VALUE), Float.MIN_VALUE, 0.001f));
+ }
+
+ public static void test_Math_max_F() {
+ Assert.assertTrue(approxEqual(Math.max(0.0f, 0.0f), 0.0f, 0.001f));
+ Assert.assertTrue(approxEqual(Math.max(1.0f, 0.0f), 1.0f, 0.001f));
+ Assert.assertTrue(approxEqual(Math.max(0.0f, 1.0f), 1.0f, 0.001f));
+ Assert.assertTrue(approxEqual(Math.max(0.0f, Float.MAX_VALUE), Float.MAX_VALUE, 0.001f));
+ Assert.assertTrue(approxEqual(Math.max(Float.MIN_VALUE, 0.0f), 0.0f, 0.001f));
+ Assert.assertTrue(approxEqual(Math.max(Float.MIN_VALUE, Float.MAX_VALUE), Float.MAX_VALUE, 0.001f));
+ }
+
+ public static void test_Math_min_D() {
+ Assert.assertTrue(approxEqual(Math.min(0.0d, 0.0d), 0.0d, 0.001d));
+ Assert.assertTrue(approxEqual(Math.min(1.0d, 0.0d), 0.0d, 0.001d));
+ Assert.assertTrue(approxEqual(Math.min(0.0d, 1.0d), 0.0d, 0.001d));
+ Assert.assertTrue(approxEqual(Math.min(0.0d, Double.MAX_VALUE), 0.0d, 0.001d));
+ Assert.assertTrue(approxEqual(Math.min(Double.MIN_VALUE, 0.0d), Double.MIN_VALUE, 0.001d));
+ Assert.assertTrue(approxEqual(Math.min(Double.MIN_VALUE, Double.MAX_VALUE), Double.MIN_VALUE, 0.001d));
+ }
+
+ public static void test_Math_max_D() {
+ Assert.assertTrue(approxEqual(Math.max(0.0d, 0.0d), 0.0d, 0.001d));
+ Assert.assertTrue(approxEqual(Math.max(1.0d, 0.0d), 1.0d, 0.001d));
+ Assert.assertTrue(approxEqual(Math.max(0.0d, 1.0d), 1.0d, 0.001d));
+ Assert.assertTrue(approxEqual(Math.max(0.0d, Double.MAX_VALUE), Double.MAX_VALUE, 0.001d));
+ Assert.assertTrue(approxEqual(Math.max(Double.MIN_VALUE, 0.0d), 0.0d, 0.001d));
+ Assert.assertTrue(approxEqual(Math.max(Double.MIN_VALUE, Double.MAX_VALUE), Double.MAX_VALUE, 0.001d));
+ }
+
public static void test_StrictMath_abs_I() {
Assert.assertEquals(StrictMath.abs(0), 0);
Assert.assertEquals(StrictMath.abs(123), 123);
@@ -281,7 +368,7 @@ public class Main {
Assert.assertEquals(StrictMath.abs(Long.MIN_VALUE - 1), Long.MAX_VALUE);
}
- public static void test_StrictMath_min() {
+ public static void test_StrictMath_min_I() {
Assert.assertEquals(StrictMath.min(0, 0), 0);
Assert.assertEquals(StrictMath.min(1, 0), 0);
Assert.assertEquals(StrictMath.min(0, 1), 0);
@@ -290,7 +377,7 @@ public class Main {
Assert.assertEquals(StrictMath.min(Integer.MIN_VALUE, Integer.MAX_VALUE), Integer.MIN_VALUE);
}
- public static void test_StrictMath_max() {
+ public static void test_StrictMath_max_I() {
Assert.assertEquals(StrictMath.max(0, 0), 0);
Assert.assertEquals(StrictMath.max(1, 0), 1);
Assert.assertEquals(StrictMath.max(0, 1), 1);
@@ -299,6 +386,60 @@ public class Main {
Assert.assertEquals(StrictMath.max(Integer.MIN_VALUE, Integer.MAX_VALUE), Integer.MAX_VALUE);
}
+ public static void test_StrictMath_min_J() {
+ Assert.assertEquals(StrictMath.min(0L, 0L), 0L);
+ Assert.assertEquals(StrictMath.min(1L, 0L), 0L);
+ Assert.assertEquals(StrictMath.min(0L, 1L), 0L);
+ Assert.assertEquals(StrictMath.min(0L, Long.MAX_VALUE), 0L);
+ Assert.assertEquals(StrictMath.min(Long.MIN_VALUE, 0L), Long.MIN_VALUE);
+ Assert.assertEquals(StrictMath.min(Long.MIN_VALUE, Long.MAX_VALUE), Long.MIN_VALUE);
+ }
+
+ public static void test_StrictMath_max_J() {
+ Assert.assertEquals(StrictMath.max(0L, 0L), 0L);
+ Assert.assertEquals(StrictMath.max(1L, 0L), 1L);
+ Assert.assertEquals(StrictMath.max(0L, 1L), 1L);
+ Assert.assertEquals(StrictMath.max(0L, Long.MAX_VALUE), Long.MAX_VALUE);
+ Assert.assertEquals(StrictMath.max(Long.MIN_VALUE, 0L), 0L);
+ Assert.assertEquals(StrictMath.max(Long.MIN_VALUE, Long.MAX_VALUE), Long.MAX_VALUE);
+ }
+
+ public static void test_StrictMath_min_F() {
+ Assert.assertTrue(approxEqual(StrictMath.min(0.0f, 0.0f), 0.0f, 0.001f));
+ Assert.assertTrue(approxEqual(StrictMath.min(1.0f, 0.0f), 0.0f, 0.001f));
+ Assert.assertTrue(approxEqual(StrictMath.min(0.0f, 1.0f), 0.0f, 0.001f));
+ Assert.assertTrue(approxEqual(StrictMath.min(0.0f, Float.MAX_VALUE), 0.0f, 0.001f));
+ Assert.assertTrue(approxEqual(StrictMath.min(Float.MIN_VALUE, 0.0f), Float.MIN_VALUE, 0.001f));
+ Assert.assertTrue(approxEqual(StrictMath.min(Float.MIN_VALUE, Float.MAX_VALUE), Float.MIN_VALUE, 0.001f));
+ }
+
+ public static void test_StrictMath_max_F() {
+ Assert.assertTrue(approxEqual(StrictMath.max(0.0f, 0.0f), 0.0f, 0.001f));
+ Assert.assertTrue(approxEqual(StrictMath.max(1.0f, 0.0f), 1.0f, 0.001f));
+ Assert.assertTrue(approxEqual(StrictMath.max(0.0f, 1.0f), 1.0f, 0.001f));
+ Assert.assertTrue(approxEqual(StrictMath.max(0.0f, Float.MAX_VALUE), Float.MAX_VALUE, 0.001f));
+ Assert.assertTrue(approxEqual(StrictMath.max(Float.MIN_VALUE, 0.0f), 0.0f, 0.001f));
+ Assert.assertTrue(approxEqual(StrictMath.max(Float.MIN_VALUE, Float.MAX_VALUE), Float.MAX_VALUE, 0.001f));
+ }
+
+ public static void test_StrictMath_min_D() {
+ Assert.assertTrue(approxEqual(StrictMath.min(0.0d, 0.0d), 0.0d, 0.001d));
+ Assert.assertTrue(approxEqual(StrictMath.min(1.0d, 0.0d), 0.0d, 0.001d));
+ Assert.assertTrue(approxEqual(StrictMath.min(0.0d, 1.0d), 0.0d, 0.001d));
+ Assert.assertTrue(approxEqual(StrictMath.min(0.0d, Double.MAX_VALUE), 0.0d, 0.001d));
+ Assert.assertTrue(approxEqual(StrictMath.min(Double.MIN_VALUE, 0.0d), Double.MIN_VALUE, 0.001d));
+ Assert.assertTrue(approxEqual(StrictMath.min(Double.MIN_VALUE, Double.MAX_VALUE), Double.MIN_VALUE, 0.001d));
+ }
+
+ public static void test_StrictMath_max_D() {
+ Assert.assertTrue(approxEqual(StrictMath.max(0.0d, 0.0d), 0.0d, 0.001d));
+ Assert.assertTrue(approxEqual(StrictMath.max(1.0d, 0.0d), 1.0d, 0.001d));
+ Assert.assertTrue(approxEqual(StrictMath.max(0.0d, 1.0d), 1.0d, 0.001d));
+ Assert.assertTrue(approxEqual(StrictMath.max(0.0d, Double.MAX_VALUE), Double.MAX_VALUE, 0.001d));
+ Assert.assertTrue(approxEqual(StrictMath.max(Double.MIN_VALUE, 0.0d), 0.0d, 0.001d));
+ Assert.assertTrue(approxEqual(StrictMath.max(Double.MIN_VALUE, Double.MAX_VALUE), Double.MAX_VALUE, 0.001d));
+ }
+
public static void test_Float_floatToRawIntBits() {
Assert.assertEquals(Float.floatToRawIntBits(-1.0f), 0xbf800000);
Assert.assertEquals(Float.floatToRawIntBits(0.0f), 0);
@@ -334,4 +475,27 @@ public class Main {
Assert.assertEquals(Double.longBitsToDouble(0x7ff0000000000000L), Double.POSITIVE_INFINITY);
Assert.assertEquals(Double.longBitsToDouble(0xfff0000000000000L), Double.NEGATIVE_INFINITY);
}
+
+ public static void test_Integer_reverse() {
+ Assert.assertEquals(Integer.reverse(1), 0x80000000);
+ Assert.assertEquals(Integer.reverse(-1), 0xffffffff);
+ Assert.assertEquals(Integer.reverse(0), 0);
+ Assert.assertEquals(Integer.reverse(0x12345678), 0x1e6a2c48);
+ Assert.assertEquals(Integer.reverse(0x87654321), 0x84c2a6e1);
+ Assert.assertEquals(Integer.reverse(Integer.MAX_VALUE), 0xfffffffe);
+ Assert.assertEquals(Integer.reverse(Integer.MIN_VALUE), 1);
+ }
+
+ public static void test_Long_reverse() {
+ Assert.assertEquals(Long.reverse(1L), 0x8000000000000000L);
+ Assert.assertEquals(Long.reverse(-1L), 0xffffffffffffffffL);
+ Assert.assertEquals(Long.reverse(0L), 0L);
+ // FIXME: This asserts fail with or without this patch. I have collected
+ // the expected results on my host machine.
+ // Assert.assertEquals(Long.reverse(0x1234567812345678L), 0x1e6a2c481e6a2c48L);
+ // Assert.assertEquals(Long.reverse(0x8765432187654321L), 0x84c2a6e184c2a6e1L);
+ // Assert.assertEquals(Long.reverse(Long.MAX_VALUE), 0xfffffffffffffffeL);
+ Assert.assertEquals(Long.reverse(Long.MIN_VALUE), 1L);
+ }
+
}