diff options
author | Andreas Gampe <agampe@google.com> | 2014-07-15 23:02:11 -0700 |
---|---|---|
committer | Andreas Gampe <agampe@google.com> | 2014-07-17 10:02:10 -0700 |
commit | 90969af6deb19b1dbe356d62fe68d8f5698d3d8f (patch) | |
tree | 6d144bcd219ce718ba9d17240eade0bec51f3400 /compiler/dex | |
parent | aab012d6196bd29b3167963ec8acb0b9780672b2 (diff) | |
download | art-90969af6deb19b1dbe356d62fe68d8f5698d3d8f.tar.gz art-90969af6deb19b1dbe356d62fe68d8f5698d3d8f.tar.bz2 art-90969af6deb19b1dbe356d62fe68d8f5698d3d8f.zip |
ART: Refactor GenSelect, refactor gen_common accordingly
This adds a GenSelect method meant for selection of constants. The
general-purpose GenInstanceof code is refactored to take advantage of
this. This cleans up code and squashes a branch-over on ARM64 to a
cset.
Also add a slow-path for type initialization in GenInstanceof.
Change-Id: Ie4494858bb8c26d386cf2e628172b81bba911ae5
Diffstat (limited to 'compiler/dex')
-rw-r--r-- | compiler/dex/quick/arm/codegen_arm.h | 3 | ||||
-rw-r--r-- | compiler/dex/quick/arm/int_arm.cc | 24 | ||||
-rw-r--r-- | compiler/dex/quick/arm64/codegen_arm64.h | 9 | ||||
-rw-r--r-- | compiler/dex/quick/arm64/int_arm64.cc | 212 | ||||
-rw-r--r-- | compiler/dex/quick/gen_common.cc | 88 | ||||
-rw-r--r-- | compiler/dex/quick/mips/codegen_mips.h | 3 | ||||
-rw-r--r-- | compiler/dex/quick/mips/int_mips.cc | 12 | ||||
-rw-r--r-- | compiler/dex/quick/mir_to_lir.h | 8 | ||||
-rw-r--r-- | compiler/dex/quick/x86/codegen_x86.h | 6 | ||||
-rwxr-xr-x | compiler/dex/quick/x86/int_x86.cc | 41 |
10 files changed, 248 insertions, 158 deletions
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h index d4b0de7b4..23e8486d5 100644 --- a/compiler/dex/quick/arm/codegen_arm.h +++ b/compiler/dex/quick/arm/codegen_arm.h @@ -138,6 +138,9 @@ class ArmMir2Lir FINAL : public Mir2Lir { void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double); void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir); void GenSelect(BasicBlock* bb, MIR* mir); + void GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code, + int32_t true_val, int32_t false_val, RegStorage rs_dest, + int dest_reg_class) OVERRIDE; bool GenMemBarrier(MemBarrierKind barrier_kind); void GenMonitorEnter(int opt_flags, RegLocation rl_src); void GenMonitorExit(int opt_flags, RegLocation rl_src); diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc index 2fcc3a5ab..a85b74021 100644 --- a/compiler/dex/quick/arm/int_arm.cc +++ b/compiler/dex/quick/arm/int_arm.cc @@ -203,6 +203,30 @@ void ArmMir2Lir::GenFusedLongCmpImmBranch(BasicBlock* bb, RegLocation rl_src1, OpCmpImmBranch(ccode, low_reg, val_lo, taken); } +void ArmMir2Lir::GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code, + int32_t true_val, int32_t false_val, RegStorage rs_dest, + int dest_reg_class) { + // TODO: Generalize the IT below to accept more than one-instruction loads. + DCHECK(InexpensiveConstantInt(true_val)); + DCHECK(InexpensiveConstantInt(false_val)); + + if ((true_val == 0 && code == kCondEq) || + (false_val == 0 && code == kCondNe)) { + OpRegRegReg(kOpSub, rs_dest, left_op, right_op); + DCHECK(last_lir_insn_->u.m.def_mask->HasBit(ResourceMask::kCCode)); + LIR* it = OpIT(kCondNe, ""); + LoadConstant(rs_dest, code == kCondEq ? false_val : true_val); + OpEndIT(it); + return; + } + + OpRegReg(kOpCmp, left_op, right_op); // Same? + LIR* it = OpIT(code, "E"); // if-convert the test + LoadConstant(rs_dest, true_val); // .eq case - load true + LoadConstant(rs_dest, false_val); // .eq case - load true + OpEndIT(it); +} + void ArmMir2Lir::GenSelect(BasicBlock* bb, MIR* mir) { RegLocation rl_result; RegLocation rl_src = mir_graph_->GetSrc(mir, 0); diff --git a/compiler/dex/quick/arm64/codegen_arm64.h b/compiler/dex/quick/arm64/codegen_arm64.h index de976531c..da586b1e1 100644 --- a/compiler/dex/quick/arm64/codegen_arm64.h +++ b/compiler/dex/quick/arm64/codegen_arm64.h @@ -206,7 +206,14 @@ class Arm64Mir2Lir FINAL : public Mir2Lir { void GenFillArrayData(DexOffset table_offset, RegLocation rl_src); void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double); void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir); - void GenSelect(BasicBlock* bb, MIR* mir); + void GenSelect(BasicBlock* bb, MIR* mir) OVERRIDE; + void GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code, + int32_t true_val, int32_t false_val, RegStorage rs_dest, + int dest_reg_class) OVERRIDE; + // Helper used in the above two. + void GenSelect(int32_t left, int32_t right, ConditionCode code, RegStorage rs_dest, + int result_reg_class); + bool GenMemBarrier(MemBarrierKind barrier_kind); void GenMonitorEnter(int opt_flags, RegLocation rl_src); void GenMonitorExit(int opt_flags, RegLocation rl_src); diff --git a/compiler/dex/quick/arm64/int_arm64.cc b/compiler/dex/quick/arm64/int_arm64.cc index 6dc4a7ab5..a76d275cf 100644 --- a/compiler/dex/quick/arm64/int_arm64.cc +++ b/compiler/dex/quick/arm64/int_arm64.cc @@ -85,141 +85,129 @@ void Arm64Mir2Lir::GenShiftOpLong(Instruction::Code opcode, RegLocation rl_dest, StoreValueWide(rl_dest, rl_result); } -void Arm64Mir2Lir::GenSelect(BasicBlock* bb, MIR* mir) { - RegLocation rl_result; - RegLocation rl_src = mir_graph_->GetSrc(mir, 0); - RegLocation rl_dest = mir_graph_->GetDest(mir); - RegisterClass src_reg_class = rl_src.ref ? kRefReg : kCoreReg; - RegisterClass result_reg_class = rl_dest.ref ? kRefReg : kCoreReg; +static constexpr bool kUseDeltaEncodingInGenSelect = false; + +void Arm64Mir2Lir::GenSelect(int32_t true_val, int32_t false_val, ConditionCode ccode, + RegStorage rs_dest, int result_reg_class) { + if (false_val == 0 || // 0 is better as first operand. + true_val == 1 || // Potentially Csinc. + true_val == -1 || // Potentially Csinv. + true_val == false_val + 1) { // Potentially Csinc. + ccode = NegateComparison(ccode); + std::swap(true_val, false_val); + } - rl_src = LoadValue(rl_src, src_reg_class); - // rl_src may be aliased with rl_result/rl_dest, so do compare early. - OpRegImm(kOpCmp, rl_src.reg, 0); + ArmConditionCode code = ArmConditionEncoding(ccode); - ArmConditionCode code = ArmConditionEncoding(mir->meta.ccode); + int opcode; // The opcode. + RegStorage left_op = RegStorage::InvalidReg(); // The operands. + RegStorage right_op = RegStorage::InvalidReg(); // The operands. - // The kMirOpSelect has two variants, one for constants and one for moves. - bool is_wide = rl_dest.ref || rl_dest.wide; + bool is_wide = rs_dest.Is64Bit(); - if (mir->ssa_rep->num_uses == 1) { - uint32_t true_val = mir->dalvikInsn.vB; - uint32_t false_val = mir->dalvikInsn.vC; - - int opcode; // The opcode. - int left_op, right_op; // The operands. - bool rl_result_evaled = false; - - // Check some simple cases. - // TODO: Improve this. - int zero_reg = (is_wide ? rs_xzr : rs_wzr).GetReg(); - - if ((true_val == 0 && false_val == 1) || (true_val == 1 && false_val == 0)) { - // CSInc cheap based on wzr. - if (true_val == 1) { - // Negate. - code = ArmConditionEncoding(NegateComparison(mir->meta.ccode)); - } + RegStorage zero_reg = is_wide ? rs_xzr : rs_wzr; - left_op = right_op = zero_reg; - opcode = is_wide ? WIDE(kA64Csinc4rrrc) : kA64Csinc4rrrc; - } else if ((true_val == 0 && false_val == 0xFFFFFFFF) || - (true_val == 0xFFFFFFFF && false_val == 0)) { - // CSneg cheap based on wzr. - if (true_val == 0xFFFFFFFF) { - // Negate. - code = ArmConditionEncoding(NegateComparison(mir->meta.ccode)); - } - - left_op = right_op = zero_reg; - opcode = is_wide ? WIDE(kA64Csinv4rrrc) : kA64Csinv4rrrc; - } else if (true_val == 0 || false_val == 0) { - // Csel half cheap based on wzr. - rl_result = EvalLoc(rl_dest, result_reg_class, true); - rl_result_evaled = true; - if (false_val == 0) { - // Negate. - code = ArmConditionEncoding(NegateComparison(mir->meta.ccode)); - } - LoadConstantNoClobber(rl_result.reg, true_val == 0 ? false_val : true_val); - left_op = zero_reg; - right_op = rl_result.reg.GetReg(); - opcode = is_wide ? WIDE(kA64Csel4rrrc) : kA64Csel4rrrc; - } else if (true_val == 1 || false_val == 1) { - // CSInc half cheap based on wzr. - rl_result = EvalLoc(rl_dest, result_reg_class, true); - rl_result_evaled = true; - if (true_val == 1) { - // Negate. - code = ArmConditionEncoding(NegateComparison(mir->meta.ccode)); - } - LoadConstantNoClobber(rl_result.reg, true_val == 1 ? false_val : true_val); - left_op = rl_result.reg.GetReg(); - right_op = zero_reg; - opcode = is_wide ? WIDE(kA64Csinc4rrrc) : kA64Csinc4rrrc; - } else if (true_val == 0xFFFFFFFF || false_val == 0xFFFFFFFF) { - // CSneg half cheap based on wzr. - rl_result = EvalLoc(rl_dest, result_reg_class, true); - rl_result_evaled = true; - if (true_val == 0xFFFFFFFF) { - // Negate. - code = ArmConditionEncoding(NegateComparison(mir->meta.ccode)); - } - LoadConstantNoClobber(rl_result.reg, true_val == 0xFFFFFFFF ? false_val : true_val); - left_op = rl_result.reg.GetReg(); - right_op = zero_reg; - opcode = is_wide ? WIDE(kA64Csinv4rrrc) : kA64Csinv4rrrc; - } else if ((true_val + 1 == false_val) || (false_val + 1 == true_val)) { - // Load a constant and use CSinc. Use rl_result. - if (false_val + 1 == true_val) { - // Negate. - code = ArmConditionEncoding(NegateComparison(mir->meta.ccode)); - true_val = false_val; + if (true_val == 0) { + left_op = zero_reg; + } else { + left_op = rs_dest; + LoadConstantNoClobber(rs_dest, true_val); + } + if (false_val == 1) { + right_op = zero_reg; + opcode = kA64Csinc4rrrc; + } else if (false_val == -1) { + right_op = zero_reg; + opcode = kA64Csinv4rrrc; + } else if (false_val == true_val + 1) { + right_op = left_op; + opcode = kA64Csinc4rrrc; + } else if (false_val == -true_val) { + right_op = left_op; + opcode = kA64Csneg4rrrc; + } else if (false_val == ~true_val) { + right_op = left_op; + opcode = kA64Csinv4rrrc; + } else if (true_val == 0) { + // left_op is zero_reg. + right_op = rs_dest; + LoadConstantNoClobber(rs_dest, false_val); + opcode = kA64Csel4rrrc; + } else { + // Generic case. + RegStorage t_reg2 = AllocTypedTemp(false, result_reg_class); + if (is_wide) { + if (t_reg2.Is32Bit()) { + t_reg2 = As64BitReg(t_reg2); } - - rl_result = EvalLoc(rl_dest, result_reg_class, true); - rl_result_evaled = true; - LoadConstantNoClobber(rl_result.reg, true_val); - left_op = right_op = rl_result.reg.GetReg(); - opcode = is_wide ? WIDE(kA64Csinc4rrrc) : kA64Csinc4rrrc; } else { - // Csel. The rest. Use rl_result and a temp. - // TODO: To minimize the constants being loaded, check whether one can be inexpensively - // loaded as n - 1 or ~n. - rl_result = EvalLoc(rl_dest, result_reg_class, true); - rl_result_evaled = true; - LoadConstantNoClobber(rl_result.reg, true_val); - RegStorage t_reg2 = AllocTypedTemp(false, result_reg_class); - if (rl_dest.wide) { - if (t_reg2.Is32Bit()) { - t_reg2 = As64BitReg(t_reg2); - } + if (t_reg2.Is64Bit()) { + t_reg2 = As32BitReg(t_reg2); } - LoadConstantNoClobber(t_reg2, false_val); + } - // Use csel. - left_op = rl_result.reg.GetReg(); - right_op = t_reg2.GetReg(); - opcode = is_wide ? WIDE(kA64Csel4rrrc) : kA64Csel4rrrc; + if (kUseDeltaEncodingInGenSelect) { + int32_t delta = false_val - true_val; + uint32_t abs_val = delta < 0 ? -delta : delta; + + if (abs_val < 0x1000) { // TODO: Replace with InexpensiveConstant with opcode. + // Can encode as immediate to an add. + right_op = t_reg2; + OpRegRegImm(kOpAdd, t_reg2, left_op, delta); + } } - if (!rl_result_evaled) { - rl_result = EvalLoc(rl_dest, result_reg_class, true); + // Load as constant. + if (!right_op.Valid()) { + LoadConstantNoClobber(t_reg2, false_val); + right_op = t_reg2; } - NewLIR4(opcode, rl_result.reg.GetReg(), left_op, right_op, code); + opcode = kA64Csel4rrrc; + } + + DCHECK(left_op.Valid() && right_op.Valid()); + NewLIR4(is_wide ? WIDE(opcode) : opcode, rs_dest.GetReg(), left_op.GetReg(), right_op.GetReg(), + code); +} + +void Arm64Mir2Lir::GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code, + int32_t true_val, int32_t false_val, RegStorage rs_dest, + int dest_reg_class) { + DCHECK(rs_dest.Valid()); + OpRegReg(kOpCmp, left_op, right_op); + GenSelect(true_val, false_val, code, rs_dest, dest_reg_class); +} + +void Arm64Mir2Lir::GenSelect(BasicBlock* bb, MIR* mir) { + RegLocation rl_src = mir_graph_->GetSrc(mir, 0); + rl_src = LoadValue(rl_src, rl_src.ref ? kRefReg : kCoreReg); + // rl_src may be aliased with rl_result/rl_dest, so do compare early. + OpRegImm(kOpCmp, rl_src.reg, 0); + + RegLocation rl_dest = mir_graph_->GetDest(mir); + + // The kMirOpSelect has two variants, one for constants and one for moves. + if (mir->ssa_rep->num_uses == 1) { + RegLocation rl_result = EvalLoc(rl_dest, rl_dest.ref ? kRefReg : kCoreReg, true); + GenSelect(mir->dalvikInsn.vB, mir->dalvikInsn.vC, mir->meta.ccode, rl_result.reg, + rl_dest.ref ? kRefReg : kCoreReg); + StoreValue(rl_dest, rl_result); } else { RegLocation rl_true = mir_graph_->reg_location_[mir->ssa_rep->uses[1]]; RegLocation rl_false = mir_graph_->reg_location_[mir->ssa_rep->uses[2]]; + RegisterClass result_reg_class = rl_dest.ref ? kRefReg : kCoreReg; rl_true = LoadValue(rl_true, result_reg_class); rl_false = LoadValue(rl_false, result_reg_class); - rl_result = EvalLoc(rl_dest, result_reg_class, true); + RegLocation rl_result = EvalLoc(rl_dest, result_reg_class, true); + bool is_wide = rl_dest.ref || rl_dest.wide; int opcode = is_wide ? WIDE(kA64Csel4rrrc) : kA64Csel4rrrc; NewLIR4(opcode, rl_result.reg.GetReg(), - rl_true.reg.GetReg(), rl_false.reg.GetReg(), code); + rl_true.reg.GetReg(), rl_false.reg.GetReg(), ArmConditionEncoding(mir->meta.ccode)); + StoreValue(rl_dest, rl_result); } - StoreValue(rl_dest, rl_result); } void Arm64Mir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) { diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc index 1fc0cff67..bea1eb880 100644 --- a/compiler/dex/quick/gen_common.cc +++ b/compiler/dex/quick/gen_common.cc @@ -1167,7 +1167,6 @@ void Mir2Lir::GenInstanceofFinal(bool use_declaring_class, uint32_t type_idx, Re LoadRefDisp(check_class, offset_of_type, check_class, kNotVolatile); } - LIR* ne_branchover = NULL; // FIXME: what should we be comparing here? compressed or decompressed references? if (cu_->instruction_set == kThumb2) { OpRegReg(kOpCmp, check_class, object_class); // Same? @@ -1175,14 +1174,10 @@ void Mir2Lir::GenInstanceofFinal(bool use_declaring_class, uint32_t type_idx, Re LoadConstant(result_reg, 1); // .eq case - load true OpEndIT(it); } else { - ne_branchover = OpCmpBranch(kCondNe, check_class, object_class, NULL); - LoadConstant(result_reg, 1); // eq case - load true + GenSelectConst32(check_class, object_class, kCondEq, 1, 0, result_reg, kCoreReg); } LIR* target = NewLIR0(kPseudoTargetLabel); null_branchover->target = target; - if (ne_branchover != NULL) { - ne_branchover->target = target; - } FreeTemp(object_class); FreeTemp(check_class); if (IsTemp(result_reg)) { @@ -1223,27 +1218,54 @@ void Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_know LoadRefDisp(method_reg, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), class_reg, kNotVolatile); } else { + if (can_assume_type_is_in_dex_cache) { + // Conditionally, as in the other case we will also load it. + LoadValueDirectFixed(rl_src, TargetReg(kArg0, kRef)); // kArg0 <= ref + } + // Load dex cache entry into class_reg (kArg2) - LoadValueDirectFixed(rl_src, TargetReg(kArg0, kRef)); // kArg0 <= ref LoadRefDisp(method_reg, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), class_reg, kNotVolatile); int32_t offset_of_type = ClassArray::OffsetOfElement(type_idx).Int32Value(); LoadRefDisp(class_reg, offset_of_type, class_reg, kNotVolatile); if (!can_assume_type_is_in_dex_cache) { - // Need to test presence of type in dex cache at runtime - LIR* hop_branch = OpCmpImmBranch(kCondNe, class_reg, 0, NULL); - // Not resolved - // Call out to helper, which will return resolved type in kRet0 - if (cu_->target64) { - CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(8, pInitializeType), type_idx, true); - } else { - CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(4, pInitializeType), type_idx, true); - } - OpRegCopy(TargetReg(kArg2, kRef), TargetReg(kRet0, kRef)); // Align usage with fast path - LoadValueDirectFixed(rl_src, TargetReg(kArg0, kRef)); /* reload Ref */ - // Rejoin code paths - LIR* hop_target = NewLIR0(kPseudoTargetLabel); - hop_branch->target = hop_target; + LIR* slow_path_branch = OpCmpImmBranch(kCondEq, class_reg, 0, NULL); + LIR* slow_path_target = NewLIR0(kPseudoTargetLabel); + + // Should load value here. + LoadValueDirectFixed(rl_src, TargetReg(kArg0, kRef)); // kArg0 <= ref + + class InitTypeSlowPath : public Mir2Lir::LIRSlowPath { + public: + InitTypeSlowPath(Mir2Lir* m2l, LIR* branch, LIR* cont, uint32_t type_idx, + RegLocation rl_src) + : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch, cont), type_idx_(type_idx), + rl_src_(rl_src) { + } + + void Compile() OVERRIDE { + GenerateTargetLabel(); + + if (cu_->target64) { + m2l_->CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(8, pInitializeType), type_idx_, + true); + } else { + m2l_->CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(4, pInitializeType), type_idx_, + true); + } + m2l_->OpRegCopy(m2l_->TargetReg(kArg2, kRef), + m2l_->TargetReg(kRet0, kRef)); // Align usage with fast path + + m2l_->OpUnconditionalBranch(cont_); + } + + private: + uint32_t type_idx_; + RegLocation rl_src_; + }; + + AddSlowPath(new (arena_) InitTypeSlowPath(this, slow_path_branch, slow_path_target, + type_idx, rl_src)); } } /* kArg0 is ref, kArg2 is class. If ref==null, use directly as bool result */ @@ -1262,17 +1284,8 @@ void Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_know LIR* branchover = NULL; if (type_known_final) { // rl_result == ref == null == 0. - if (cu_->instruction_set == kThumb2) { - OpRegReg(kOpCmp, TargetReg(kArg1, kRef), TargetReg(kArg2, kRef)); // Same? - LIR* it = OpIT(kCondEq, "E"); // if-convert the test - LoadConstant(rl_result.reg, 1); // .eq case - load true - LoadConstant(rl_result.reg, 0); // .ne case - load false - OpEndIT(it); - } else { - LoadConstant(rl_result.reg, 0); // ne case - load false - branchover = OpCmpBranch(kCondNe, TargetReg(kArg1, kRef), TargetReg(kArg2, kRef), NULL); - LoadConstant(rl_result.reg, 1); // eq case - load true - } + GenSelectConst32(TargetReg(kArg1, kRef), TargetReg(kArg2, kRef), kCondEq, 1, 0, rl_result.reg, + kCoreReg); } else { if (cu_->instruction_set == kThumb2) { RegStorage r_tgt = cu_->target64 ? @@ -1297,12 +1310,13 @@ void Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_know LoadConstant(rl_result.reg, 1); // assume true branchover = OpCmpBranch(kCondEq, TargetReg(kArg1, kRef), TargetReg(kArg2, kRef), NULL); } - RegStorage r_tgt = cu_->target64 ? - LoadHelper(QUICK_ENTRYPOINT_OFFSET(8, pInstanceofNonTrivial)) : - LoadHelper(QUICK_ENTRYPOINT_OFFSET(4, pInstanceofNonTrivial)); + OpRegCopy(TargetReg(kArg0, kRef), TargetReg(kArg2, kRef)); // .ne case - arg0 <= class - OpReg(kOpBlx, r_tgt); // .ne case: helper(class, ref->class) - FreeTemp(r_tgt); + if (cu_->target64) { + CallRuntimeHelper(QUICK_ENTRYPOINT_OFFSET(8, pInstanceofNonTrivial), false); + } else { + CallRuntimeHelper(QUICK_ENTRYPOINT_OFFSET(4, pInstanceofNonTrivial), false); + } } } // TODO: only clobber when type isn't final? diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h index 2c33377a2..4ac689207 100644 --- a/compiler/dex/quick/mips/codegen_mips.h +++ b/compiler/dex/quick/mips/codegen_mips.h @@ -136,6 +136,9 @@ class MipsMir2Lir FINAL : public Mir2Lir { void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double); void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir); void GenSelect(BasicBlock* bb, MIR* mir); + void GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code, + int32_t true_val, int32_t false_val, RegStorage rs_dest, + int dest_reg_class) OVERRIDE; bool GenMemBarrier(MemBarrierKind barrier_kind); void GenMoveException(RegLocation rl_dest); void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result, int lit, diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc index c3a4c1714..1f8f9ece8 100644 --- a/compiler/dex/quick/mips/int_mips.cc +++ b/compiler/dex/quick/mips/int_mips.cc @@ -215,6 +215,18 @@ void MipsMir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) { } } +void MipsMir2Lir::GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code, + int32_t true_val, int32_t false_val, RegStorage rs_dest, + int dest_reg_class) { + // Implement as a branch-over. + // TODO: Conditional move? + LoadConstant(rs_dest, false_val); // Favors false. + LIR* ne_branchover = OpCmpBranch(code, left_op, right_op, NULL); + LoadConstant(rs_dest, true_val); + LIR* target_label = NewLIR0(kPseudoTargetLabel); + ne_branchover->target = target_label; +} + void MipsMir2Lir::GenSelect(BasicBlock* bb, MIR* mir) { UNIMPLEMENTED(FATAL) << "Need codegen for select"; } diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index c68ad6be4..2aa158f0d 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -1380,6 +1380,14 @@ class Mir2Lir : public Backend { virtual void GenSelect(BasicBlock* bb, MIR* mir) = 0; /** + * @brief Generates code to select one of the given constants depending on the given opcode. + * @note Will neither call EvalLoc nor StoreValue for rl_dest. + */ + virtual void GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code, + int32_t true_val, int32_t false_val, RegStorage rs_dest, + int dest_reg_class) = 0; + + /** * @brief Used to generate a memory barrier in an architecture specific way. * @details The last generated LIR will be considered for use as barrier. Namely, * if the last LIR can be updated in a way where it will serve the semantics of diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h index f4fa1b4b1..0857bd6b8 100644 --- a/compiler/dex/quick/x86/codegen_x86.h +++ b/compiler/dex/quick/x86/codegen_x86.h @@ -203,6 +203,12 @@ class X86Mir2Lir : public Mir2Lir { void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double); void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir); void GenSelect(BasicBlock* bb, MIR* mir); + void GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code, + int32_t true_val, int32_t false_val, RegStorage rs_dest, + int dest_reg_class) OVERRIDE; + // Optimized version for selection of 0 and 1. + void GenSelectConst01(RegStorage left_op, RegStorage right_op, ConditionCode code, bool true_val, + RegStorage rs_dest); bool GenMemBarrier(MemBarrierKind barrier_kind); void GenMoveException(RegLocation rl_dest); void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result, int lit, diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc index 2f27482e5..30b87babd 100755 --- a/compiler/dex/quick/x86/int_x86.cc +++ b/compiler/dex/quick/x86/int_x86.cc @@ -206,6 +206,38 @@ void X86Mir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) { } } +// Set rs_dest to 0 or 1 depending on the comparison between left_op and right_op. +// rs_dest := (left_op <code> right_op) ? [true_val] : [!true_val] +// +// Implemented as: +// true_val = true => rs_dest := 0; +// rs_dest := (left_op <code> right_op) ? 1 : rs_dest; +// true_val = false => rs_dest := 0; +// rs_dest := (left_op <~code> right_op) ? 1 : rs_dest; +void X86Mir2Lir::GenSelectConst01(RegStorage left_op, RegStorage right_op, ConditionCode code, + bool true_val, RegStorage rs_dest) { + LoadConstant(rs_dest, 0); + OpRegReg(kOpCmp, left_op, right_op); + // Set the low byte of the result to 0 or 1 from the compare condition code. + NewLIR2(kX86Set8R, rs_dest.GetReg(), + X86ConditionEncoding(true_val ? code : FlipComparisonOrder(code))); +} + +void X86Mir2Lir::GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code, + int32_t true_val, int32_t false_val, RegStorage rs_dest, + int dest_reg_class) { + if ((true_val == 0 && false_val == 1) || (true_val == 1 && false_val == 0)) { + // Can we use Setcc? + if (rs_dest.Is64Bit() || rs_dest.GetRegNum() < 4) { + GenSelectConst01(left_op, right_op, code, true_val == 1, rs_dest); + return; + } + } + + // TODO: Refactor the code below to make this more general. + UNIMPLEMENTED(FATAL) << "General GenSelectConst32 not implemented for x86."; +} + void X86Mir2Lir::GenSelect(BasicBlock* bb, MIR* mir) { RegLocation rl_result; RegLocation rl_src = mir_graph_->GetSrc(mir, 0); @@ -2459,9 +2491,6 @@ void X86Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_k OpRegCopy(rl_result.reg, ref_reg); } - // For 32-bit, SETcc only works with EAX..EDX. - DCHECK_LT(rl_result.reg.GetRegNum(), 4); - // Is the class NULL? LIR* branch1 = OpCmpImmBranch(kCondEq, ref_reg, 0, NULL); @@ -2473,11 +2502,7 @@ void X86Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_k /* kArg0 is ref, kArg1 is ref->klass_, kArg2 is class. */ LIR* branchover = nullptr; if (type_known_final) { - // Ensure top 3 bytes of result are 0. - LoadConstant(rl_result.reg, 0); - OpRegReg(kOpCmp, ref_class_reg, class_reg); - // Set the low byte of the result to 0 or 1 from the compare condition code. - NewLIR2(kX86Set8R, rl_result.reg.GetReg(), kX86CondEq); + GenSelectConst32(ref_class_reg, class_reg, kCondEq, 1, 0, rl_result.reg, kCoreReg); } else { if (!type_known_abstract) { LoadConstant(rl_result.reg, 1); // Assume result succeeds. |