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; }