From ef87c5db0443fc4daa960042313a35352743430e Mon Sep 17 00:00:00 2001 From: Nicolas Geoffray Date: Fri, 30 Jan 2015 12:41:14 +0000 Subject: [PATCH] Allow nested inlining. Also run optimizations before iterating over the instructions to get rid of, e.g., null checks. Change-Id: I6e52e61ce4d0ccb63d687afea09bb4722453bb6a --- compiler/optimizing/inliner.cc | 67 +++++++++++++++++------------- compiler/optimizing/inliner.h | 7 +++- test/446-checker-inliner2/expected.txt | 0 test/446-checker-inliner2/info.txt | 1 + test/446-checker-inliner2/src/Main.java | 72 +++++++++++++++++++++++++++++++++ 5 files changed, 116 insertions(+), 31 deletions(-) create mode 100644 test/446-checker-inliner2/expected.txt create mode 100644 test/446-checker-inliner2/info.txt create mode 100644 test/446-checker-inliner2/src/Main.java diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 532167c17..513be7d80 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -36,23 +36,26 @@ namespace art { 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& 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 @@ bool HInliner::TryInline(HInvoke* invoke_instruction, 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 @@ bool HInliner::TryInline(HInvoke* invoke_instruction, } } - // 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 370e33c2a..07d893e7c 100644 --- a/compiler/optimizing/inliner.h +++ b/compiler/optimizing/inliner.h @@ -33,11 +33,13 @@ class HInliner : public HOptimization { 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 @@ class HInliner : public HOptimization { 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 000000000..e69de29bb diff --git a/test/446-checker-inliner2/info.txt b/test/446-checker-inliner2/info.txt new file mode 100644 index 000000000..66a3270f7 --- /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 000000000..ecf071e45 --- /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"); + } + } +} -- 2.11.0