summaryrefslogtreecommitdiffstats
path: root/compiler/dex
diff options
context:
space:
mode:
authorAndreas Gampe <agampe@google.com>2014-07-15 23:02:11 -0700
committerAndreas Gampe <agampe@google.com>2014-07-17 10:02:10 -0700
commit90969af6deb19b1dbe356d62fe68d8f5698d3d8f (patch)
tree6d144bcd219ce718ba9d17240eade0bec51f3400 /compiler/dex
parentaab012d6196bd29b3167963ec8acb0b9780672b2 (diff)
downloadart-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.h3
-rw-r--r--compiler/dex/quick/arm/int_arm.cc24
-rw-r--r--compiler/dex/quick/arm64/codegen_arm64.h9
-rw-r--r--compiler/dex/quick/arm64/int_arm64.cc212
-rw-r--r--compiler/dex/quick/gen_common.cc88
-rw-r--r--compiler/dex/quick/mips/codegen_mips.h3
-rw-r--r--compiler/dex/quick/mips/int_mips.cc12
-rw-r--r--compiler/dex/quick/mir_to_lir.h8
-rw-r--r--compiler/dex/quick/x86/codegen_x86.h6
-rwxr-xr-xcompiler/dex/quick/x86/int_x86.cc41
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.