Merge "Allow nested inlining."
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 532167c..513be7d 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -36,23 +36,26 @@
static constexpr int kMaxInlineCodeUnits = 100;
static constexpr int kMaxInlineNumberOfBlocks = 3;
+static constexpr int kDepthLimit = 5;
void HInliner::Run() {
- for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
- for (HInstructionIterator instr_it(it.Current()->GetInstructions());
- !instr_it.Done();
- instr_it.Advance()) {
- HInvokeStaticOrDirect* current = instr_it.Current()->AsInvokeStaticOrDirect();
- if (current != nullptr) {
- if (!TryInline(current, current->GetDexMethodIndex(), current->GetInvokeType())) {
+ const GrowableArray<HBasicBlock*>& blocks = graph_->GetReversePostOrder();
+ for (size_t i = 0; i < blocks.Size(); ++i) {
+ HBasicBlock* block = blocks.Get(i);
+ for (HInstruction* instruction = block->GetFirstInstruction(); instruction != nullptr;) {
+ HInstruction* next = instruction->GetNext();
+ HInvokeStaticOrDirect* call = instruction->AsInvokeStaticOrDirect();
+ if (call != nullptr) {
+ if (!TryInline(call, call->GetDexMethodIndex(), call->GetInvokeType())) {
if (kIsDebugBuild) {
std::string callee_name =
- PrettyMethod(current->GetDexMethodIndex(), *outer_compilation_unit_.GetDexFile());
+ PrettyMethod(call->GetDexMethodIndex(), *outer_compilation_unit_.GetDexFile());
bool should_inline = callee_name.find("$inline$") != std::string::npos;
CHECK(!should_inline) << "Could not inline " << callee_name;
}
}
}
+ instruction = next;
}
}
}
@@ -157,8 +160,34 @@
return false;
}
+ // Run simple optimizations on the graph.
+ SsaRedundantPhiElimination redundant_phi(callee_graph);
+ SsaDeadPhiElimination dead_phi(callee_graph);
+ HDeadCodeElimination dce(callee_graph);
+ HConstantFolding fold(callee_graph);
+ InstructionSimplifier simplify(callee_graph);
+
+ HOptimization* optimizations[] = {
+ &redundant_phi,
+ &dead_phi,
+ &dce,
+ &fold,
+ &simplify,
+ };
+
+ for (size_t i = 0; i < arraysize(optimizations); ++i) {
+ HOptimization* optimization = optimizations[i];
+ optimization->Run();
+ }
+
+ if (depth_ + 1 < kDepthLimit) {
+ HInliner inliner(
+ callee_graph, outer_compilation_unit_, compiler_driver_, outer_stats_, depth_ + 1);
+ inliner.Run();
+ }
+
HReversePostOrderIterator it(*callee_graph);
- it.Advance(); // Past the entry block to avoid seeing the suspend check.
+ it.Advance(); // Past the entry block, it does not contain instructions that prevent inlining.
for (; !it.Done(); it.Advance()) {
HBasicBlock* block = it.Current();
if (block->IsLoopHeader()) {
@@ -187,26 +216,6 @@
}
}
- // Run simple optimizations on the graph.
- SsaRedundantPhiElimination redundant_phi(callee_graph);
- SsaDeadPhiElimination dead_phi(callee_graph);
- HDeadCodeElimination dce(callee_graph);
- HConstantFolding fold(callee_graph);
- InstructionSimplifier simplify(callee_graph);
-
- HOptimization* optimizations[] = {
- &redundant_phi,
- &dead_phi,
- &dce,
- &fold,
- &simplify,
- };
-
- for (size_t i = 0; i < arraysize(optimizations); ++i) {
- HOptimization* optimization = optimizations[i];
- optimization->Run();
- }
-
callee_graph->InlineInto(graph_, invoke_instruction);
// Now that we have inlined the callee, we need to update the next
diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h
index 370e33c..07d893e 100644
--- a/compiler/optimizing/inliner.h
+++ b/compiler/optimizing/inliner.h
@@ -33,11 +33,13 @@
HInliner(HGraph* outer_graph,
const DexCompilationUnit& outer_compilation_unit,
CompilerDriver* compiler_driver,
- OptimizingCompilerStats* stats)
+ OptimizingCompilerStats* stats,
+ size_t depth = 0)
: HOptimization(outer_graph, true, "inliner"),
outer_compilation_unit_(outer_compilation_unit),
compiler_driver_(compiler_driver),
- outer_stats_(stats) {}
+ outer_stats_(stats),
+ depth_(depth) {}
void Run() OVERRIDE;
@@ -47,6 +49,7 @@
const DexCompilationUnit& outer_compilation_unit_;
CompilerDriver* const compiler_driver_;
OptimizingCompilerStats* const outer_stats_;
+ const size_t depth_;
DISALLOW_COPY_AND_ASSIGN(HInliner);
};
diff --git a/test/446-checker-inliner2/expected.txt b/test/446-checker-inliner2/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/446-checker-inliner2/expected.txt
diff --git a/test/446-checker-inliner2/info.txt b/test/446-checker-inliner2/info.txt
new file mode 100644
index 0000000..66a3270
--- /dev/null
+++ b/test/446-checker-inliner2/info.txt
@@ -0,0 +1 @@
+Tests inlining in the optimizing compiler.
diff --git a/test/446-checker-inliner2/src/Main.java b/test/446-checker-inliner2/src/Main.java
new file mode 100644
index 0000000..ecf071e
--- /dev/null
+++ b/test/446-checker-inliner2/src/Main.java
@@ -0,0 +1,72 @@
+/*
+* 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 {
+
+ // CHECK-START: int Main.inlineInstanceCall(Main) inliner (before)
+ // CHECK-DAG: [[Invoke:i\d+]] InvokeStaticOrDirect
+ // CHECK-DAG: Return [ [[Invoke]] ]
+
+ // CHECK-START: int Main.inlineInstanceCall(Main) inliner (after)
+ // CHECK-NOT: InvokeStaticOrDirect
+
+ // CHECK-START: int Main.inlineInstanceCall(Main) inliner (after)
+ // CHECK-DAG: [[Field:i\d+]] InstanceFieldGet
+ // CHECK-DAG: Return [ [[Field]] ]
+
+ public static int inlineInstanceCall(Main m) {
+ return m.foo();
+ }
+
+ private int foo() {
+ return field;
+ }
+
+ int field = 42;
+
+ // CHECK-START: int Main.inlineNestedCall() inliner (before)
+ // CHECK-DAG: [[Invoke:i\d+]] InvokeStaticOrDirect
+ // CHECK-DAG: Return [ [[Invoke]] ]
+
+ // CHECK-START: int Main.inlineNestedCall() inliner (after)
+ // CHECK-NOT: InvokeStaticOrDirect
+
+ // CHECK-START: int Main.inlineNestedCall() inliner (after)
+ // CHECK-DAG: [[Const38:i\d+]] IntConstant 38
+ // CHECK-DAG: Return [ [[Const38]] ]
+
+ public static int inlineNestedCall() {
+ return nestedCall();
+ }
+
+ public static int nestedCall() {
+ return bar();
+ }
+
+ public static int bar() {
+ return 38;
+ }
+
+ public static void main(String[] args) {
+ if (inlineInstanceCall(new Main()) != 42) {
+ throw new Error("Expected 42");
+ }
+
+ if (inlineNestedCall() != 38) {
+ throw new Error("Expected 38");
+ }
+ }
+}