diff options
Diffstat (limited to 'compiler/optimizing/instruction_simplifier.cc')
-rw-r--r-- | compiler/optimizing/instruction_simplifier.cc | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index 56bbd8017f..e972e4795e 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -3405,4 +3405,76 @@ void InstructionSimplifierVisitor::VisitVecMul(HVecMul* instruction) { } } +bool TryMergeNegatedInput(HBinaryOperation* op) { + DCHECK(op->IsAnd() || op->IsOr() || op->IsXor()) << op->DebugName(); + HInstruction* left = op->GetLeft(); + HInstruction* right = op->GetRight(); + + // Only consider the case where there is exactly one Not, with 2 Not's De + // Morgan's laws should be applied instead. + if (left->IsNot() ^ right->IsNot()) { + HInstruction* hnot = (left->IsNot() ? left : right); + HInstruction* hother = (left->IsNot() ? right : left); + + // Only do the simplification if the Not has only one use and can thus be + // safely removed. Even though ARM64 negated bitwise operations do not have + // an immediate variant (only register), we still do the simplification when + // `hother` is a constant, because it removes an instruction if the constant + // cannot be encoded as an immediate: + // mov r0, #large_constant + // neg r2, r1 + // and r0, r0, r2 + // becomes: + // mov r0, #large_constant + // bic r0, r0, r1 + if (hnot->HasOnlyOneNonEnvironmentUse()) { + // Replace code looking like + // NOT tmp, mask + // AND dst, src, tmp (respectively ORR, EOR) + // with + // BIC dst, src, mask (respectively ORN, EON) + HInstruction* src = hnot->AsNot()->GetInput(); + + HBitwiseNegatedRight* neg_op = new (hnot->GetBlock()->GetGraph()->GetAllocator()) + HBitwiseNegatedRight(op->GetType(), op->GetKind(), hother, src, op->GetDexPc()); + + op->GetBlock()->ReplaceAndRemoveInstructionWith(op, neg_op); + hnot->GetBlock()->RemoveInstruction(hnot); + return true; + } + } + + return false; +} + +bool TryMergeWithAnd(HSub* instruction) { + HAnd* and_instr = instruction->GetRight()->AsAndOrNull(); + if (and_instr == nullptr) { + return false; + } + + HInstruction* value = instruction->GetLeft(); + + HInstruction* left = and_instr->GetLeft(); + const bool left_is_equal = left == value; + HInstruction* right = and_instr->GetRight(); + const bool right_is_equal = right == value; + if (!left_is_equal && !right_is_equal) { + return false; + } + + HBitwiseNegatedRight* bnr = new (instruction->GetBlock()->GetGraph()->GetAllocator()) + HBitwiseNegatedRight(instruction->GetType(), + HInstruction::InstructionKind::kAnd, + value, + left_is_equal ? right : left, + instruction->GetDexPc()); + instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, bnr); + // Since we don't run DCE after this phase, try to manually remove the And instruction. + if (!and_instr->HasUses()) { + and_instr->GetBlock()->RemoveInstruction(and_instr); + } + return true; +} + } // namespace art |