Opt compiler: enhance gvn for commutative ops.

Change-Id: I415b50d58b30cab4ec38077be22373eb9598ec40
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index cda5c1a..07cc41a 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -988,7 +988,7 @@
     __ cmp(left, ShifterOperand(locations->InAt(1).AsRegister<Register>()));
   } else {
     DCHECK(locations->InAt(1).IsConstant());
-    int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
+    int32_t value = CodeGenerator::GetInt32ValueOf(locations->InAt(1).GetConstant());
     ShifterOperand operand;
     if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, value, &operand)) {
       __ cmp(left, operand);
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index adc022a..6365bca 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -894,7 +894,7 @@
     if (rhs.IsRegister()) {
       __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
     } else if (rhs.IsConstant()) {
-      int32_t constant = rhs.GetConstant()->AsIntConstant()->GetValue();
+      int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
       if (constant == 0) {
         __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
       } else {
diff --git a/compiler/optimizing/gvn.cc b/compiler/optimizing/gvn.cc
index cb448c8..ea65dc0 100644
--- a/compiler/optimizing/gvn.cc
+++ b/compiler/optimizing/gvn.cc
@@ -299,8 +299,17 @@
     // Save the next instruction in case `current` is removed from the graph.
     HInstruction* next = current->GetNext();
     if (current->CanBeMoved()) {
+      if (current->IsBinaryOperation() && current->AsBinaryOperation()->IsCommutative()) {
+        // For commutative ops, (x op y) will be treated the same as (y op x)
+        // after fixed ordering.
+        current->AsBinaryOperation()->OrderInputs();
+      }
       HInstruction* existing = set->Lookup(current);
       if (existing != nullptr) {
+        // This replacement doesn't make more OrderInputs() necessary since
+        // current is either used by an instruction that it dominates,
+        // which hasn't been visited yet due to the order we visit instructions.
+        // Or current is used by a phi, and we don't do OrderInputs() on a phi anyway.
         current->ReplaceWith(existing);
         current->GetBlock()->RemoveInstruction(current);
       } else {
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 7e07564..98076a0 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -1500,7 +1500,39 @@
   HInstruction* GetRight() const { return InputAt(1); }
   Primitive::Type GetResultType() const { return GetType(); }
 
-  virtual bool IsCommutative() { return false; }
+  virtual bool IsCommutative() const { return false; }
+
+  // Put constant on the right.
+  // Returns whether order is changed.
+  bool OrderInputsWithConstantOnTheRight() {
+    HInstruction* left = InputAt(0);
+    HInstruction* right = InputAt(1);
+    if (left->IsConstant() && !right->IsConstant()) {
+      ReplaceInput(right, 0);
+      ReplaceInput(left, 1);
+      return true;
+    }
+    return false;
+  }
+
+  // Order inputs by instruction id, but favor constant on the right side.
+  // This helps GVN for commutative ops.
+  void OrderInputs() {
+    DCHECK(IsCommutative());
+    HInstruction* left = InputAt(0);
+    HInstruction* right = InputAt(1);
+    if (left == right || (!left->IsConstant() && right->IsConstant())) {
+      return;
+    }
+    if (OrderInputsWithConstantOnTheRight()) {
+      return;
+    }
+    // Order according to instruction id.
+    if (left->GetId() > right->GetId()) {
+      ReplaceInput(right, 0);
+      ReplaceInput(left, 1);
+    }
+  }
 
   virtual bool CanBeMoved() const { return true; }
   virtual bool InstructionDataEquals(HInstruction* other) const {
@@ -1529,8 +1561,6 @@
       : HBinaryOperation(Primitive::kPrimBoolean, first, second),
         needs_materialization_(true) {}
 
-  virtual bool IsCommutative() { return true; }
-
   bool NeedsMaterialization() const { return needs_materialization_; }
   void ClearNeedsMaterialization() { needs_materialization_ = false; }
 
@@ -1556,6 +1586,8 @@
   HEqual(HInstruction* first, HInstruction* second)
       : HCondition(first, second) {}
 
+  bool IsCommutative() const OVERRIDE { return true; }
+
   virtual int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE {
     return x == y ? 1 : 0;
   }
@@ -1578,6 +1610,8 @@
   HNotEqual(HInstruction* first, HInstruction* second)
       : HCondition(first, second) {}
 
+  bool IsCommutative() const OVERRIDE { return true; }
+
   virtual int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE {
     return x != y ? 1 : 0;
   }
@@ -2136,7 +2170,7 @@
   HAdd(Primitive::Type result_type, HInstruction* left, HInstruction* right)
       : HBinaryOperation(result_type, left, right) {}
 
-  virtual bool IsCommutative() { return true; }
+  virtual bool IsCommutative() const OVERRIDE { return true; }
 
   virtual int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE {
     return x + y;
@@ -2174,7 +2208,7 @@
   HMul(Primitive::Type result_type, HInstruction* left, HInstruction* right)
       : HBinaryOperation(result_type, left, right) {}
 
-  virtual bool IsCommutative() { return true; }
+  virtual bool IsCommutative() const OVERRIDE { return true; }
 
   virtual int32_t Evaluate(int32_t x, int32_t y) const { return x * y; }
   virtual int64_t Evaluate(int64_t x, int64_t y) const { return x * y; }
@@ -2323,7 +2357,7 @@
   HAnd(Primitive::Type result_type, HInstruction* left, HInstruction* right)
       : HBinaryOperation(result_type, left, right) {}
 
-  bool IsCommutative() OVERRIDE { return true; }
+  bool IsCommutative() const OVERRIDE { return true; }
 
   int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x & y; }
   int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x & y; }
@@ -2339,7 +2373,7 @@
   HOr(Primitive::Type result_type, HInstruction* left, HInstruction* right)
       : HBinaryOperation(result_type, left, right) {}
 
-  bool IsCommutative() OVERRIDE { return true; }
+  bool IsCommutative() const OVERRIDE { return true; }
 
   int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x | y; }
   int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x | y; }
@@ -2355,7 +2389,7 @@
   HXor(Primitive::Type result_type, HInstruction* left, HInstruction* right)
       : HBinaryOperation(result_type, left, right) {}
 
-  bool IsCommutative() OVERRIDE { return true; }
+  bool IsCommutative() const OVERRIDE { return true; }
 
   int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x ^ y; }
   int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x ^ y; }
diff --git a/test/455-checker-gvn/expected.txt b/test/455-checker-gvn/expected.txt
new file mode 100644
index 0000000..8351c19
--- /dev/null
+++ b/test/455-checker-gvn/expected.txt
@@ -0,0 +1 @@
+14
diff --git a/test/455-checker-gvn/info.txt b/test/455-checker-gvn/info.txt
new file mode 100644
index 0000000..dfffd92
--- /dev/null
+++ b/test/455-checker-gvn/info.txt
@@ -0,0 +1 @@
+Checker test for GVN.
diff --git a/test/455-checker-gvn/src/Main.java b/test/455-checker-gvn/src/Main.java
new file mode 100644
index 0000000..e94fc46
--- /dev/null
+++ b/test/455-checker-gvn/src/Main.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+  public static void main(String[] args) {
+    System.out.println(foo(3, 4));
+  }
+
+  // CHECK-START: int Main.foo(int, int) GVN (before)
+  // CHECK: Add
+  // CHECK: Add
+  // CHECK: Add
+
+  // CHECK-START: int Main.foo(int, int) GVN (after)
+  // CHECK: Add
+  // CHECK: Add
+  // CHECK-NOT: Add
+
+  public static int foo(int x, int y) {
+    int sum1 = x + y;
+    int sum2 = y + x;
+    return sum1 + sum2;
+  }
+
+  public static long bar(int i) {
+    return i;
+  }
+}