ART: Squash a cmp w/ zero and b.ls to cbz (ARM/ARM64)
In case of array bounds checks at constant index 0 we generate a
compare and a branch. Squash into a cbz.
Change-Id: I1c6a6e37a7a2356b2c4580a3387cedb55436e251
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index f4ea592..2fcc3a5 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -341,7 +341,7 @@
* is responsible for setting branch target field.
*/
LIR* ArmMir2Lir::OpCmpImmBranch(ConditionCode cond, RegStorage reg, int check_value, LIR* target) {
- LIR* branch;
+ LIR* branch = nullptr;
ArmConditionCode arm_cond = ArmConditionEncoding(cond);
/*
* A common use of OpCmpImmBranch is for null checks, and using the Thumb 16-bit
@@ -354,14 +354,22 @@
*/
bool skip = ((target != NULL) && (target->opcode == kPseudoThrowTarget));
skip &= ((cu_->code_item->insns_size_in_code_units_ - current_dalvik_offset_) > 64);
- if (!skip && reg.Low8() && (check_value == 0) &&
- ((arm_cond == kArmCondEq) || (arm_cond == kArmCondNe))) {
- branch = NewLIR2((arm_cond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
- reg.GetReg(), 0);
- } else {
+ if (!skip && reg.Low8() && (check_value == 0)) {
+ if (arm_cond == kArmCondEq || arm_cond == kArmCondNe) {
+ branch = NewLIR2((arm_cond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
+ reg.GetReg(), 0);
+ } else if (arm_cond == kArmCondLs) {
+ // kArmCondLs is an unsigned less or equal. A comparison r <= 0 is then the same as cbz.
+ // This case happens for a bounds check of array[0].
+ branch = NewLIR2(kThumb2Cbz, reg.GetReg(), 0);
+ }
+ }
+
+ if (branch == nullptr) {
OpRegImm(kOpCmp, reg, check_value);
branch = NewLIR2(kThumbBCond, 0, arm_cond);
}
+
branch->target = target;
return branch;
}
diff --git a/compiler/dex/quick/arm64/int_arm64.cc b/compiler/dex/quick/arm64/int_arm64.cc
index 2650892..6dc4a7a 100644
--- a/compiler/dex/quick/arm64/int_arm64.cc
+++ b/compiler/dex/quick/arm64/int_arm64.cc
@@ -269,16 +269,27 @@
*/
LIR* Arm64Mir2Lir::OpCmpImmBranch(ConditionCode cond, RegStorage reg, int check_value,
LIR* target) {
- LIR* branch;
+ LIR* branch = nullptr;
ArmConditionCode arm_cond = ArmConditionEncoding(cond);
- if (check_value == 0 && (arm_cond == kArmCondEq || arm_cond == kArmCondNe)) {
- ArmOpcode opcode = (arm_cond == kArmCondEq) ? kA64Cbz2rt : kA64Cbnz2rt;
- ArmOpcode wide = reg.Is64Bit() ? WIDE(0) : UNWIDE(0);
- branch = NewLIR2(opcode | wide, reg.GetReg(), 0);
- } else {
+ if (check_value == 0) {
+ if (arm_cond == kArmCondEq || arm_cond == kArmCondNe) {
+ ArmOpcode opcode = (arm_cond == kArmCondEq) ? kA64Cbz2rt : kA64Cbnz2rt;
+ ArmOpcode wide = reg.Is64Bit() ? WIDE(0) : UNWIDE(0);
+ branch = NewLIR2(opcode | wide, reg.GetReg(), 0);
+ } else if (arm_cond == kArmCondLs) {
+ // kArmCondLs is an unsigned less or equal. A comparison r <= 0 is then the same as cbz.
+ // This case happens for a bounds check of array[0].
+ ArmOpcode opcode = kA64Cbz2rt;
+ ArmOpcode wide = reg.Is64Bit() ? WIDE(0) : UNWIDE(0);
+ branch = NewLIR2(opcode | wide, reg.GetReg(), 0);
+ }
+ }
+
+ if (branch == nullptr) {
OpRegImm(kOpCmp, reg, check_value);
branch = NewLIR2(kA64B2ct, arm_cond, 0);
}
+
branch->target = target;
return branch;
}