Fold opposite values for OR and XOR into -1
We can fold operations like `a | ~a` and `a ^ ~a` into 0xFF...FF.
These operations only exist for int/long.
Test: art/test/testrunner/testrunner.py --host --64 --optimizing -b
Change-Id: I765e294ca2938710576a94de5978994ab1227a6b
diff --git a/compiler/optimizing/constant_folding.cc b/compiler/optimizing/constant_folding.cc
index f57d8ad..52cbfe8 100644
--- a/compiler/optimizing/constant_folding.cc
+++ b/compiler/optimizing/constant_folding.cc
@@ -876,18 +876,35 @@
void InstructionWithAbsorbingInputSimplifier::VisitOr(HOr* instruction) {
HConstant* input_cst = instruction->GetConstantRight();
-
- if (input_cst == nullptr) {
- return;
- }
-
- if (Int64FromConstant(input_cst) == -1) {
+ if (input_cst != nullptr && Int64FromConstant(input_cst) == -1) {
// Replace code looking like
// OR dst, src, 0xFFF...FF
// with
// CONSTANT 0xFFF...FF
instruction->ReplaceWith(input_cst);
instruction->GetBlock()->RemoveInstruction(instruction);
+ return;
+ }
+
+ HInstruction* left = instruction->GetLeft();
+ HInstruction* right = instruction->GetRight();
+ if (left->IsNot() ^ right->IsNot()) {
+ // Replace code looking like
+ // NOT notsrc, src
+ // OR dst, notsrc, src
+ // with
+ // CONSTANT 0xFFF...FF
+ HInstruction* hnot = (left->IsNot() ? left : right);
+ HInstruction* hother = (left->IsNot() ? right : left);
+ HInstruction* src = hnot->AsNot()->GetInput();
+
+ if (src == hother) {
+ DCHECK(instruction->GetType() == DataType::Type::kInt32 ||
+ instruction->GetType() == DataType::Type::kInt64);
+ instruction->ReplaceWith(GetGraph()->GetConstant(instruction->GetType(), -1));
+ instruction->GetBlock()->RemoveInstruction(instruction);
+ return;
+ }
}
}
@@ -974,6 +991,28 @@
HBasicBlock* block = instruction->GetBlock();
instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
block->RemoveInstruction(instruction);
+ return;
+ }
+
+ HInstruction* left = instruction->GetLeft();
+ HInstruction* right = instruction->GetRight();
+ if (left->IsNot() ^ right->IsNot()) {
+ // Replace code looking like
+ // NOT notsrc, src
+ // XOR dst, notsrc, src
+ // with
+ // CONSTANT 0xFFF...FF
+ HInstruction* hnot = (left->IsNot() ? left : right);
+ HInstruction* hother = (left->IsNot() ? right : left);
+ HInstruction* src = hnot->AsNot()->GetInput();
+
+ if (src == hother) {
+ DCHECK(instruction->GetType() == DataType::Type::kInt32 ||
+ instruction->GetType() == DataType::Type::kInt64);
+ instruction->ReplaceWith(GetGraph()->GetConstant(instruction->GetType(), -1));
+ instruction->GetBlock()->RemoveInstruction(instruction);
+ return;
+ }
}
}
diff --git a/test/442-checker-constant-folding/src/Main.java b/test/442-checker-constant-folding/src/Main.java
index 7c6d609..13c42d2 100644
--- a/test/442-checker-constant-folding/src/Main.java
+++ b/test/442-checker-constant-folding/src/Main.java
@@ -886,6 +886,91 @@
return arg & ~arg;
}
+ /// CHECK-START: int Main.OrSelfNegated(int) constant_folding (before)
+ /// CHECK-DAG: <<Arg:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Not:i\d+>> Not [<<Arg>>]
+ /// CHECK-DAG: <<Or:i\d+>> Or [<<Not>>,<<Arg>>]
+ /// CHECK-DAG: Return [<<Or>>]
+
+ /// CHECK-START: int Main.OrSelfNegated(int) constant_folding (after)
+ /// CHECK-DAG: <<Const:i\d+>> IntConstant -1
+ /// CHECK-DAG: Return [<<Const>>]
+
+ /// CHECK-START: int Main.OrSelfNegated(int) constant_folding (after)
+ /// CHECK-NOT: Or
+
+ public static int OrSelfNegated(int arg) {
+ return arg | ~arg;
+ }
+
+ /// CHECK-START: int Main.XorSelfNegated(int) constant_folding (before)
+ /// CHECK-DAG: <<Arg:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Not:i\d+>> Not [<<Arg>>]
+ /// CHECK-DAG: <<Xor:i\d+>> Xor [<<Not>>,<<Arg>>]
+ /// CHECK-DAG: Return [<<Xor>>]
+
+ /// CHECK-START: int Main.XorSelfNegated(int) constant_folding (after)
+ /// CHECK-DAG: <<Const:i\d+>> IntConstant -1
+ /// CHECK-DAG: Return [<<Const>>]
+
+ /// CHECK-START: int Main.XorSelfNegated(int) constant_folding (after)
+ /// CHECK-NOT: Xor
+
+ public static int XorSelfNegated(int arg) {
+ return arg ^ ~arg;
+ }
+
+ /// CHECK-START: long Main.AndSelfNegated(long) constant_folding (before)
+ /// CHECK-DAG: <<Arg:j\d+>> ParameterValue
+ /// CHECK-DAG: <<Not:j\d+>> Not [<<Arg>>]
+ /// CHECK-DAG: <<And:j\d+>> And [<<Not>>,<<Arg>>]
+ /// CHECK-DAG: Return [<<And>>]
+
+ /// CHECK-START: long Main.AndSelfNegated(long) constant_folding (after)
+ /// CHECK-DAG: <<Const0:j\d+>> LongConstant 0
+ /// CHECK-DAG: Return [<<Const0>>]
+
+ /// CHECK-START: long Main.AndSelfNegated(long) constant_folding (after)
+ /// CHECK-NOT: And
+
+ public static long AndSelfNegated(long arg) {
+ return arg & ~arg;
+ }
+
+ /// CHECK-START: long Main.OrSelfNegated(long) constant_folding (before)
+ /// CHECK-DAG: <<Arg:j\d+>> ParameterValue
+ /// CHECK-DAG: <<Not:j\d+>> Not [<<Arg>>]
+ /// CHECK-DAG: <<Or:j\d+>> Or [<<Not>>,<<Arg>>]
+ /// CHECK-DAG: Return [<<Or>>]
+
+ /// CHECK-START: long Main.OrSelfNegated(long) constant_folding (after)
+ /// CHECK-DAG: <<Const:j\d+>> LongConstant -1
+ /// CHECK-DAG: Return [<<Const>>]
+
+ /// CHECK-START: long Main.OrSelfNegated(long) constant_folding (after)
+ /// CHECK-NOT: Or
+
+ public static long OrSelfNegated(long arg) {
+ return arg | ~arg;
+ }
+
+ /// CHECK-START: long Main.XorSelfNegated(long) constant_folding (before)
+ /// CHECK-DAG: <<Arg:j\d+>> ParameterValue
+ /// CHECK-DAG: <<Not:j\d+>> Not [<<Arg>>]
+ /// CHECK-DAG: <<Xor:j\d+>> Xor [<<Not>>,<<Arg>>]
+ /// CHECK-DAG: Return [<<Xor>>]
+
+ /// CHECK-START: long Main.XorSelfNegated(long) constant_folding (after)
+ /// CHECK-DAG: <<Const:j\d+>> LongConstant -1
+ /// CHECK-DAG: Return [<<Const>>]
+
+ /// CHECK-START: long Main.XorSelfNegated(long) constant_folding (after)
+ /// CHECK-NOT: Xor
+
+ public static long XorSelfNegated(long arg) {
+ return arg ^ ~arg;
+ }
+
/**
* Exercise constant folding on logical or.