diff options
| author | 2015-09-25 14:44:17 +0100 | |
|---|---|---|
| committer | 2015-09-29 13:40:06 +0100 | |
| commit | 452c1b60120aee0883c3339b363f820b8d69c299 (patch) | |
| tree | 78d0c7134064446dadd86407d353769b939d64f0 /compiler/optimizing/instruction_simplifier.cc | |
| parent | ec7e44f7afe0ff48d4d1ae54a12d375e0392d24c (diff) | |
Optimizing: Simplify UShr+And, Shr+And.
Eliminate And from UShr+And if the And-mask contains all the
bits that can be non-zero after UShr. Transform Shr+And to
UShr if the And-mask precisely clears the shifted-in sign
bits.
This prepares for detecting the Rotate pattern, i.e.
(x << N) | (x >>> (SIZE - N))
in code that unnecessarily masks the UShr, for example
(x << 1) | ((x >>> 31) & 1) ,
or uses Shr, for example
(x << 8) | ((x >> 24) & 0xff) .
Change-Id: I684c4b752547d9b1057d0d4c4d44550bb1a3ffb4
Diffstat (limited to 'compiler/optimizing/instruction_simplifier.cc')
| -rw-r--r-- | compiler/optimizing/instruction_simplifier.cc | 47 |
1 files changed, 39 insertions, 8 deletions
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index 0ac26de674..abdda13bb8 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -502,14 +502,45 @@ void InstructionSimplifierVisitor::VisitAnd(HAnd* instruction) { HConstant* input_cst = instruction->GetConstantRight(); HInstruction* input_other = instruction->GetLeastConstantLeft(); - if ((input_cst != nullptr) && AreAllBitsSet(input_cst)) { - // Replace code looking like - // AND dst, src, 0xFFF...FF - // with - // src - instruction->ReplaceWith(input_other); - instruction->GetBlock()->RemoveInstruction(instruction); - return; + if (input_cst != nullptr) { + int64_t value = Int64FromConstant(input_cst); + if (value == -1) { + // Replace code looking like + // AND dst, src, 0xFFF...FF + // with + // src + instruction->ReplaceWith(input_other); + instruction->GetBlock()->RemoveInstruction(instruction); + RecordSimplification(); + return; + } + // Eliminate And from UShr+And if the And-mask contains all the bits that + // can be non-zero after UShr. Transform Shr+And to UShr if the And-mask + // precisely clears the shifted-in sign bits. + if ((input_other->IsUShr() || input_other->IsShr()) && input_other->InputAt(1)->IsConstant()) { + size_t reg_bits = (instruction->GetResultType() == Primitive::kPrimLong) ? 64 : 32; + size_t shift = Int64FromConstant(input_other->InputAt(1)->AsConstant()) & (reg_bits - 1); + size_t num_tail_bits_set = CTZ(value + 1); + if ((num_tail_bits_set >= reg_bits - shift) && input_other->IsUShr()) { + // This AND clears only bits known to be clear, for example "(x >>> 24) & 0xff". + instruction->ReplaceWith(input_other); + instruction->GetBlock()->RemoveInstruction(instruction); + RecordSimplification(); + return; + } else if ((num_tail_bits_set == reg_bits - shift) && IsPowerOfTwo(value + 1) && + input_other->HasOnlyOneNonEnvironmentUse()) { + DCHECK(input_other->IsShr()); // For UShr, we would have taken the branch above. + // Replace SHR+AND with USHR, for example "(x >> 24) & 0xff" -> "x >>> 24". + HUShr* ushr = new (GetGraph()->GetArena()) HUShr(instruction->GetType(), + input_other->InputAt(0), + input_other->InputAt(1), + input_other->GetDexPc()); + instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, ushr); + input_other->GetBlock()->RemoveInstruction(input_other); + RecordSimplification(); + return; + } + } } // We assume that GVN has run before, so we only perform a pointer comparison. |