Optimizing: Improve constant folding + DCE for inlining.
Run constant folding before DCE in inliner to eliminate more
code that can prevent inlining. Improve the constant folding
to evaluate Equals and NotEquals for null inputs.
Change-Id: I876ffb903ef39484370b6c8793f0f8467a977362
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 353881e..c9319f5 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -406,8 +406,8 @@
&type_propagation,
&sharpening,
&simplify,
- &dce,
&fold,
+ &dce,
};
for (size_t i = 0; i < arraysize(optimizations); ++i) {
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index f006df1..1a46853 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -1090,6 +1090,8 @@
} else if (GetRight()->IsLongConstant()) {
return Evaluate(GetLeft()->AsLongConstant(), GetRight()->AsLongConstant());
}
+ } else if (GetLeft()->IsNullConstant() && GetRight()->IsNullConstant()) {
+ return Evaluate(GetLeft()->AsNullConstant(), GetRight()->AsNullConstant());
}
return nullptr;
}
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 4421419..ba140af 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -2612,6 +2612,11 @@
VLOG(compiler) << DebugName() << " is not defined for the (long, int) case.";
return nullptr;
}
+ virtual HConstant* Evaluate(HNullConstant* x ATTRIBUTE_UNUSED,
+ HNullConstant* y ATTRIBUTE_UNUSED) const {
+ VLOG(compiler) << DebugName() << " is not defined for the (null, null) case.";
+ return nullptr;
+ }
// Returns an input that can legally be used as the right input and is
// constant, or null.
@@ -2702,6 +2707,10 @@
return GetBlock()->GetGraph()->GetIntConstant(
Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
+ HConstant* Evaluate(HNullConstant* x ATTRIBUTE_UNUSED,
+ HNullConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ return GetBlock()->GetGraph()->GetConstant(GetType(), 1);
+ }
DECLARE_INSTRUCTION(Equal);
@@ -2734,6 +2743,10 @@
return GetBlock()->GetGraph()->GetIntConstant(
Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
+ HConstant* Evaluate(HNullConstant* x ATTRIBUTE_UNUSED,
+ HNullConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ return GetBlock()->GetGraph()->GetConstant(GetType(), 0);
+ }
DECLARE_INSTRUCTION(NotEqual);
diff --git a/test/442-checker-constant-folding/src/Main.java b/test/442-checker-constant-folding/src/Main.java
index 59e7282..43bc9d0 100644
--- a/test/442-checker-constant-folding/src/Main.java
+++ b/test/442-checker-constant-folding/src/Main.java
@@ -659,6 +659,33 @@
/**
+ * Exercise constant folding on constant (static) condition for null references.
+ */
+
+ /// CHECK-START: int Main.StaticConditionNulls() constant_folding_after_inlining (before)
+ /// CHECK-DAG: <<Null:l\d+>> NullConstant
+ /// CHECK-DAG: <<Cond:z\d+>> NotEqual [<<Null>>,<<Null>>]
+ /// CHECK-DAG: If [<<Cond>>]
+
+ /// CHECK-START: int Main.StaticConditionNulls() constant_folding_after_inlining (after)
+ /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
+ /// CHECK-DAG: If [<<Const0>>]
+
+ /// CHECK-START: int Main.StaticConditionNulls() constant_folding_after_inlining (after)
+ /// CHECK-NOT: NotEqual
+
+ private static Object getNull() {
+ return null;
+ }
+
+ public static int StaticConditionNulls() {
+ Object a = getNull();
+ Object b = getNull();
+ return (a == b) ? 5 : 2;
+ }
+
+
+ /**
* Exercise constant folding on a program with condition
* (i.e. jumps) leading to the creation of many blocks.
*
@@ -1208,6 +1235,7 @@
assertLongEquals(9, XorLongInt());
assertIntEquals(5, StaticCondition());
+ assertIntEquals(5, StaticConditionNulls());
assertIntEquals(7, JumpsAndConditionals(true));
assertIntEquals(3, JumpsAndConditionals(false));
diff --git a/test/548-checker-inlining-and-dce/expected.txt b/test/548-checker-inlining-and-dce/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/548-checker-inlining-and-dce/expected.txt
diff --git a/test/548-checker-inlining-and-dce/info.txt b/test/548-checker-inlining-and-dce/info.txt
new file mode 100644
index 0000000..3255d6b
--- /dev/null
+++ b/test/548-checker-inlining-and-dce/info.txt
@@ -0,0 +1 @@
+Test that inlining works when code preventing inlining is eliminated by DCE.
diff --git a/test/548-checker-inlining-and-dce/src/Main.java b/test/548-checker-inlining-and-dce/src/Main.java
new file mode 100644
index 0000000..38fdcc0
--- /dev/null
+++ b/test/548-checker-inlining-and-dce/src/Main.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2015 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 {
+
+ private void inlinedForNull(Iterable it) {
+ if (it != null) {
+ // We're not inlining invoke-interface at the moment.
+ it.iterator();
+ }
+ }
+
+ private void inlinedForFalse(boolean value, Iterable it) {
+ if (value) {
+ // We're not inlining invoke-interface at the moment.
+ it.iterator();
+ }
+ }
+
+ /// CHECK-START: void Main.testInlinedForFalseInlined(java.lang.Iterable) inliner (before)
+ /// CHECK: InvokeStaticOrDirect
+
+ /// CHECK-START: void Main.testInlinedForFalseInlined(java.lang.Iterable) inliner (after)
+ /// CHECK-NOT: InvokeStaticOrDirect
+ /// CHECK-NOT: InvokeInterface
+
+ public void testInlinedForFalseInlined(Iterable it) {
+ inlinedForFalse(false, it);
+ }
+
+ /// CHECK-START: void Main.testInlinedForFalseNotInlined(java.lang.Iterable) inliner (before)
+ /// CHECK: InvokeStaticOrDirect
+
+ /// CHECK-START: void Main.testInlinedForFalseNotInlined(java.lang.Iterable) inliner (after)
+ /// CHECK: InvokeStaticOrDirect
+
+ public void testInlinedForFalseNotInlined(Iterable it) {
+ inlinedForFalse(true, it);
+ }
+
+ /// CHECK-START: void Main.testInlinedForNullInlined(java.lang.Iterable) inliner (before)
+ /// CHECK: InvokeStaticOrDirect
+
+ /// CHECK-START: void Main.testInlinedForNullInlined(java.lang.Iterable) inliner (after)
+ /// CHECK-NOT: InvokeStaticOrDirect
+ /// CHECK-NOT: InvokeInterface
+
+ public void testInlinedForNullInlined(Iterable it) {
+ inlinedForNull(null);
+ }
+
+ /// CHECK-START: void Main.testInlinedForNullNotInlined(java.lang.Iterable) inliner (before)
+ /// CHECK: InvokeStaticOrDirect
+
+ /// CHECK-START: void Main.testInlinedForNullNotInlined(java.lang.Iterable) inliner (after)
+ /// CHECK: InvokeStaticOrDirect
+
+ public void testInlinedForNullNotInlined(Iterable it) {
+ inlinedForNull(it);
+ }
+
+ public static void main(String[] args) {
+ Main m = new Main();
+ Iterable it = new Iterable() {
+ public java.util.Iterator iterator() { return null; }
+ };
+ m.testInlinedForFalseInlined(it);
+ m.testInlinedForFalseNotInlined(it);
+ m.testInlinedForNullInlined(it);
+ m.testInlinedForNullNotInlined(it);
+ }
+}