diff options
author | Serban Constantinescu <serban.constantinescu@arm.com> | 2014-06-11 16:43:35 +0100 |
---|---|---|
committer | buzbee <buzbee@google.com> | 2014-06-12 14:50:28 -0700 |
commit | 169489b4f4be8c5dd880ba6f152948324d22ff79 (patch) | |
tree | b6b267d402ee5badf53c6e2cca3d98647ab6c0f6 | |
parent | cbaa3076b51db805c5e74636d77c8c7cbd79d125 (diff) | |
download | art-169489b4f4be8c5dd880ba6f152948324d22ff79.zip art-169489b4f4be8c5dd880ba6f152948324d22ff79.tar.gz art-169489b4f4be8c5dd880ba6f152948324d22ff79.tar.bz2 |
AArch64: Add support for inlined methods
This patch adds support for Arm64 inlined methods.
Change-Id: Ic6aeed6d2d32f65cd1e63cf482f83cdcf958798a
-rw-r--r-- | compiler/dex/quick/arm64/arm64_lir.h | 2 | ||||
-rw-r--r-- | compiler/dex/quick/arm64/assemble_arm64.cc | 16 | ||||
-rw-r--r-- | compiler/dex/quick/arm64/codegen_arm64.h | 1 | ||||
-rw-r--r-- | compiler/dex/quick/arm64/int_arm64.cc | 203 | ||||
-rw-r--r-- | compiler/dex/quick/arm64/utility_arm64.cc | 4 | ||||
-rw-r--r-- | compiler/dex/quick/gen_invoke.cc | 19 | ||||
-rw-r--r-- | compiler/dex/quick/mir_to_lir.h | 2 | ||||
-rw-r--r-- | runtime/arch/arm64/quick_entrypoints_arm64.S | 98 |
8 files changed, 190 insertions, 155 deletions
diff --git a/compiler/dex/quick/arm64/arm64_lir.h b/compiler/dex/quick/arm64/arm64_lir.h index e15ccb4..c1ce03d 100644 --- a/compiler/dex/quick/arm64/arm64_lir.h +++ b/compiler/dex/quick/arm64/arm64_lir.h @@ -286,6 +286,7 @@ enum ArmOpcode { kA64Ldur3fXd, // ldur[1s111100010] imm_9[20-12] [00] rn[9-5] rt[4-0]. kA64Ldur3rXd, // ldur[1s111000010] imm_9[20-12] [00] rn[9-5] rt[4-0]. kA64Ldxr2rX, // ldxr[1s00100001011111011111] rn[9-5] rt[4-0]. + kA64Ldaxr2rX, // ldaxr[1s00100001011111111111] rn[9-5] rt[4-0]. kA64Lsl3rrr, // lsl [s0011010110] rm[20-16] [001000] rn[9-5] rd[4-0]. kA64Lsr3rrd, // lsr alias of "ubfm arg0, arg1, arg2, #{31/63}". kA64Lsr3rrr, // lsr [s0011010110] rm[20-16] [001001] rn[9-5] rd[4-0]. @@ -325,6 +326,7 @@ enum ArmOpcode { kA64Stur3fXd, // stur[1s111100000] imm_9[20-12] [00] rn[9-5] rt[4-0]. kA64Stur3rXd, // stur[1s111000000] imm_9[20-12] [00] rn[9-5] rt[4-0]. kA64Stxr3wrX, // stxr[11001000000] rs[20-16] [011111] rn[9-5] rt[4-0]. + kA64Stlxr3wrX, // stlxr[11001000000] rs[20-16] [111111] rn[9-5] rt[4-0]. kA64Sub4RRdT, // sub [s101000100] imm_12[21-10] rn[9-5] rd[4-0]. kA64Sub4rrro, // sub [s1001011000] rm[20-16] option[15-13] imm_3[12-10] rn[9-5] rd[4-0]. kA64Subs3rRd, // subs[s111000100] imm_12[21-10] 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 fcaaba5..2c4f262 100644 --- a/compiler/dex/quick/arm64/assemble_arm64.cc +++ b/compiler/dex/quick/arm64/assemble_arm64.cc @@ -386,6 +386,10 @@ const ArmEncodingMap Arm64Mir2Lir::EncodingMap[kA64Last] = { kFmtRegR, 4, 0, kFmtRegXOrSp, 9, 5, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1 | IS_LOAD, "ldxr", "!0r, [!1X]", kFixupNone), + ENCODING_MAP(WIDE(kA64Ldaxr2rX), SIZE_VARIANTS(0x885ffc00), + kFmtRegR, 4, 0, kFmtRegXOrSp, 9, 5, kFmtUnused, -1, -1, + kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1 | IS_LOAD, + "ldaxr", "!0r, [!1X]", kFixupNone), ENCODING_MAP(WIDE(kA64Lsl3rrr), SF_VARIANTS(0x1ac02000), kFmtRegR, 4, 0, kFmtRegR, 9, 5, kFmtRegR, 20, 16, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, @@ -443,11 +447,11 @@ const ArmEncodingMap Arm64Mir2Lir::EncodingMap[kA64Last] = { kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH, "ret", "", kFixupNone), ENCODING_MAP(WIDE(kA64Rev2rr), CUSTOM_VARIANTS(0x5ac00800, 0xdac00c00), - kFmtRegR, 11, 8, kFmtRegR, 19, 16, kFmtUnused, -1, -1, + kFmtRegR, 4, 0, kFmtRegR, 9, 5, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, "rev", "!0r, !1r", kFixupNone), - ENCODING_MAP(WIDE(kA64Rev162rr), SF_VARIANTS(0xfa90f0b0), - kFmtRegR, 11, 8, kFmtRegR, 19, 16, kFmtUnused, -1, -1, + ENCODING_MAP(WIDE(kA64Rev162rr), SF_VARIANTS(0x5ac00400), + kFmtRegR, 4, 0, kFmtRegR, 9, 5, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, "rev16", "!0r, !1r", kFixupNone), ENCODING_MAP(WIDE(kA64Ror3rrr), SF_VARIANTS(0x1ac02c00), @@ -542,6 +546,10 @@ const ArmEncodingMap Arm64Mir2Lir::EncodingMap[kA64Last] = { kFmtRegW, 20, 16, kFmtRegR, 4, 0, kFmtRegXOrSp, 9, 5, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_STORE, "stxr", "!0w, !1r, [!2X]", kFixupNone), + ENCODING_MAP(WIDE(kA64Stlxr3wrX), SIZE_VARIANTS(0x8800fc00), + kFmtRegW, 20, 16, kFmtRegR, 4, 0, kFmtRegXOrSp, 9, 5, + kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_STORE, + "stlxr", "!0w, !1r, [!2X]", kFixupNone), ENCODING_MAP(WIDE(kA64Sub4RRdT), SF_VARIANTS(0x51000000), kFmtRegROrSp, 4, 0, kFmtRegROrSp, 9, 5, kFmtBitBlt, 21, 10, kFmtBitBlt, 23, 22, IS_QUAD_OP | REG_DEF0_USE1, @@ -803,7 +811,7 @@ void Arm64Mir2Lir::AssembleLIR() { DCHECK(target_lir); CodeOffset pc = lir->offset; CodeOffset target = target_lir->offset + - ((target_lir->flags.generation == lir->flags.generation) ? 0 : offset_adjustment); + ((target_lir->flags.generation == lir->flags.generation) ? 0 : offset_adjustment); int32_t delta = target - pc; if (!((delta & 0x3) == 0 && IS_SIGNED_IMM19(delta >> 2))) { LOG(FATAL) << "Invalid jump range in kFixupLoad"; diff --git a/compiler/dex/quick/arm64/codegen_arm64.h b/compiler/dex/quick/arm64/codegen_arm64.h index 8ecc393..bf09b86 100644 --- a/compiler/dex/quick/arm64/codegen_arm64.h +++ b/compiler/dex/quick/arm64/codegen_arm64.h @@ -124,6 +124,7 @@ class Arm64Mir2Lir : public Mir2Lir { bool GenInlinedSqrt(CallInfo* info); bool GenInlinedPeek(CallInfo* info, OpSize size); bool GenInlinedPoke(CallInfo* info, OpSize size); + bool GenInlinedAbsLong(CallInfo* info); void GenIntToLong(RegLocation rl_dest, RegLocation rl_src); void GenNotLong(RegLocation rl_dest, RegLocation rl_src); void GenNegLong(RegLocation rl_dest, RegLocation rl_src); diff --git a/compiler/dex/quick/arm64/int_arm64.cc b/compiler/dex/quick/arm64/int_arm64.cc index a18cc82..8112c2e 100644 --- a/compiler/dex/quick/arm64/int_arm64.cc +++ b/compiler/dex/quick/arm64/int_arm64.cc @@ -361,11 +361,22 @@ RegLocation Arm64Mir2Lir::GenDivRem(RegLocation rl_dest, RegStorage r_src1, RegS return rl_result; } -bool Arm64Mir2Lir::GenInlinedMinMaxInt(CallInfo* info, bool is_min) { - // TODO(Arm64): implement this. - UNIMPLEMENTED(FATAL); +bool Arm64Mir2Lir::GenInlinedAbsLong(CallInfo* info) { + RegLocation rl_src = info->args[0]; + rl_src = LoadValueWide(rl_src, kCoreReg); + RegLocation rl_dest = InlineTargetWide(info); + RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); + RegStorage sign_reg = AllocTempWide(); + // abs(x) = y<=x>>63, (x+y)^y. + OpRegRegImm(kOpAsr, sign_reg, rl_src.reg, 63); + OpRegRegReg(kOpAdd, rl_result.reg, rl_src.reg, sign_reg); + OpRegReg(kOpXor, rl_result.reg, sign_reg); + StoreValueWide(rl_dest, rl_result); + return true; +} - DCHECK_EQ(cu_->instruction_set, kThumb2); +bool Arm64Mir2Lir::GenInlinedMinMaxInt(CallInfo* info, bool is_min) { + DCHECK_EQ(cu_->instruction_set, kArm64); RegLocation rl_src1 = info->args[0]; RegLocation rl_src2 = info->args[1]; rl_src1 = LoadValue(rl_src1, kCoreReg); @@ -373,61 +384,43 @@ bool Arm64Mir2Lir::GenInlinedMinMaxInt(CallInfo* info, bool is_min) { RegLocation rl_dest = InlineTarget(info); RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); OpRegReg(kOpCmp, rl_src1.reg, rl_src2.reg); - // OpIT((is_min) ? kCondGt : kCondLt, "E"); - OpRegReg(kOpMov, rl_result.reg, rl_src2.reg); - OpRegReg(kOpMov, rl_result.reg, rl_src1.reg); - GenBarrier(); + NewLIR4(kA64Csel4rrrc, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), + rl_src2.reg.GetReg(), (is_min) ? kArmCondLt : kArmCondGt); StoreValue(rl_dest, rl_result); return true; } bool Arm64Mir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) { - // TODO(Arm64): implement this. - UNIMPLEMENTED(WARNING); - RegLocation rl_src_address = info->args[0]; // long address - rl_src_address = NarrowRegLoc(rl_src_address); // ignore high half in info->args[1] + rl_src_address = NarrowRegLoc(rl_src_address); // ignore high half in info->args[1] ? RegLocation rl_dest = InlineTarget(info); - RegLocation rl_address = LoadValue(rl_src_address, kCoreReg); + RegLocation rl_address = LoadValue(rl_src_address, kCoreReg); // kRefReg RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); + + LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size); if (size == k64) { - // Fake unaligned LDRD by two unaligned LDR instructions on ARMv7 with SCTLR.A set to 0. - if (rl_address.reg.GetReg() != rl_result.reg.GetLowReg()) { - LoadWordDisp(rl_address.reg, 0, rl_result.reg.GetLow()); - LoadWordDisp(rl_address.reg, 4, rl_result.reg.GetHigh()); - } else { - LoadWordDisp(rl_address.reg, 4, rl_result.reg.GetHigh()); - LoadWordDisp(rl_address.reg, 0, rl_result.reg.GetLow()); - } StoreValueWide(rl_dest, rl_result); } else { DCHECK(size == kSignedByte || size == kSignedHalf || size == k32); - // Unaligned load with LDR and LDRSH is allowed on ARMv7 with SCTLR.A set to 0. - LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size); StoreValue(rl_dest, rl_result); } return true; } bool Arm64Mir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) { - // TODO(Arm64): implement this. - UNIMPLEMENTED(WARNING); - RegLocation rl_src_address = info->args[0]; // long address rl_src_address = NarrowRegLoc(rl_src_address); // ignore high half in info->args[1] RegLocation rl_src_value = info->args[2]; // [size] value - RegLocation rl_address = LoadValue(rl_src_address, kCoreReg); + RegLocation rl_address = LoadValue(rl_src_address, kCoreReg); // kRefReg + + RegLocation rl_value; if (size == k64) { - // Fake unaligned STRD by two unaligned STR instructions on ARMv7 with SCTLR.A set to 0. - RegLocation rl_value = LoadValueWide(rl_src_value, kCoreReg); - StoreBaseDisp(rl_address.reg, 0, rl_value.reg.GetLow(), k32); - StoreBaseDisp(rl_address.reg, 4, rl_value.reg.GetHigh(), k32); + rl_value = LoadValueWide(rl_src_value, kCoreReg); } else { DCHECK(size == kSignedByte || size == kSignedHalf || size == k32); - // Unaligned store with STR and STRSH is allowed on ARMv7 with SCTLR.A set to 0. - RegLocation rl_value = LoadValue(rl_src_value, kCoreReg); - StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size); + rl_value = LoadValue(rl_src_value, kCoreReg); } + StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size); return true; } @@ -444,71 +437,30 @@ void Arm64Mir2Lir::OpTlsCmp(ThreadOffset<8> offset, int val) { } bool Arm64Mir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) { - // TODO(Arm64): implement this. - UNIMPLEMENTED(WARNING); - - DCHECK_EQ(cu_->instruction_set, kThumb2); + DCHECK_EQ(cu_->instruction_set, kArm64); + ArmOpcode wide = is_long ? WIDE(0) : UNWIDE(0); // Unused - RegLocation rl_src_unsafe = info->args[0]; RegLocation rl_src_obj = info->args[1]; // Object - known non-null RegLocation rl_src_offset = info->args[2]; // long low - rl_src_offset = NarrowRegLoc(rl_src_offset); // ignore high half in info->args[3] + rl_src_offset = NarrowRegLoc(rl_src_offset); // ignore high half in info->args[3] //TODO: do we really need this RegLocation rl_src_expected = info->args[4]; // int, long or Object // If is_long, high half is in info->args[5] RegLocation rl_src_new_value = info->args[is_long ? 6 : 5]; // int, long or Object // If is_long, high half is in info->args[7] RegLocation rl_dest = InlineTarget(info); // boolean place for result - // We have only 5 temporary registers available and actually only 4 if the InlineTarget - // above locked one of the temps. For a straightforward CAS64 we need 7 registers: - // r_ptr (1), new_value (2), expected(2) and ldrexd result (2). If neither expected nor - // new_value is in a non-temp core register we shall reload them in the ldrex/strex loop - // into the same temps, reducing the number of required temps down to 5. We shall work - // around the potentially locked temp by using LR for r_ptr, unconditionally. - // TODO: Pass information about the need for more temps to the stack frame generation - // code so that we can rely on being able to allocate enough temps. - DCHECK(!GetRegInfo(rs_rA64_LR)->IsTemp()); - MarkTemp(rs_rA64_LR); - FreeTemp(rs_rA64_LR); - LockTemp(rs_rA64_LR); - bool load_early = true; - if (is_long) { - RegStorage expected_reg = rl_src_expected.reg.IsPair() ? rl_src_expected.reg.GetLow() : - rl_src_expected.reg; - RegStorage new_val_reg = rl_src_new_value.reg.IsPair() ? rl_src_new_value.reg.GetLow() : - rl_src_new_value.reg; - bool expected_is_core_reg = rl_src_expected.location == kLocPhysReg && !expected_reg.IsFloat(); - bool new_value_is_core_reg = rl_src_new_value.location == kLocPhysReg && !new_val_reg.IsFloat(); - bool expected_is_good_reg = expected_is_core_reg && !IsTemp(expected_reg); - bool new_value_is_good_reg = new_value_is_core_reg && !IsTemp(new_val_reg); - - if (!expected_is_good_reg && !new_value_is_good_reg) { - // None of expected/new_value is non-temp reg, need to load both late - load_early = false; - // Make sure they are not in the temp regs and the load will not be skipped. - if (expected_is_core_reg) { - FlushRegWide(rl_src_expected.reg); - ClobberSReg(rl_src_expected.s_reg_low); - ClobberSReg(GetSRegHi(rl_src_expected.s_reg_low)); - rl_src_expected.location = kLocDalvikFrame; - } - if (new_value_is_core_reg) { - FlushRegWide(rl_src_new_value.reg); - ClobberSReg(rl_src_new_value.s_reg_low); - ClobberSReg(GetSRegHi(rl_src_new_value.s_reg_low)); - rl_src_new_value.location = kLocDalvikFrame; - } - } - } - - // Release store semantics, get the barrier out of the way. TODO: revisit - GenMemBarrier(kStoreLoad); - + // Load Object and offset RegLocation rl_object = LoadValue(rl_src_obj, kRefReg); + RegLocation rl_offset = LoadValue(rl_src_offset, kRefReg); + RegLocation rl_new_value; - if (!is_long) { - rl_new_value = LoadValue(rl_src_new_value); - } else if (load_early) { + RegLocation rl_expected; + if (is_long) { rl_new_value = LoadValueWide(rl_src_new_value, kCoreReg); + rl_expected = LoadValueWide(rl_src_expected, kCoreReg); + } else { + rl_new_value = LoadValue(rl_src_new_value, is_object ? kRefReg : kCoreReg); + rl_expected = LoadValue(rl_src_expected, is_object ? kRefReg : kCoreReg); } if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) { @@ -516,9 +468,7 @@ bool Arm64Mir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) { MarkGCCard(rl_new_value.reg, rl_object.reg); } - RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg); - - RegStorage r_ptr = rs_rA64_LR; + RegStorage r_ptr = AllocTempRef(); OpRegRegReg(kOpAdd, r_ptr, rl_object.reg, rl_offset.reg); // Free now unneeded rl_object and rl_offset to give more temps. @@ -527,77 +477,40 @@ bool Arm64Mir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) { ClobberSReg(rl_offset.s_reg_low); FreeTemp(rl_offset.reg); - RegLocation rl_expected; - if (!is_long) { - rl_expected = LoadValue(rl_src_expected); - } else if (load_early) { - rl_expected = LoadValueWide(rl_src_expected, kCoreReg); - } else { - // NOTE: partially defined rl_expected & rl_new_value - but we just want the regs. - int low_reg = AllocTemp().GetReg(); - int high_reg = AllocTemp().GetReg(); - rl_new_value.reg = RegStorage(RegStorage::k64BitPair, low_reg, high_reg); - rl_expected = rl_new_value; - } - // do { // tmp = [r_ptr] - expected; // } while (tmp == 0 && failure([r_ptr] <- r_new_value)); // result = tmp != 0; - RegStorage r_tmp = AllocTemp(); - LIR* target = NewLIR0(kPseudoTargetLabel); - + RegStorage r_tmp; if (is_long) { - RegStorage r_tmp_high = AllocTemp(); - if (!load_early) { - LoadValueDirectWide(rl_src_expected, rl_expected.reg); - } - NewLIR3(kA64Ldxr2rX, r_tmp.GetReg(), r_tmp_high.GetReg(), r_ptr.GetReg()); - OpRegReg(kOpSub, r_tmp, rl_expected.reg.GetLow()); - OpRegReg(kOpSub, r_tmp_high, rl_expected.reg.GetHigh()); - if (!load_early) { - LoadValueDirectWide(rl_src_new_value, rl_new_value.reg); - } - - LIR* branch1 = OpCmpImmBranch(kCondNe, r_tmp, 0, NULL); - LIR* branch2 = OpCmpImmBranch(kCondNe, r_tmp_high, 0, NULL); - NewLIR4(WIDE(kA64Stxr3wrX) /* eq */, r_tmp.GetReg(), rl_new_value.reg.GetReg(), - rl_new_value.reg.GetHighReg(), r_ptr.GetReg()); - LIR* target2 = NewLIR0(kPseudoTargetLabel); - branch1->target = target2; - branch2->target = target2; - FreeTemp(r_tmp_high); // Now unneeded - + r_tmp = AllocTempWide(); + } else if (is_object) { + r_tmp = AllocTempRef(); } else { - NewLIR3(kA64Ldxr2rX, r_tmp.GetReg(), r_ptr.GetReg(), 0); - OpRegReg(kOpSub, r_tmp, rl_expected.reg); - DCHECK(last_lir_insn_->u.m.def_mask->HasBit(ResourceMask::kCCode)); - // OpIT(kCondEq, "T"); - NewLIR4(kA64Stxr3wrX /* eq */, r_tmp.GetReg(), rl_new_value.reg.GetReg(), r_ptr.GetReg(), 0); + r_tmp = AllocTemp(); } - // Still one conditional left from OpIT(kCondEq, "T") from either branch - OpRegImm(kOpCmp /* eq */, r_tmp, 1); - OpCondBranch(kCondEq, target); + LIR* loop = NewLIR0(kPseudoTargetLabel); + NewLIR2(kA64Ldaxr2rX | wide, r_tmp.GetReg(), r_ptr.GetReg()); + OpRegReg(kOpCmp, r_tmp, rl_expected.reg); + DCHECK(last_lir_insn_->u.m.def_mask->HasBit(ResourceMask::kCCode)); + LIR* early_exit = OpCondBranch(kCondNe, NULL); - if (!load_early) { - FreeTemp(rl_expected.reg); // Now unneeded. - } + NewLIR3(kA64Stlxr3wrX | wide, As32BitReg(r_tmp).GetReg(), rl_new_value.reg.GetReg(), r_ptr.GetReg()); + NewLIR3(kA64Cmp3RdT, As32BitReg(r_tmp).GetReg(), 0, ENCODE_NO_SHIFT); + DCHECK(last_lir_insn_->u.m.def_mask->HasBit(ResourceMask::kCCode)); + OpCondBranch(kCondNe, loop); - // result := (tmp1 != 0) ? 0 : 1; RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); - OpRegRegImm(kOpRsub, rl_result.reg, r_tmp, 1); - DCHECK(last_lir_insn_->u.m.def_mask->HasBit(ResourceMask::kCCode)); - // OpIT(kCondUlt, ""); - LoadConstant(rl_result.reg, 0); /* cc */ + LIR* exit = NewLIR4(kA64Csinc4rrrc, rl_result.reg.GetReg(), rwzr, rwzr, kArmCondNe); + early_exit->target = exit; + FreeTemp(r_tmp); // Now unneeded. + FreeTemp(r_ptr); // Now unneeded. StoreValue(rl_dest, rl_result); - // Now, restore lr to its non-temp status. - Clobber(rs_rA64_LR); - UnmarkTemp(rs_rA64_LR); return true; } diff --git a/compiler/dex/quick/arm64/utility_arm64.cc b/compiler/dex/quick/arm64/utility_arm64.cc index bb8b7e3..71e9e95 100644 --- a/compiler/dex/quick/arm64/utility_arm64.cc +++ b/compiler/dex/quick/arm64/utility_arm64.cc @@ -387,11 +387,11 @@ LIR* Arm64Mir2Lir::OpRegRegShift(OpKind op, RegStorage r_dest_src1, RegStorage r case kOpRev: DCHECK_EQ(shift, 0); // Binary, but rm is encoded twice. - return NewLIR3(kA64Rev2rr | wide, r_dest_src1.GetReg(), r_src2.GetReg(), r_src2.GetReg()); + return NewLIR2(kA64Rev2rr | wide, r_dest_src1.GetReg(), r_src2.GetReg()); break; case kOpRevsh: // Binary, but rm is encoded twice. - return NewLIR3(kA64Rev162rr | wide, r_dest_src1.GetReg(), r_src2.GetReg(), r_src2.GetReg()); + return NewLIR2(kA64Rev162rr | wide, r_dest_src1.GetReg(), r_src2.GetReg()); break; case kOp2Byte: DCHECK_EQ(shift, ENCODE_NO_SHIFT); diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index 35a98e6..2af847c 100644 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -1328,6 +1328,9 @@ bool Mir2Lir::GenInlinedStringIsEmptyOrLength(CallInfo* info, bool is_empty) { RegStorage t_reg = AllocTemp(); OpRegReg(kOpNeg, t_reg, rl_result.reg); OpRegRegReg(kOpAdc, rl_result.reg, rl_result.reg, t_reg); + } else if (cu_->instruction_set == kArm64) { + OpRegImm(kOpSub, rl_result.reg, 1); + OpRegRegImm(kOpLsr, rl_result.reg, rl_result.reg, 31); } else { DCHECK(cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64); OpRegImm(kOpSub, rl_result.reg, 1); @@ -1348,6 +1351,11 @@ bool Mir2Lir::GenInlinedReverseBytes(CallInfo* info, OpSize size) { RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); if (size == k64) { RegLocation rl_i = LoadValueWide(rl_src_i, kCoreReg); + if (cu_->instruction_set == kArm64) { + OpRegReg(kOpRev, rl_result.reg, rl_i.reg); + StoreValueWide(rl_dest, rl_result); + return true; + } RegStorage r_i_low = rl_i.reg.GetLow(); if (rl_i.reg.GetLowReg() == rl_result.reg.GetLowReg()) { // First REV shall clobber rl_result.reg.GetReg(), save the value in a temp for the second REV. @@ -1446,8 +1454,15 @@ bool Mir2Lir::GenInlinedAbsDouble(CallInfo* info) { rl_src = LoadValueWide(rl_src, kCoreReg); RegLocation rl_dest = InlineTargetWide(info); RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); - OpRegCopyWide(rl_result.reg, rl_src.reg); - OpRegImm(kOpAnd, rl_result.reg.GetHigh(), 0x7fffffff); + + if (cu_->instruction_set == kArm64) { + // TODO - Can ecode ? UBXF otherwise + // OpRegRegImm(kOpAnd, rl_result.reg, 0x7fffffffffffffff); + return false; + } else { + OpRegCopyWide(rl_result.reg, rl_src.reg); + OpRegImm(kOpAnd, rl_result.reg.GetHigh(), 0x7fffffff); + } StoreValueWide(rl_dest, rl_result); return true; } diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index b051d6c..ca4d0e4 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -952,7 +952,7 @@ class Mir2Lir : public Backend { bool GenInlinedStringIsEmptyOrLength(CallInfo* info, bool is_empty); bool GenInlinedReverseBytes(CallInfo* info, OpSize size); bool GenInlinedAbsInt(CallInfo* info); - bool GenInlinedAbsLong(CallInfo* info); + virtual bool GenInlinedAbsLong(CallInfo* info); bool GenInlinedAbsFloat(CallInfo* info); bool GenInlinedAbsDouble(CallInfo* info); bool GenInlinedFloatCvt(CallInfo* info); diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S index 6031e25..dd8e221 100644 --- a/runtime/arch/arm64/quick_entrypoints_arm64.S +++ b/runtime/arch/arm64/quick_entrypoints_arm64.S @@ -1650,7 +1650,102 @@ ENTRY art_quick_deoptimize END art_quick_deoptimize -UNIMPLEMENTED art_quick_indexof + /* + * String's indexOf. + * + * TODO: Not very optimized. + * On entry: + * x0: string object (known non-null) + * w1: char to match (known <= 0xFFFF) + * w2: Starting offset in string data + */ +ENTRY art_quick_indexof + ldr w3, [x0, #STRING_COUNT_OFFSET] + ldr w4, [x0, #STRING_OFFSET_OFFSET] + ldr w0, [x0, #STRING_VALUE_OFFSET] // x0 ? + + /* Clamp start to [0..count] */ + cmp w2, #0 + csel w2, wzr, w2, lt + cmp w2, w3 + csel w2, w3, w2, gt + + /* Build a pointer to the start of the string data */ + add x0, x0, #STRING_DATA_OFFSET + add x0, x0, x4, lsl #1 + + /* Save a copy to compute result */ + mov x5, x0 + + /* Build pointer to start of data to compare and pre-bias */ + add x0, x0, x2, lsl #1 + sub x0, x0, #2 + + /* Compute iteration count */ + sub w2, w3, w2 + + /* + * At this point we have: + * x0: start of the data to test + * w1: char to compare + * w2: iteration count + * x5: original start of string data + */ + + subs w2, w2, #4 + b.lt .Lindexof_remainder + +.Lindexof_loop4: + ldrh w6, [x0, #2]! + ldrh w7, [x0, #2]! + ldrh w8, [x0, #2]! + ldrh w9, [x0, #2]! + cmp w6, w1 + b.eq .Lmatch_0 + cmp w7, w1 + b.eq .Lmatch_1 + cmp w8, w1 + b.eq .Lmatch_2 + cmp w9, w1 + b.eq .Lmatch_3 + subs w2, w2, #4 + b.ge .Lindexof_loop4 + +.Lindexof_remainder: + adds w2, w2, #4 + b.eq .Lindexof_nomatch + +.Lindexof_loop1: + ldrh w6, [x0, #2]! + cmp w6, w1 + b.eq .Lmatch_3 + subs w2, w2, #1 + b.ne .Lindexof_loop1 + +.Lindexof_nomatch: + mov x0, #-1 + ret + +.Lmatch_0: + sub x0, x0, #6 + sub x0, x0, x5 + asr x0, x0, #1 + ret +.Lmatch_1: + sub x0, x0, #4 + sub x0, x0, x5 + asr x0, x0, #1 + ret +.Lmatch_2: + sub x0, x0, #2 + sub x0, x0, x5 + asr x0, x0, #1 + ret +.Lmatch_3: + sub x0, x0, x5 + asr x0, x0, #1 + ret +END art_quick_indexof /* * String's compareTo. @@ -1698,6 +1793,7 @@ ENTRY art_quick_string_compareto add x2, x2, #STRING_DATA_OFFSET add x1, x1, #STRING_DATA_OFFSET + // TODO: Tune this value. // Check for long string, do memcmp16 for them. cmp w3, #28 // Constant from arm32. bgt .Ldo_memcmp16 |