summaryrefslogtreecommitdiff
path: root/compiler/optimizing/instruction_simplifier_arm64.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing/instruction_simplifier_arm64.cc')
-rw-r--r--compiler/optimizing/instruction_simplifier_arm64.cc55
1 files changed, 55 insertions, 0 deletions
diff --git a/compiler/optimizing/instruction_simplifier_arm64.cc b/compiler/optimizing/instruction_simplifier_arm64.cc
index 83126a5c4d..c2bbdccc29 100644
--- a/compiler/optimizing/instruction_simplifier_arm64.cc
+++ b/compiler/optimizing/instruction_simplifier_arm64.cc
@@ -180,6 +180,53 @@ bool InstructionSimplifierArm64Visitor::TryMergeIntoUsersShifterOperand(HInstruc
return true;
}
+bool InstructionSimplifierArm64Visitor::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();
+
+ HArm64BitwiseNegatedRight* neg_op = new (GetGraph()->GetArena())
+ HArm64BitwiseNegatedRight(op->GetType(), op->GetKind(), hother, src, op->GetDexPc());
+
+ op->GetBlock()->ReplaceAndRemoveInstructionWith(op, neg_op);
+ hnot->GetBlock()->RemoveInstruction(hnot);
+ RecordSimplification();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void InstructionSimplifierArm64Visitor::VisitAnd(HAnd* instruction) {
+ TryMergeNegatedInput(instruction);
+}
+
void InstructionSimplifierArm64Visitor::VisitArrayGet(HArrayGet* instruction) {
TryExtractArrayAccessAddress(instruction,
instruction->GetArray(),
@@ -200,6 +247,10 @@ void InstructionSimplifierArm64Visitor::VisitMul(HMul* instruction) {
}
}
+void InstructionSimplifierArm64Visitor::VisitOr(HOr* instruction) {
+ TryMergeNegatedInput(instruction);
+}
+
void InstructionSimplifierArm64Visitor::VisitShl(HShl* instruction) {
if (instruction->InputAt(1)->IsConstant()) {
TryMergeIntoUsersShifterOperand(instruction);
@@ -232,5 +283,9 @@ void InstructionSimplifierArm64Visitor::VisitUShr(HUShr* instruction) {
}
}
+void InstructionSimplifierArm64Visitor::VisitXor(HXor* instruction) {
+ TryMergeNegatedInput(instruction);
+}
+
} // namespace arm64
} // namespace art