OSDN Git Service

AArch64: Add support for inlined methods
authorSerban Constantinescu <serban.constantinescu@arm.com>
Wed, 11 Jun 2014 15:43:35 +0000 (16:43 +0100)
committerbuzbee <buzbee@google.com>
Thu, 12 Jun 2014 21:50:28 +0000 (14:50 -0700)
This patch adds support for Arm64 inlined methods.

Change-Id: Ic6aeed6d2d32f65cd1e63cf482f83cdcf958798a

compiler/dex/quick/arm64/arm64_lir.h
compiler/dex/quick/arm64/assemble_arm64.cc
compiler/dex/quick/arm64/codegen_arm64.h
compiler/dex/quick/arm64/int_arm64.cc
compiler/dex/quick/arm64/utility_arm64.cc
compiler/dex/quick/gen_invoke.cc
compiler/dex/quick/mir_to_lir.h
runtime/arch/arm64/quick_entrypoints_arm64.S

index e15ccb4..c1ce03d 100644 (file)
@@ -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].
index fcaaba5..2c4f262 100644 (file)
@@ -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";
index 8ecc393..bf09b86 100644 (file)
@@ -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);
index a18cc82..8112c2e 100644 (file)
@@ -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;
 }
 
index bb8b7e3..71e9e95 100644 (file)
@@ -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);
index 35a98e6..2af847c 100644 (file)
@@ -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;
 }
index b051d6c..ca4d0e4 100644 (file)
@@ -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);
index 6031e25..dd8e221 100644 (file)
@@ -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