Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(397)

Side by Side Diff: runtime/vm/flow_graph_inliner.cc

Issue 10967007: Inlining functions with control flow. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/compiler.h"
8 #include "vm/flags.h" 8 #include "vm/flags.h"
9 #include "vm/flow_graph.h" 9 #include "vm/flow_graph.h"
10 #include "vm/flow_graph_builder.h" 10 #include "vm/flow_graph_builder.h"
(...skipping 16 matching lines...) Expand all
27 if (FLAG_trace_inlining) statement; \ 27 if (FLAG_trace_inlining) statement; \
28 } while (false) 28 } while (false)
29 29
30 30
31 class CallSiteInliner : public FlowGraphVisitor { 31 class CallSiteInliner : public FlowGraphVisitor {
32 public: 32 public:
33 explicit CallSiteInliner(FlowGraph* flow_graph) 33 explicit CallSiteInliner(FlowGraph* flow_graph)
34 : FlowGraphVisitor(flow_graph->postorder()), 34 : FlowGraphVisitor(flow_graph->postorder()),
35 caller_graph_(flow_graph), 35 caller_graph_(flow_graph),
36 next_ssa_temp_index_(flow_graph->max_virtual_register_number()), 36 next_ssa_temp_index_(flow_graph->max_virtual_register_number()),
37 inlined_(false) { } 37 inlined_(false),
38 static_calls_(),
39 closure_calls_(),
40 instance_calls_() { }
38 41
42 void VisitClosureCall(ClosureCallInstr* call) {
43 closure_calls_.Add(call);
44 }
45
46 void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr* call) {
47 instance_calls_.Add(call);
48 }
49
50 void VisitStaticCall(StaticCallInstr* call) {
51 static_calls_.Add(call);
52 }
53
54 void FindCallSites() {
55 VisitBlocks();
56 }
57
58 void InlineCalls() {
59 InlineStaticCalls();
60 InlineClosureCalls();
61 InlineInstanceCalls();
62 }
63
64 bool inlined() const { return inlined_; }
65
66 private:
39 bool TryInlining(const Function& function, 67 bool TryInlining(const Function& function,
40 GrowableArray<Value*>* arguments, 68 GrowableArray<Value*>* arguments,
41 Definition* call) { 69 Definition* call) {
42 TRACE_INLINING(OS::Print(" => %s\n", function.ToCString())); 70 TRACE_INLINING(OS::Print(" => %s\n", function.ToCString()));
43 71
44 // Abort if the callee has optional parameters. 72 // Abort if the callee has optional parameters.
45 if (function.HasOptionalParameters()) { 73 if (function.HasOptionalParameters()) {
46 TRACE_INLINING(OS::Print(" Bailout: optional parameters\n")); 74 TRACE_INLINING(OS::Print(" Bailout: optional parameters\n"));
47 return false; 75 return false;
48 } 76 }
(...skipping 28 matching lines...) Expand all
77 if ((function.deoptimization_counter() < 105 if ((function.deoptimization_counter() <
78 FLAG_deoptimization_counter_threshold) && 106 FLAG_deoptimization_counter_threshold) &&
79 function.HasCode()) { 107 function.HasCode()) {
80 const Code& unoptimized_code = 108 const Code& unoptimized_code =
81 Code::Handle(function.unoptimized_code()); 109 Code::Handle(function.unoptimized_code());
82 isolate->set_ic_data_array(unoptimized_code.ExtractTypeFeedbackArray()); 110 isolate->set_ic_data_array(unoptimized_code.ExtractTypeFeedbackArray());
83 } 111 }
84 112
85 // Build the callee graph. 113 // Build the callee graph.
86 FlowGraphBuilder builder(parsed_function); 114 FlowGraphBuilder builder(parsed_function);
115 builder.SetInitialBlockId(caller_graph_->max_block_id());
87 FlowGraph* callee_graph = 116 FlowGraph* callee_graph =
88 builder.BuildGraph(FlowGraphBuilder::kValueContext); 117 builder.BuildGraph(FlowGraphBuilder::kValueContext);
89 118
90 // Abort if the callee graph contains control flow.
91 if (callee_graph->preorder().length() != 2) {
92 isolate->set_long_jump_base(base);
93 isolate->set_ic_data_array(prev_ic_data.raw());
94 TRACE_INLINING(OS::Print(" Bailout: control flow\n"));
95 return false;
96 }
97
98 // Compute SSA on the callee graph, catching bailouts. 119 // Compute SSA on the callee graph, catching bailouts.
99 callee_graph->ComputeSSA(next_ssa_temp_index_); 120 callee_graph->ComputeSSA(next_ssa_temp_index_);
100 callee_graph->ComputeUseLists(); 121 callee_graph->ComputeUseLists();
101 122
102 // TODO(zerny): Do more optimization passes on the callee graph. 123 // TODO(zerny): Do more optimization passes on the callee graph.
103 FlowGraphOptimizer optimizer(callee_graph); 124 FlowGraphOptimizer optimizer(callee_graph);
104 optimizer.ApplyICData(); 125 optimizer.ApplyICData();
105 callee_graph->ComputeUseLists(); 126 callee_graph->ComputeUseLists();
106 127
107 if (FLAG_trace_inlining && FLAG_print_flow_graph) { 128 if (FLAG_trace_inlining && FLAG_print_flow_graph) {
108 OS::Print("Callee graph for inlining %s\n", 129 OS::Print("Callee graph for inlining %s\n",
109 parsed_function.function().ToFullyQualifiedCString()); 130 parsed_function.function().ToFullyQualifiedCString());
110 FlowGraphPrinter printer(*callee_graph); 131 FlowGraphPrinter printer(*callee_graph);
111 printer.PrintBlocks(); 132 printer.PrintBlocks();
112 } 133 }
113 134
114 // TODO(zerny): If result is more than size threshold then abort. 135 // TODO(zerny): If result is more than size threshold then abort.
115 136
116 // TODO(zerny): If effort is less than threshold then inline recursively. 137 // TODO(zerny): If effort is less than threshold then inline recursively.
117 138
118 // Plug result in the caller graph. 139 // Plug result in the caller graph.
119 caller_graph_->InlineCall(call, callee_graph); 140 caller_graph_->InlineCall(call, callee_graph);
120 next_ssa_temp_index_ = caller_graph_->max_virtual_register_number(); 141 next_ssa_temp_index_ = caller_graph_->max_virtual_register_number();
121 142
122 // Check that inlining maintains use lists.
123 DEBUG_ASSERT(caller_graph_->ValidateUseLists());
124
125 // Remove push arguments of the call. 143 // Remove push arguments of the call.
126 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { 144 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
127 PushArgumentInstr* push = call->ArgumentAt(i); 145 PushArgumentInstr* push = call->ArgumentAt(i);
128 push->ReplaceUsesWith(push->value()->definition()); 146 push->ReplaceUsesWith(push->value()->definition());
129 push->RemoveFromGraph(); 147 push->RemoveFromGraph();
130 } 148 }
131 149
132 // Replace formal parameters with actuals. 150 // Replace formal parameters with actuals.
133 intptr_t arg_index = 0; 151 intptr_t arg_index = 0;
134 GrowableArray<Definition*>* defns = 152 GrowableArray<Definition*>* defns =
135 callee_graph->graph_entry()->initial_definitions(); 153 callee_graph->graph_entry()->initial_definitions();
136 for (intptr_t i = 0; i < defns->length(); ++i) { 154 for (intptr_t i = 0; i < defns->length(); ++i) {
137 ParameterInstr* param = (*defns)[i]->AsParameter(); 155 ParameterInstr* param = (*defns)[i]->AsParameter();
138 if (param != NULL) { 156 if (param != NULL) {
139 param->ReplaceUsesWith((*arguments)[arg_index++]->definition()); 157 param->ReplaceUsesWith((*arguments)[arg_index++]->definition());
140 } 158 }
141 } 159 }
142 ASSERT(arg_index == arguments->length()); 160 ASSERT(arg_index == arguments->length());
143 161
144 // Replace callee's null constant with caller's null constant. 162 // Replace callee's null constant with caller's null constant.
145 callee_graph->graph_entry()->constant_null()->ReplaceUsesWith( 163 callee_graph->graph_entry()->constant_null()->ReplaceUsesWith(
146 caller_graph_->graph_entry()->constant_null()); 164 caller_graph_->graph_entry()->constant_null());
147 165
148 TRACE_INLINING(OS::Print(" Success\n")); 166 TRACE_INLINING(OS::Print(" Success\n"));
149 167
168 // Check that inlining maintains use lists.
169 DEBUG_ASSERT(caller_graph_->ValidateUseLists());
170
150 // Build succeeded so we restore the bailout jump. 171 // Build succeeded so we restore the bailout jump.
151 inlined_ = true; 172 inlined_ = true;
152 isolate->set_long_jump_base(base); 173 isolate->set_long_jump_base(base);
153 isolate->set_deopt_id(prev_deopt_id); 174 isolate->set_deopt_id(prev_deopt_id);
154 isolate->set_ic_data_array(prev_ic_data.raw()); 175 isolate->set_ic_data_array(prev_ic_data.raw());
155 return true; 176 return true;
156 } else { 177 } else {
157 Error& error = Error::Handle(); 178 Error& error = Error::Handle();
158 error = isolate->object_store()->sticky_error(); 179 error = isolate->object_store()->sticky_error();
159 isolate->object_store()->clear_sticky_error(); 180 isolate->object_store()->clear_sticky_error();
160 isolate->set_long_jump_base(base); 181 isolate->set_long_jump_base(base);
161 isolate->set_deopt_id(prev_deopt_id); 182 isolate->set_deopt_id(prev_deopt_id);
162 isolate->set_ic_data_array(prev_ic_data.raw()); 183 isolate->set_ic_data_array(prev_ic_data.raw());
163 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); 184 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString()));
164 return false; 185 return false;
165 } 186 }
166 } 187 }
167 188
168 void VisitClosureCall(ClosureCallInstr* call) { 189 void InlineStaticCalls() {
169 TRACE_INLINING(OS::Print(" ClosureCall\n")); 190 TRACE_INLINING(OS::Print(" Static Calls (%d)\n",
170 // Find the closure of the callee. 191 static_calls_.length()));
171 ASSERT(call->ArgumentCount() > 0); 192 for (intptr_t i = 0; i < static_calls_.length(); ++i) {
172 const CreateClosureInstr* closure = 193 StaticCallInstr* call = static_calls_[i];
173 call->ArgumentAt(0)->value()->definition()->AsCreateClosure(); 194 GrowableArray<Value*> arguments(call->ArgumentCount());
174 if (closure == NULL) { 195 for (int i = 0; i < call->ArgumentCount(); ++i) {
175 TRACE_INLINING(OS::Print(" Bailout: non-closure operator\n")); 196 arguments.Add(call->ArgumentAt(i)->value());
176 return; 197 }
198 TryInlining(call->function(), &arguments, call);
177 } 199 }
178 GrowableArray<Value*> arguments(call->ArgumentCount() - 1);
179 for (int i = 1; i < call->ArgumentCount(); ++i) {
180 arguments.Add(call->ArgumentAt(i)->value());
181 }
182 TryInlining(closure->function(), &arguments, call);
183 } 200 }
184 201
185 void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr* instr) { 202 void InlineClosureCalls() {
186 TRACE_INLINING(OS::Print(" PolymorphicInstanceCall\n")); 203 TRACE_INLINING(OS::Print(" Closure Calls (%d)\n",
187 if (instr->with_checks()) { 204 closure_calls_.length()));
188 TRACE_INLINING(OS::Print(" Bailout: checks\n")); 205 for (intptr_t i = 0; i < closure_calls_.length(); ++i) {
189 return; 206 ClosureCallInstr* call = closure_calls_[i];
207 // Find the closure of the callee.
208 ASSERT(call->ArgumentCount() > 0);
209 const CreateClosureInstr* closure =
210 call->ArgumentAt(0)->value()->definition()->AsCreateClosure();
211 if (closure == NULL) {
212 TRACE_INLINING(OS::Print(" Bailout: non-closure operator\n"));
213 return;
214 }
215 GrowableArray<Value*> arguments(call->ArgumentCount() - 1);
216 for (int i = 1; i < call->ArgumentCount(); ++i) {
217 arguments.Add(call->ArgumentAt(i)->value());
218 }
219 TryInlining(closure->function(), &arguments, call);
190 } 220 }
191 const ICData& ic_data = instr->ic_data();
192 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
193
194 GrowableArray<Value*> arguments(instr->ArgumentCount());
195 for (int i = 0; i < instr->ArgumentCount(); ++i) {
196 arguments.Add(instr->ArgumentAt(i)->value());
197 }
198
199 TryInlining(target, &arguments, instr);
200 } 221 }
201 222
202 void VisitStaticCall(StaticCallInstr* call) { 223 void InlineInstanceCalls() {
203 TRACE_INLINING(OS::Print(" StaticCall\n")); 224 TRACE_INLINING(OS::Print(" Polymorphic Instance Calls (%d)\n",
204 GrowableArray<Value*> arguments(call->ArgumentCount()); 225 instance_calls_.length()));
205 for (int i = 0; i < call->ArgumentCount(); ++i) { 226 for (intptr_t i = 0; i < instance_calls_.length(); ++i) {
206 arguments.Add(call->ArgumentAt(i)->value()); 227 PolymorphicInstanceCallInstr* instr = instance_calls_[i];
228 if (instr->with_checks()) {
229 TRACE_INLINING(OS::Print(" Bailout: checks\n"));
230 continue;
231 }
232 const ICData& ic_data = instr->ic_data();
233 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
234 GrowableArray<Value*> arguments(instr->ArgumentCount());
235 for (int i = 0; i < instr->ArgumentCount(); ++i) {
236 arguments.Add(instr->ArgumentAt(i)->value());
237 }
238 TryInlining(target, &arguments, instr);
207 } 239 }
208 TryInlining(call->function(), &arguments, call);
209 } 240 }
210 241
211 bool inlined() const { return inlined_; }
212
213 private:
214 FlowGraph* caller_graph_; 242 FlowGraph* caller_graph_;
215 intptr_t next_ssa_temp_index_; 243 intptr_t next_ssa_temp_index_;
216 bool inlined_; 244 bool inlined_;
245
246 GrowableArray<StaticCallInstr*> static_calls_;
247 GrowableArray<ClosureCallInstr*> closure_calls_;
248 GrowableArray<PolymorphicInstanceCallInstr*> instance_calls_;
217 }; 249 };
218 250
219 251
220 void FlowGraphInliner::Inline() { 252 void FlowGraphInliner::Inline() {
221 if ((FLAG_inlining_filter != NULL) && 253 if ((FLAG_inlining_filter != NULL) &&
222 (strstr(flow_graph_-> 254 (strstr(flow_graph_->
223 parsed_function().function().ToFullyQualifiedCString(), 255 parsed_function().function().ToFullyQualifiedCString(),
224 FLAG_inlining_filter) == NULL)) { 256 FLAG_inlining_filter) == NULL)) {
225 return; 257 return;
226 } 258 }
227 259
228 TRACE_INLINING(OS::Print( 260 TRACE_INLINING(OS::Print(
229 "Inlining calls in %s\n", 261 "Inlining calls in %s\n",
230 flow_graph_->parsed_function().function().ToCString())); 262 flow_graph_->parsed_function().function().ToCString()));
231 263
232 if (FLAG_trace_inlining && FLAG_print_flow_graph) { 264 if (FLAG_trace_inlining && FLAG_print_flow_graph) {
233 OS::Print("Before Inlining of %s\n", flow_graph_-> 265 OS::Print("Before Inlining of %s\n", flow_graph_->
234 parsed_function().function().ToFullyQualifiedCString()); 266 parsed_function().function().ToFullyQualifiedCString());
235 FlowGraphPrinter printer(*flow_graph_); 267 FlowGraphPrinter printer(*flow_graph_);
236 printer.PrintBlocks(); 268 printer.PrintBlocks();
237 } 269 }
238 270
239 CallSiteInliner inliner(flow_graph_); 271 CallSiteInliner inliner(flow_graph_);
240 inliner.VisitBlocks(); 272 inliner.FindCallSites();
273 inliner.InlineCalls();
241 274
242 if (inliner.inlined()) { 275 if (inliner.inlined()) {
243 if (FLAG_trace_inlining && FLAG_print_flow_graph) { 276 if (FLAG_trace_inlining && FLAG_print_flow_graph) {
244 OS::Print("After Inlining of %s\n", flow_graph_-> 277 OS::Print("After Inlining of %s\n", flow_graph_->
245 parsed_function().function().ToFullyQualifiedCString()); 278 parsed_function().function().ToFullyQualifiedCString());
246 FlowGraphPrinter printer(*flow_graph_); 279 FlowGraphPrinter printer(*flow_graph_);
247 printer.PrintBlocks(); 280 printer.PrintBlocks();
248 } 281 }
249 } 282 }
250 } 283 }
251 284
252 } // namespace dart 285 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698