Add OpEndIT() for marking the end of OpIT blocks
In ARM we need to prevent code motion to the inside of an
IT block. This was done using a GenBarrier() to mark the end, but
it wasn't obvious that this is what was happening. This CL adds
an explicit OpEndIT() that takes the LIR of the OpIT for future
checks.
Bug: 13751744
Change-Id: If41d2adea1f43f11ebb3b72906bd308252ce3d01
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index 8c9f8ea..d0d0e6b 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -81,8 +81,9 @@
NewLIR2(kThumb2LdmiaWB, r_base.GetReg(), (1 << r_key.GetReg()) | (1 << r_disp.GetReg()));
OpRegReg(kOpCmp, r_key, rl_src.reg);
// Go if match. NOTE: No instruction set switch here - must stay Thumb2
- OpIT(kCondEq, "");
+ LIR* it = OpIT(kCondEq, "");
LIR* switch_branch = NewLIR1(kThumb2AddPCR, r_disp.GetReg());
+ OpEndIT(it);
tab_rec->anchor = switch_branch;
// Needs to use setflags encoding here
OpRegRegImm(kOpSub, r_idx, r_idx, 1); // For value == 1, this should set flags.
@@ -222,14 +223,16 @@
NewLIR3(kThumb2Ldrex, r1, r0, mirror::Object::MonitorOffset().Int32Value() >> 2);
MarkPossibleNullPointerException(opt_flags);
OpRegImm(kOpCmp, rs_r1, 0);
- OpIT(kCondEq, "");
+ LIR* it = OpIT(kCondEq, "");
NewLIR4(kThumb2Strex/*eq*/, r1, r2, r0, mirror::Object::MonitorOffset().Int32Value() >> 2);
+ OpEndIT(it);
OpRegImm(kOpCmp, rs_r1, 0);
- OpIT(kCondNe, "T");
+ it = OpIT(kCondNe, "T");
// Go expensive route - artLockObjectFromCode(self, obj);
LoadWordDisp/*ne*/(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pLockObject).Int32Value(), rs_rARM_LR);
ClobberCallerSave();
LIR* call_inst = OpReg(kOpBlx/*ne*/, rs_rARM_LR);
+ OpEndIT(it);
MarkSafepointPC(call_inst);
GenMemBarrier(kLoadLoad);
}
@@ -287,13 +290,14 @@
LoadConstantNoClobber(rs_r3, 0);
// Is lock unheld on lock or held by us (==thread_id) on unlock?
OpRegReg(kOpCmp, rs_r1, rs_r2);
- OpIT(kCondEq, "EE");
+ LIR* it = OpIT(kCondEq, "EE");
StoreWordDisp/*eq*/(rs_r0, mirror::Object::MonitorOffset().Int32Value(), rs_r3);
// Go expensive route - UnlockObjectFromCode(obj);
LoadWordDisp/*ne*/(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pUnlockObject).Int32Value(),
rs_rARM_LR);
ClobberCallerSave();
LIR* call_inst = OpReg(kOpBlx/*ne*/, rs_rARM_LR);
+ OpEndIT(it);
MarkSafepointPC(call_inst);
GenMemBarrier(kStoreLoad);
}
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index 0ad2b70..13fa635 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -158,6 +158,7 @@
LIR* OpDecAndBranch(ConditionCode c_code, RegStorage reg, LIR* target);
LIR* OpFpRegCopy(RegStorage r_dest, RegStorage r_src);
LIR* OpIT(ConditionCode cond, const char* guide);
+ void OpEndIT(LIR* it);
LIR* OpMem(OpKind op, RegStorage r_base, int disp);
LIR* OpPcRelLoad(RegStorage reg, LIR* target);
LIR* OpReg(OpKind op, RegStorage r_dest_src);
diff --git a/compiler/dex/quick/arm/fp_arm.cc b/compiler/dex/quick/arm/fp_arm.cc
index 07a13ce..d72f596 100644
--- a/compiler/dex/quick/arm/fp_arm.cc
+++ b/compiler/dex/quick/arm/fp_arm.cc
@@ -314,14 +314,14 @@
DCHECK(!ARM_FPREG(rl_result.reg.GetReg()));
NewLIR0(kThumb2Fmstat);
- OpIT((default_result == -1) ? kCondGt : kCondMi, "");
+ LIR* it = OpIT((default_result == -1) ? kCondGt : kCondMi, "");
NewLIR2(kThumb2MovI8M, rl_result.reg.GetReg(),
ModifiedImmediate(-default_result)); // Must not alter ccodes
- GenBarrier();
+ OpEndIT(it);
- OpIT(kCondEq, "");
+ it = OpIT(kCondEq, "");
LoadConstant(rl_result.reg, 0);
- GenBarrier();
+ OpEndIT(it);
StoreValue(rl_dest, rl_result);
}
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index 8177999..1c563bb 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -67,6 +67,14 @@
return NewLIR2(kThumb2It, code, mask);
}
+void ArmMir2Lir::OpEndIT(LIR* it) {
+ // TODO: use the 'it' pointer to do some checks with the LIR, for example
+ // we could check that the number of instructions matches the mask
+ // in the IT instruction.
+ CHECK(it != nullptr);
+ GenBarrier();
+}
+
/*
* 64-bit 3way compare function.
* mov rX, #-1
@@ -96,10 +104,10 @@
OpRegRegReg(kOpSub, t_reg, rl_src1.reg, rl_src2.reg);
LIR* branch3 = OpCondBranch(kCondEq, NULL);
- OpIT(kCondHi, "E");
+ LIR* it = OpIT(kCondHi, "E");
NewLIR2(kThumb2MovI8M, t_reg.GetReg(), ModifiedImmediate(-1));
LoadConstant(t_reg, 1);
- GenBarrier();
+ OpEndIT(it);
target2 = NewLIR0(kPseudoTargetLabel);
OpRegReg(kOpNeg, t_reg, t_reg);
@@ -187,21 +195,21 @@
if (cheap_false_val && ccode == kCondEq && (true_val == 0 || true_val == -1)) {
OpRegRegImm(kOpSub, rl_result.reg, rl_src.reg, -true_val);
DCHECK(last_lir_insn_->u.m.def_mask & ENCODE_CCODE);
- OpIT(true_val == 0 ? kCondNe : kCondUge, "");
+ LIR* it = OpIT(true_val == 0 ? kCondNe : kCondUge, "");
LoadConstant(rl_result.reg, false_val);
- GenBarrier(); // Add a scheduling barrier to keep the IT shadow intact
+ OpEndIT(it); // Add a scheduling barrier to keep the IT shadow intact
} else if (cheap_false_val && ccode == kCondEq && true_val == 1) {
OpRegRegImm(kOpRsub, rl_result.reg, rl_src.reg, 1);
DCHECK(last_lir_insn_->u.m.def_mask & ENCODE_CCODE);
- OpIT(kCondLs, "");
+ LIR* it = OpIT(kCondLs, "");
LoadConstant(rl_result.reg, false_val);
- GenBarrier(); // Add a scheduling barrier to keep the IT shadow intact
+ OpEndIT(it); // Add a scheduling barrier to keep the IT shadow intact
} else if (cheap_false_val && InexpensiveConstantInt(true_val)) {
OpRegImm(kOpCmp, rl_src.reg, 0);
- OpIT(ccode, "E");
+ LIR* it = OpIT(ccode, "E");
LoadConstant(rl_result.reg, true_val);
LoadConstant(rl_result.reg, false_val);
- GenBarrier(); // Add a scheduling barrier to keep the IT shadow intact
+ OpEndIT(it); // Add a scheduling barrier to keep the IT shadow intact
} else {
// Unlikely case - could be tuned.
RegStorage t_reg1 = AllocTemp();
@@ -209,10 +217,10 @@
LoadConstant(t_reg1, true_val);
LoadConstant(t_reg2, false_val);
OpRegImm(kOpCmp, rl_src.reg, 0);
- OpIT(ccode, "E");
+ LIR* it = OpIT(ccode, "E");
OpRegCopy(rl_result.reg, t_reg1);
OpRegCopy(rl_result.reg, t_reg2);
- GenBarrier(); // Add a scheduling barrier to keep the IT shadow intact
+ OpEndIT(it); // Add a scheduling barrier to keep the IT shadow intact
}
} else {
// MOVE case
@@ -222,18 +230,19 @@
rl_false = LoadValue(rl_false, kCoreReg);
rl_result = EvalLoc(rl_dest, kCoreReg, true);
OpRegImm(kOpCmp, rl_src.reg, 0);
+ LIR* it = nullptr;
if (rl_result.reg.GetReg() == rl_true.reg.GetReg()) { // Is the "true" case already in place?
- OpIT(NegateComparison(ccode), "");
+ it = OpIT(NegateComparison(ccode), "");
OpRegCopy(rl_result.reg, rl_false.reg);
} else if (rl_result.reg.GetReg() == rl_false.reg.GetReg()) { // False case in place?
- OpIT(ccode, "");
+ it = OpIT(ccode, "");
OpRegCopy(rl_result.reg, rl_true.reg);
} else { // Normal - select between the two.
- OpIT(ccode, "E");
+ it = OpIT(ccode, "E");
OpRegCopy(rl_result.reg, rl_true.reg);
OpRegCopy(rl_result.reg, rl_false.reg);
}
- GenBarrier(); // Add a scheduling barrier to keep the IT shadow intact
+ OpEndIT(it); // Add a scheduling barrier to keep the IT shadow intact
}
StoreValue(rl_dest, rl_result);
}
@@ -623,10 +632,10 @@
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");
+ LIR* it = OpIT((is_min) ? kCondGt : kCondLt, "E");
OpRegReg(kOpMov, rl_result.reg, rl_src2.reg);
OpRegReg(kOpMov, rl_result.reg, rl_src1.reg);
- GenBarrier();
+ OpEndIT(it);
StoreValue(rl_dest, rl_result);
return true;
}
@@ -783,6 +792,7 @@
RegStorage r_tmp = AllocTemp();
LIR* target = NewLIR0(kPseudoTargetLabel);
+ LIR* it = nullptr;
if (is_long) {
RegStorage r_tmp_high = AllocTemp();
if (!load_early) {
@@ -803,20 +813,20 @@
FreeTemp(r_tmp_high); // Now unneeded
DCHECK(last_lir_insn_->u.m.def_mask & ENCODE_CCODE);
- OpIT(kCondEq, "T");
+ it = OpIT(kCondEq, "T");
NewLIR4(kThumb2Strexd /* eq */, r_tmp.GetReg(), rl_new_value.reg.GetLowReg(), rl_new_value.reg.GetHighReg(), r_ptr.GetReg());
} else {
NewLIR3(kThumb2Ldrex, r_tmp.GetReg(), r_ptr.GetReg(), 0);
OpRegReg(kOpSub, r_tmp, rl_expected.reg);
DCHECK(last_lir_insn_->u.m.def_mask & ENCODE_CCODE);
- OpIT(kCondEq, "T");
+ it = OpIT(kCondEq, "T");
NewLIR4(kThumb2Strex /* eq */, r_tmp.GetReg(), rl_new_value.reg.GetReg(), r_ptr.GetReg(), 0);
}
// Still one conditional left from OpIT(kCondEq, "T") from either branch
OpRegImm(kOpCmp /* eq */, r_tmp, 1);
- GenBarrier();
+ OpEndIT(it);
OpCondBranch(kCondEq, target);
@@ -828,10 +838,10 @@
RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
OpRegRegImm(kOpRsub, rl_result.reg, r_tmp, 1);
DCHECK(last_lir_insn_->u.m.def_mask & ENCODE_CCODE);
- OpIT(kCondUlt, "");
+ it = OpIT(kCondUlt, "");
LoadConstant(rl_result.reg, 0); /* cc */
FreeTemp(r_tmp); // Now unneeded.
- GenBarrier(); // Barrier to terminate OpIT.
+ OpEndIT(it); // Barrier to terminate OpIT.
StoreValue(rl_dest, rl_result);