Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/flow_graph_inliner.h" | 5 #include "vm/flow_graph_inliner.h" |
| 6 | 6 |
| 7 #include "vm/compiler.h" | |
| 7 #include "vm/flags.h" | 8 #include "vm/flags.h" |
| 8 #include "vm/flow_graph.h" | 9 #include "vm/flow_graph.h" |
| 9 #include "vm/flow_graph_builder.h" | 10 #include "vm/flow_graph_builder.h" |
| 11 #include "vm/flow_graph_optimizer.h" | |
| 12 #include "vm/intrinsifier.h" | |
|
Kevin Millikin (Google)
2012/09/18 11:01:55
I think we try to keep these sorted according to M
zerny-google
2012/09/18 11:53:07
Thanks again.
| |
| 10 #include "vm/il_printer.h" | 13 #include "vm/il_printer.h" |
| 11 #include "vm/longjump.h" | 14 #include "vm/longjump.h" |
| 12 #include "vm/object.h" | 15 #include "vm/object.h" |
| 13 #include "vm/object_store.h" | 16 #include "vm/object_store.h" |
| 14 | 17 |
| 15 namespace dart { | 18 namespace dart { |
| 16 | 19 |
| 17 DEFINE_FLAG(bool, trace_inlining, false, "Trace inlining"); | 20 DEFINE_FLAG(bool, trace_inlining, false, "Trace inlining"); |
| 18 DEFINE_FLAG(charp, inlining_filter, NULL, "Inline only in named function"); | 21 DEFINE_FLAG(charp, inlining_filter, NULL, "Inline only in named function"); |
| 19 DECLARE_FLAG(bool, print_flow_graph); | 22 DECLARE_FLAG(bool, print_flow_graph); |
| 23 DECLARE_FLAG(bool, deoptimization_counter_threshold); | |
| 20 | 24 |
| 21 #define TRACE_INLINING(statement) \ | 25 #define TRACE_INLINING(statement) \ |
| 22 do { \ | 26 do { \ |
| 23 if (FLAG_trace_inlining) statement; \ | 27 if (FLAG_trace_inlining) statement; \ |
| 24 } while (false) | 28 } while (false) |
| 25 | 29 |
| 26 | 30 |
| 27 class CallSiteInliner : public FlowGraphVisitor { | 31 class CallSiteInliner : public FlowGraphVisitor { |
| 28 public: | 32 public: |
| 29 explicit CallSiteInliner(FlowGraph* flow_graph) | 33 explicit CallSiteInliner(FlowGraph* flow_graph) |
| 30 : FlowGraphVisitor(flow_graph->postorder()), | 34 : FlowGraphVisitor(flow_graph->postorder()), |
| 31 caller_graph_(flow_graph), | 35 caller_graph_(flow_graph), |
| 32 next_ssa_temp_index_(flow_graph->max_virtual_register_number()), | 36 next_ssa_temp_index_(flow_graph->max_virtual_register_number()), |
| 33 inlined_(false) { } | 37 inlined_(false) { } |
| 34 | 38 |
| 35 bool TryInlining(const Function& function, | 39 bool TryInlining(const Function& function, |
| 36 GrowableArray<Value*>* arguments, | 40 GrowableArray<Value*>* arguments, |
| 37 Definition* call) { | 41 Definition* call) { |
| 38 TRACE_INLINING(OS::Print(" => %s\n", function.ToCString())); | 42 TRACE_INLINING(OS::Print(" => %s\n", function.ToCString())); |
| 39 | 43 |
| 40 // Abort if the callee has optional parameters. | 44 // Abort if the callee has optional parameters. |
| 41 if (function.HasOptionalParameters()) { | 45 if (function.HasOptionalParameters()) { |
| 42 TRACE_INLINING(OS::Print(" Bailout: optional parameters\n")); | 46 TRACE_INLINING(OS::Print(" Bailout: optional parameters\n")); |
| 43 return false; | 47 return false; |
| 44 } | 48 } |
| 45 | 49 |
| 46 // Assuming no optional parameters the actual/formal count should match. | 50 // Assuming no optional parameters the actual/formal count should match. |
| 47 ASSERT(arguments->length() == function.num_fixed_parameters()); | 51 ASSERT(arguments->length() == function.num_fixed_parameters()); |
| 48 | 52 |
| 53 // Abort if the callee has an intrinsic translation. | |
| 54 if (Intrinsifier::CanIntrinsify(function)) { | |
| 55 TRACE_INLINING(OS::Print(" Bailout: can intrinsify\n")); | |
| 56 return false; | |
| 57 } | |
| 58 | |
| 49 Isolate* isolate = Isolate::Current(); | 59 Isolate* isolate = Isolate::Current(); |
| 50 // Save and clear IC data. | 60 // Save and clear IC data. |
| 51 const Array& old_ic_data = Array::Handle(isolate->ic_data_array()); | 61 const Array& old_ic_data = Array::Handle(isolate->ic_data_array()); |
| 52 isolate->set_ic_data_array(Array::null()); | 62 isolate->set_ic_data_array(Array::null()); |
| 63 // Save and clear deopt id. | |
| 64 const intptr_t prev_deopt_id = isolate->deopt_id(); | |
|
Kevin Millikin (Google)
2012/09/18 11:01:55
It distracts me that we have old_ic_data and prev_
zerny-google
2012/09/18 11:53:07
Done.
| |
| 65 isolate->set_deopt_id(0); | |
| 53 // Install bailout jump. | 66 // Install bailout jump. |
| 54 LongJump* base = isolate->long_jump_base(); | 67 LongJump* base = isolate->long_jump_base(); |
| 55 LongJump jump; | 68 LongJump jump; |
| 56 isolate->set_long_jump_base(&jump); | 69 isolate->set_long_jump_base(&jump); |
| 57 if (setjmp(*jump.Set()) == 0) { | 70 if (setjmp(*jump.Set()) == 0) { |
| 58 // Parse the callee function. | 71 // Parse the callee function. |
| 59 ParsedFunction parsed_function(function); | 72 ParsedFunction parsed_function(function); |
| 60 Parser::ParseFunction(&parsed_function); | 73 Parser::ParseFunction(&parsed_function); |
| 61 parsed_function.AllocateVariables(); | 74 parsed_function.AllocateVariables(); |
| 62 FlowGraphBuilder builder(parsed_function); | 75 |
| 76 // Load IC data for the callee. | |
| 77 if ((function.deoptimization_counter() < | |
| 78 FLAG_deoptimization_counter_threshold) && | |
| 79 function.HasCode()) { | |
| 80 const Code& unoptimized_code = | |
| 81 Code::Handle(function.unoptimized_code()); | |
| 82 isolate->set_ic_data_array( | |
| 83 Compiler::ExtractTypeFeedbackArray(unoptimized_code)); | |
| 84 } | |
| 63 | 85 |
| 64 // Build the callee graph. | 86 // Build the callee graph. |
| 87 FlowGraphBuilder builder(parsed_function); | |
| 65 FlowGraph* callee_graph = | 88 FlowGraph* callee_graph = |
| 66 builder.BuildGraph(FlowGraphBuilder::kValueContext); | 89 builder.BuildGraph(FlowGraphBuilder::kValueContext); |
| 67 | 90 |
| 68 // Abort if the callee graph contains control flow. | 91 // Abort if the callee graph contains control flow. |
| 69 if (callee_graph->preorder().length() != 2) { | 92 if (callee_graph->preorder().length() != 2) { |
| 70 isolate->set_long_jump_base(base); | 93 isolate->set_long_jump_base(base); |
| 71 isolate->set_ic_data_array(old_ic_data.raw()); | 94 isolate->set_ic_data_array(old_ic_data.raw()); |
| 72 TRACE_INLINING(OS::Print(" Bailout: control flow\n")); | 95 TRACE_INLINING(OS::Print(" Bailout: control flow\n")); |
| 73 return false; | 96 return false; |
| 74 } | 97 } |
| 75 | 98 |
| 99 // Compute SSA on the callee graph. (catching bailouts) | |
|
Kevin Millikin (Google)
2012/09/18 11:01:55
Format as a complete sentence: "Compute SSA on the
zerny-google
2012/09/18 11:53:07
Done.
| |
| 100 callee_graph->ComputeSSA(next_ssa_temp_index_); | |
| 101 callee_graph->ComputeUseLists(); | |
| 102 | |
| 103 // TODO(zerny): Do optimization passes on the callee graph. | |
|
Kevin Millikin (Google)
2012/09/18 11:01:55
"Do more optimization...."
zerny-google
2012/09/18 11:53:07
Done.
| |
| 104 FlowGraphOptimizer optimizer(callee_graph); | |
| 105 optimizer.ApplyICData(); | |
| 106 callee_graph->ComputeUseLists(); | |
| 107 | |
| 76 if (FLAG_trace_inlining && FLAG_print_flow_graph) { | 108 if (FLAG_trace_inlining && FLAG_print_flow_graph) { |
| 77 OS::Print("Callee graph before SSA %s\n", | 109 OS::Print("Callee graph for inlining %s\n", |
| 78 parsed_function.function().ToFullyQualifiedCString()); | 110 parsed_function.function().ToFullyQualifiedCString()); |
| 79 FlowGraphPrinter printer(*callee_graph); | 111 FlowGraphPrinter printer(*callee_graph); |
| 80 printer.PrintBlocks(); | 112 printer.PrintBlocks(); |
| 81 } | 113 } |
| 82 | 114 |
| 83 // Compute SSA on the callee graph. (catching bailouts) | |
| 84 callee_graph->ComputeSSA(next_ssa_temp_index_); | |
| 85 | |
| 86 if (FLAG_trace_inlining && FLAG_print_flow_graph) { | |
| 87 OS::Print("Callee graph after SSA %s\n", | |
| 88 parsed_function.function().ToFullyQualifiedCString()); | |
| 89 FlowGraphPrinter printer(*callee_graph); | |
| 90 printer.PrintBlocks(); | |
| 91 } | |
| 92 | |
| 93 callee_graph->ComputeUseLists(); | |
| 94 | |
| 95 // TODO(zerny): Do optimization passes on the callee graph. | |
| 96 | |
| 97 // TODO(zerny): If result is more than size threshold then abort. | 115 // TODO(zerny): If result is more than size threshold then abort. |
| 98 | 116 |
| 99 // TODO(zerny): If effort is less than threshold then inline recursively. | 117 // TODO(zerny): If effort is less than threshold then inline recursively. |
| 100 | 118 |
| 101 // Plug result in the caller graph. | 119 // Plug result in the caller graph. |
| 102 caller_graph_->InlineCall(call, callee_graph); | 120 caller_graph_->InlineCall(call, callee_graph); |
| 103 next_ssa_temp_index_ = caller_graph_->max_virtual_register_number(); | 121 next_ssa_temp_index_ = caller_graph_->max_virtual_register_number(); |
| 104 | 122 |
| 105 // Remove (all) push arguments of the call. | 123 // Check that inlining maintains use lists. |
| 124 DEBUG_ASSERT(caller_graph_->ValidateUseLists()); | |
| 125 | |
| 126 // Remove push arguments of the call. | |
| 106 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | 127 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
| 107 PushArgumentInstr* push = call->ArgumentAt(i); | 128 PushArgumentInstr* push = call->ArgumentAt(i); |
| 108 push->ReplaceUsesWith(push->value()->definition()); | 129 push->ReplaceUsesWith(push->value()->definition()); |
| 109 push->RemoveFromGraph(); | 130 push->RemoveFromGraph(); |
| 110 } | 131 } |
| 111 | 132 |
| 112 // Replace all the formal parameters with the actuals. | 133 // Replace formal parameters with actuals. |
| 113 for (intptr_t i = 0; i < arguments->length(); ++i) { | 134 for (intptr_t i = 0; i < arguments->length(); ++i) { |
| 114 Value* val = callee_graph->graph_entry()->start_env()->ValueAt(i); | 135 Value* val = callee_graph->graph_entry()->start_env()->ValueAt(i); |
| 115 ParameterInstr* param = val->definition()->AsParameter(); | 136 ParameterInstr* param = val->definition()->AsParameter(); |
| 116 ASSERT(param != NULL); | 137 ASSERT(param != NULL); |
| 117 param->ReplaceUsesWith((*arguments)[i]->definition()); | 138 param->ReplaceUsesWith((*arguments)[i]->definition()); |
| 118 } | 139 } |
| 119 | 140 |
| 120 // Replace callee's null constant with caller's null constant. | 141 // Replace callee's null constant with caller's null constant. |
| 121 callee_graph->graph_entry()->constant_null()->ReplaceUsesWith( | 142 callee_graph->graph_entry()->constant_null()->ReplaceUsesWith( |
| 122 caller_graph_->graph_entry()->constant_null()); | 143 caller_graph_->graph_entry()->constant_null()); |
| 123 | 144 |
| 124 TRACE_INLINING(OS::Print(" Success\n")); | 145 TRACE_INLINING(OS::Print(" Success\n")); |
| 125 | 146 |
| 126 // Build succeeded so we restore the bailout jump. | 147 // Build succeeded so we restore the bailout jump. |
| 127 inlined_ = true; | 148 inlined_ = true; |
| 128 isolate->set_long_jump_base(base); | 149 isolate->set_long_jump_base(base); |
| 150 isolate->set_deopt_id(prev_deopt_id); | |
| 129 isolate->set_ic_data_array(old_ic_data.raw()); | 151 isolate->set_ic_data_array(old_ic_data.raw()); |
| 130 return true; | 152 return true; |
| 131 } else { | 153 } else { |
| 132 Error& error = Error::Handle(); | 154 Error& error = Error::Handle(); |
| 133 error = isolate->object_store()->sticky_error(); | 155 error = isolate->object_store()->sticky_error(); |
| 134 isolate->object_store()->clear_sticky_error(); | 156 isolate->object_store()->clear_sticky_error(); |
| 135 isolate->set_long_jump_base(base); | 157 isolate->set_long_jump_base(base); |
| 158 isolate->set_deopt_id(prev_deopt_id); | |
| 136 isolate->set_ic_data_array(old_ic_data.raw()); | 159 isolate->set_ic_data_array(old_ic_data.raw()); |
| 137 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); | 160 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); |
| 138 return false; | 161 return false; |
| 139 } | 162 } |
| 140 } | 163 } |
| 141 | 164 |
| 142 void VisitClosureCall(ClosureCallInstr* call) { | 165 void VisitClosureCall(ClosureCallInstr* call) { |
| 143 TRACE_INLINING(OS::Print(" ClosureCall\n")); | 166 TRACE_INLINING(OS::Print(" ClosureCall\n")); |
| 144 // Find the closure of the callee. | 167 // Find the closure of the callee. |
| 145 ASSERT(call->ArgumentCount() > 0); | 168 ASSERT(call->ArgumentCount() > 0); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 192 | 215 |
| 193 | 216 |
| 194 void FlowGraphInliner::Inline() { | 217 void FlowGraphInliner::Inline() { |
| 195 if ((FLAG_inlining_filter != NULL) && | 218 if ((FLAG_inlining_filter != NULL) && |
| 196 (strstr(flow_graph_-> | 219 (strstr(flow_graph_-> |
| 197 parsed_function().function().ToFullyQualifiedCString(), | 220 parsed_function().function().ToFullyQualifiedCString(), |
| 198 FLAG_inlining_filter) == NULL)) { | 221 FLAG_inlining_filter) == NULL)) { |
| 199 return; | 222 return; |
| 200 } | 223 } |
| 201 | 224 |
| 225 TRACE_INLINING(OS::Print( | |
| 226 "Inlining calls in %s\n", | |
| 227 flow_graph_->parsed_function().function().ToCString())); | |
| 228 | |
| 202 if (FLAG_trace_inlining && FLAG_print_flow_graph) { | 229 if (FLAG_trace_inlining && FLAG_print_flow_graph) { |
| 203 OS::Print("Before Inlining of %s\n", flow_graph_-> | 230 OS::Print("Before Inlining of %s\n", flow_graph_-> |
| 204 parsed_function().function().ToFullyQualifiedCString()); | 231 parsed_function().function().ToFullyQualifiedCString()); |
| 205 FlowGraphPrinter printer(*flow_graph_); | 232 FlowGraphPrinter printer(*flow_graph_); |
| 206 printer.PrintBlocks(); | 233 printer.PrintBlocks(); |
| 207 } | 234 } |
| 208 | 235 |
| 209 TRACE_INLINING(OS::Print( | |
| 210 "Inlining calls in %s\n", | |
| 211 flow_graph_->parsed_function().function().ToCString())); | |
| 212 CallSiteInliner inliner(flow_graph_); | 236 CallSiteInliner inliner(flow_graph_); |
| 213 inliner.VisitBlocks(); | 237 inliner.VisitBlocks(); |
| 214 | 238 |
| 215 if (inliner.inlined()) { | 239 if (inliner.inlined()) { |
| 216 if (FLAG_trace_inlining && FLAG_print_flow_graph) { | 240 if (FLAG_trace_inlining && FLAG_print_flow_graph) { |
| 217 OS::Print("After Inlining of %s\n", flow_graph_-> | 241 OS::Print("After Inlining of %s\n", flow_graph_-> |
| 218 parsed_function().function().ToFullyQualifiedCString()); | 242 parsed_function().function().ToFullyQualifiedCString()); |
| 219 FlowGraphPrinter printer(*flow_graph_); | 243 FlowGraphPrinter printer(*flow_graph_); |
| 220 printer.PrintBlocks(); | 244 printer.PrintBlocks(); |
| 221 } | 245 } |
| 222 } | 246 } |
| 223 } | 247 } |
| 224 | 248 |
| 225 } // namespace dart | 249 } // namespace dart |
| OLD | NEW |