Revert "Revert "ART: DCHECK zero case for CLZ/CTZ""
This reverts commit 4318d91ea4be673d4deba39d33ac4718d77986a7.
Fix up the lit=-1 case in the arm32 Quick backend; add test case.
Change-Id: I8d0861133db950090ee959f532ede1448683dfa9
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index cf01884..db76cc6 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -593,13 +593,20 @@
return true;
}
+ // At this point lit != 1 (which is a power of two).
+ DCHECK_NE(lit, 1);
if (IsPowerOfTwo(lit - 1)) {
op->op = kOpAdd;
op->shift = CTZ(lit - 1);
return true;
}
- if (IsPowerOfTwo(lit + 1)) {
+ if (lit == -1) {
+ // Can be created as neg.
+ op->op = kOpNeg;
+ op->shift = 0;
+ return true;
+ } else if (IsPowerOfTwo(lit + 1)) {
op->op = kOpRsub;
op->shift = CTZ(lit + 1);
return true;
@@ -612,21 +619,26 @@
// Try to convert *lit to 1~2 RegRegRegShift/RegRegShift forms.
bool ArmMir2Lir::GetEasyMultiplyTwoOps(int lit, EasyMultiplyOp* ops) {
+ DCHECK_NE(lit, 1); // A case of "1" should have been folded.
+ DCHECK_NE(lit, -1); // A case of "-1" should have been folded.
if (GetEasyMultiplyOp(lit, &ops[0])) {
ops[1].op = kOpInvalid;
ops[1].shift = 0;
return true;
}
- int lit1 = lit;
- uint32_t shift = CTZ(lit1);
+ DCHECK_NE(lit, 0); // Should be handled above.
+ DCHECK(!IsPowerOfTwo(lit)); // Same.
+
+ int lit1 = lit; // With the DCHECKs, it's clear we don't get "0", "1" or "-1" for
+ uint32_t shift = CTZ(lit1); // lit1.
if (GetEasyMultiplyOp(lit1 >> shift, &ops[0])) {
ops[1].op = kOpLsl;
ops[1].shift = shift;
return true;
}
- lit1 = lit - 1;
+ lit1 = lit - 1; // With the DCHECKs, it's clear we don't get "0" or "1" for lit1.
shift = CTZ(lit1);
if (GetEasyMultiplyOp(lit1 >> shift, &ops[0])) {
ops[1].op = kOpAdd;
@@ -634,7 +646,7 @@
return true;
}
- lit1 = lit + 1;
+ lit1 = lit + 1; // With the DCHECKs, it's clear we don't get "0" here.
shift = CTZ(lit1);
if (GetEasyMultiplyOp(lit1 >> shift, &ops[0])) {
ops[1].op = kOpRsub;
@@ -652,7 +664,7 @@
// Additional temporary register is required,
// if it need to generate 2 instructions and src/dest overlap.
void ArmMir2Lir::GenEasyMultiplyTwoOps(RegStorage r_dest, RegStorage r_src, EasyMultiplyOp* ops) {
- // tmp1 = ( src << shift1) + [ src | -src | 0 ]
+ // tmp1 = (( src << shift1) + [ src | -src | 0 ] ) | -src
// dest = (tmp1 << shift2) + [ src | -src | 0 ]
RegStorage r_tmp1;
@@ -674,6 +686,9 @@
case kOpRsub:
OpRegRegRegShift(kOpRsub, r_tmp1, r_src, r_src, EncodeShift(kArmLsl, ops[0].shift));
break;
+ case kOpNeg:
+ OpRegReg(kOpNeg, r_tmp1, r_src);
+ break;
default:
DCHECK_EQ(ops[0].op, kOpInvalid);
break;
@@ -691,6 +706,7 @@
case kOpRsub:
OpRegRegRegShift(kOpRsub, r_dest, r_src, r_tmp1, EncodeShift(kArmLsl, ops[1].shift));
break;
+ // No negation allowed in second op.
default:
LOG(FATAL) << "Unexpected opcode passed to GenEasyMultiplyTwoOps";
break;