OSDN Git Service

Allow nested inlining.
authorNicolas Geoffray <ngeoffray@google.com>
Fri, 30 Jan 2015 12:41:14 +0000 (12:41 +0000)
committerNicolas Geoffray <ngeoffray@google.com>
Tue, 3 Feb 2015 11:18:29 +0000 (11:18 +0000)
Also run optimizations before iterating over
the instructions to get rid of, e.g., null checks.

Change-Id: I6e52e61ce4d0ccb63d687afea09bb4722453bb6a

compiler/optimizing/inliner.cc
compiler/optimizing/inliner.h
test/446-checker-inliner2/expected.txt [new file with mode: 0644]
test/446-checker-inliner2/info.txt [new file with mode: 0644]
test/446-checker-inliner2/src/Main.java [new file with mode: 0644]

index 532167c..513be7d 100644 (file)
@@ -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<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 @@ 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
index 370e33c..07d893e 100644 (file)
@@ -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 (file)
index 0000000..e69de29
diff --git a/test/446-checker-inliner2/info.txt b/test/446-checker-inliner2/info.txt
new file mode 100644 (file)
index 0000000..66a3270
--- /dev/null
@@ -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 (file)
index 0000000..ecf071e
--- /dev/null
@@ -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");
+    }
+  }
+}