Fold opposite values for OR and XOR into -1 am: 31d96b5c37 am: b092315dd2

Original change: https://android-review.googlesource.com/c/platform/art/+/2984874

Change-Id: I83075580e292f52fcde811c6d7461a64cf395fc3
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
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.