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

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
« no previous file with comments | « runtime/vm/flow_graph_builder.cc ('k') | runtime/vm/il_printer.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 if (call->function().is_inlinable()) 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 inlinable bit on the function is low. 72 // Abort if the inlinable bit on the function is low.
45 if (!function.is_inlinable()) { 73 if (!function.is_inlinable()) {
46 TRACE_INLINING(OS::Print(" Bailout: not inlinable\n")); 74 TRACE_INLINING(OS::Print(" Bailout: not inlinable\n"));
47 return false; 75 return false;
48 } 76 }
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 if ((function.deoptimization_counter() < 112 if ((function.deoptimization_counter() <
85 FLAG_deoptimization_counter_threshold) && 113 FLAG_deoptimization_counter_threshold) &&
86 function.HasCode()) { 114 function.HasCode()) {
87 const Code& unoptimized_code = 115 const Code& unoptimized_code =
88 Code::Handle(function.unoptimized_code()); 116 Code::Handle(function.unoptimized_code());
89 isolate->set_ic_data_array(unoptimized_code.ExtractTypeFeedbackArray()); 117 isolate->set_ic_data_array(unoptimized_code.ExtractTypeFeedbackArray());
90 } 118 }
91 119
92 // Build the callee graph. 120 // Build the callee graph.
93 FlowGraphBuilder builder(parsed_function); 121 FlowGraphBuilder builder(parsed_function);
122 builder.SetInitialBlockId(caller_graph_->max_block_id());
94 FlowGraph* callee_graph = 123 FlowGraph* callee_graph =
95 builder.BuildGraph(FlowGraphBuilder::kValueContext); 124 builder.BuildGraph(FlowGraphBuilder::kValueContext);
96 125
97 // Abort if the callee graph contains control flow.
98 if (callee_graph->preorder().length() != 2) {
99 function.set_is_inlinable(false);
100 isolate->set_long_jump_base(base);
101 isolate->set_ic_data_array(prev_ic_data.raw());
102 TRACE_INLINING(OS::Print(" Bailout: control flow\n"));
103 return false;
104 }
105
106 // Compute SSA on the callee graph, catching bailouts. 126 // Compute SSA on the callee graph, catching bailouts.
107 callee_graph->ComputeSSA(next_ssa_temp_index_); 127 callee_graph->ComputeSSA(next_ssa_temp_index_);
108 callee_graph->ComputeUseLists(); 128 callee_graph->ComputeUseLists();
109 129
110 // TODO(zerny): Do more optimization passes on the callee graph. 130 // TODO(zerny): Do more optimization passes on the callee graph.
111 FlowGraphOptimizer optimizer(callee_graph); 131 FlowGraphOptimizer optimizer(callee_graph);
112 optimizer.ApplyICData(); 132 optimizer.ApplyICData();
113 callee_graph->ComputeUseLists(); 133 callee_graph->ComputeUseLists();
114 134
115 if (FLAG_trace_inlining && FLAG_print_flow_graph) { 135 if (FLAG_trace_inlining && FLAG_print_flow_graph) {
116 OS::Print("Callee graph for inlining %s\n", 136 OS::Print("Callee graph for inlining %s\n",
117 parsed_function.function().ToFullyQualifiedCString()); 137 parsed_function.function().ToFullyQualifiedCString());
118 FlowGraphPrinter printer(*callee_graph); 138 FlowGraphPrinter printer(*callee_graph);
119 printer.PrintBlocks(); 139 printer.PrintBlocks();
120 } 140 }
121 141
122 // TODO(zerny): If result is more than size threshold then abort. 142 // TODO(zerny): If result is more than size threshold then abort.
123 143
124 // TODO(zerny): If effort is less than threshold then inline recursively. 144 // TODO(zerny): If effort is less than threshold then inline recursively.
125 145
126 // Plug result in the caller graph. 146 // Plug result in the caller graph.
127 caller_graph_->InlineCall(call, callee_graph); 147 caller_graph_->InlineCall(call, callee_graph);
128 next_ssa_temp_index_ = caller_graph_->max_virtual_register_number(); 148 next_ssa_temp_index_ = caller_graph_->max_virtual_register_number();
129 149
130 // Check that inlining maintains use lists.
131 DEBUG_ASSERT(caller_graph_->ValidateUseLists());
132
133 // Remove push arguments of the call. 150 // Remove push arguments of the call.
134 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { 151 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
135 PushArgumentInstr* push = call->ArgumentAt(i); 152 PushArgumentInstr* push = call->ArgumentAt(i);
136 push->ReplaceUsesWith(push->value()->definition()); 153 push->ReplaceUsesWith(push->value()->definition());
137 push->RemoveFromGraph(); 154 push->RemoveFromGraph();
138 } 155 }
139 156
140 // Replace formal parameters with actuals. 157 // Replace formal parameters with actuals.
141 intptr_t arg_index = 0; 158 intptr_t arg_index = 0;
142 GrowableArray<Definition*>* defns = 159 GrowableArray<Definition*>* defns =
143 callee_graph->graph_entry()->initial_definitions(); 160 callee_graph->graph_entry()->initial_definitions();
144 for (intptr_t i = 0; i < defns->length(); ++i) { 161 for (intptr_t i = 0; i < defns->length(); ++i) {
145 ParameterInstr* param = (*defns)[i]->AsParameter(); 162 ParameterInstr* param = (*defns)[i]->AsParameter();
146 if (param != NULL) { 163 if (param != NULL) {
147 param->ReplaceUsesWith((*arguments)[arg_index++]->definition()); 164 param->ReplaceUsesWith((*arguments)[arg_index++]->definition());
148 } 165 }
149 } 166 }
150 ASSERT(arg_index == arguments->length()); 167 ASSERT(arg_index == arguments->length());
151 168
152 // Replace callee's null constant with caller's null constant. 169 // Replace callee's null constant with caller's null constant.
153 callee_graph->graph_entry()->constant_null()->ReplaceUsesWith( 170 callee_graph->graph_entry()->constant_null()->ReplaceUsesWith(
154 caller_graph_->graph_entry()->constant_null()); 171 caller_graph_->graph_entry()->constant_null());
155 172
156 TRACE_INLINING(OS::Print(" Success\n")); 173 TRACE_INLINING(OS::Print(" Success\n"));
157 174
175 // Check that inlining maintains use lists.
176 DEBUG_ASSERT(caller_graph_->ValidateUseLists());
177
158 // Build succeeded so we restore the bailout jump. 178 // Build succeeded so we restore the bailout jump.
159 inlined_ = true; 179 inlined_ = true;
160 isolate->set_long_jump_base(base); 180 isolate->set_long_jump_base(base);
161 isolate->set_deopt_id(prev_deopt_id); 181 isolate->set_deopt_id(prev_deopt_id);
162 isolate->set_ic_data_array(prev_ic_data.raw()); 182 isolate->set_ic_data_array(prev_ic_data.raw());
163 return true; 183 return true;
164 } else { 184 } else {
165 Error& error = Error::Handle(); 185 Error& error = Error::Handle();
166 error = isolate->object_store()->sticky_error(); 186 error = isolate->object_store()->sticky_error();
167 isolate->object_store()->clear_sticky_error(); 187 isolate->object_store()->clear_sticky_error();
168 isolate->set_long_jump_base(base); 188 isolate->set_long_jump_base(base);
169 isolate->set_deopt_id(prev_deopt_id); 189 isolate->set_deopt_id(prev_deopt_id);
170 isolate->set_ic_data_array(prev_ic_data.raw()); 190 isolate->set_ic_data_array(prev_ic_data.raw());
171 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); 191 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString()));
172 return false; 192 return false;
173 } 193 }
174 } 194 }
175 195
176 void VisitClosureCall(ClosureCallInstr* call) { 196 void InlineStaticCalls() {
177 TRACE_INLINING(OS::Print(" ClosureCall\n")); 197 TRACE_INLINING(OS::Print(" Static Calls (%d)\n",
178 // Find the closure of the callee. 198 static_calls_.length()));
179 ASSERT(call->ArgumentCount() > 0); 199 for (intptr_t i = 0; i < static_calls_.length(); ++i) {
180 const CreateClosureInstr* closure = 200 StaticCallInstr* call = static_calls_[i];
181 call->ArgumentAt(0)->value()->definition()->AsCreateClosure(); 201 GrowableArray<Value*> arguments(call->ArgumentCount());
182 if (closure == NULL) { 202 for (int i = 0; i < call->ArgumentCount(); ++i) {
183 TRACE_INLINING(OS::Print(" Bailout: non-closure operator\n")); 203 arguments.Add(call->ArgumentAt(i)->value());
184 return; 204 }
205 TryInlining(call->function(), &arguments, call);
185 } 206 }
186 GrowableArray<Value*> arguments(call->ArgumentCount() - 1);
187 for (int i = 1; i < call->ArgumentCount(); ++i) {
188 arguments.Add(call->ArgumentAt(i)->value());
189 }
190 TryInlining(closure->function(), &arguments, call);
191 } 207 }
192 208
193 void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr* instr) { 209 void InlineClosureCalls() {
194 TRACE_INLINING(OS::Print(" PolymorphicInstanceCall\n")); 210 TRACE_INLINING(OS::Print(" Closure Calls (%d)\n",
195 const ICData& ic_data = instr->ic_data(); 211 closure_calls_.length()));
196 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); 212 for (intptr_t i = 0; i < closure_calls_.length(); ++i) {
197 if (instr->with_checks()) { 213 ClosureCallInstr* call = closure_calls_[i];
198 TRACE_INLINING(OS::Print(" Bailout: %"Pd" checks target '%s'\n", 214 // Find the closure of the callee.
199 ic_data.NumberOfChecks(), 215 ASSERT(call->ArgumentCount() > 0);
200 target.ToCString())); 216 const CreateClosureInstr* closure =
201 return; 217 call->ArgumentAt(0)->value()->definition()->AsCreateClosure();
218 if (closure == NULL) {
219 TRACE_INLINING(OS::Print(" Bailout: non-closure operator\n"));
220 continue;
221 }
222 GrowableArray<Value*> arguments(call->ArgumentCount() - 1);
223 for (int i = 1; i < call->ArgumentCount(); ++i) {
224 arguments.Add(call->ArgumentAt(i)->value());
225 }
226 TryInlining(closure->function(), &arguments, call);
202 } 227 }
203
204 GrowableArray<Value*> arguments(instr->ArgumentCount());
205 for (int i = 0; i < instr->ArgumentCount(); ++i) {
206 arguments.Add(instr->ArgumentAt(i)->value());
207 }
208
209 TryInlining(target, &arguments, instr);
210 } 228 }
211 229
212 void VisitStaticCall(StaticCallInstr* call) { 230 void InlineInstanceCalls() {
213 TRACE_INLINING(OS::Print(" StaticCall\n")); 231 TRACE_INLINING(OS::Print(" Polymorphic Instance Calls (%d)\n",
214 GrowableArray<Value*> arguments(call->ArgumentCount()); 232 instance_calls_.length()));
215 for (int i = 0; i < call->ArgumentCount(); ++i) { 233 for (intptr_t i = 0; i < instance_calls_.length(); ++i) {
216 arguments.Add(call->ArgumentAt(i)->value()); 234 PolymorphicInstanceCallInstr* instr = instance_calls_[i];
235 const ICData& ic_data = instr->ic_data();
236 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
237 if (instr->with_checks()) {
238 TRACE_INLINING(OS::Print(" Bailout: %"Pd" checks target '%s'\n",
239 ic_data.NumberOfChecks(),
240 target.ToCString()));
241 continue;
242 }
243 GrowableArray<Value*> arguments(instr->ArgumentCount());
244 for (int i = 0; i < instr->ArgumentCount(); ++i) {
245 arguments.Add(instr->ArgumentAt(i)->value());
246 }
247 TryInlining(target, &arguments, instr);
217 } 248 }
218 TryInlining(call->function(), &arguments, call);
219 } 249 }
220 250
221 bool inlined() const { return inlined_; }
222
223 private:
224 FlowGraph* caller_graph_; 251 FlowGraph* caller_graph_;
225 intptr_t next_ssa_temp_index_; 252 intptr_t next_ssa_temp_index_;
226 bool inlined_; 253 bool inlined_;
254
255 GrowableArray<StaticCallInstr*> static_calls_;
256 GrowableArray<ClosureCallInstr*> closure_calls_;
257 GrowableArray<PolymorphicInstanceCallInstr*> instance_calls_;
227 }; 258 };
228 259
229 260
230 void FlowGraphInliner::Inline() { 261 void FlowGraphInliner::Inline() {
231 if ((FLAG_inlining_filter != NULL) && 262 if ((FLAG_inlining_filter != NULL) &&
232 (strstr(flow_graph_-> 263 (strstr(flow_graph_->
233 parsed_function().function().ToFullyQualifiedCString(), 264 parsed_function().function().ToFullyQualifiedCString(),
234 FLAG_inlining_filter) == NULL)) { 265 FLAG_inlining_filter) == NULL)) {
235 return; 266 return;
236 } 267 }
237 268
238 TRACE_INLINING(OS::Print( 269 TRACE_INLINING(OS::Print(
239 "Inlining calls in %s\n", 270 "Inlining calls in %s\n",
240 flow_graph_->parsed_function().function().ToCString())); 271 flow_graph_->parsed_function().function().ToCString()));
241 272
242 if (FLAG_trace_inlining && FLAG_print_flow_graph) { 273 if (FLAG_trace_inlining && FLAG_print_flow_graph) {
243 OS::Print("Before Inlining of %s\n", flow_graph_-> 274 OS::Print("Before Inlining of %s\n", flow_graph_->
244 parsed_function().function().ToFullyQualifiedCString()); 275 parsed_function().function().ToFullyQualifiedCString());
245 FlowGraphPrinter printer(*flow_graph_); 276 FlowGraphPrinter printer(*flow_graph_);
246 printer.PrintBlocks(); 277 printer.PrintBlocks();
247 } 278 }
248 279
249 CallSiteInliner inliner(flow_graph_); 280 CallSiteInliner inliner(flow_graph_);
250 inliner.VisitBlocks(); 281 inliner.FindCallSites();
282 inliner.InlineCalls();
251 283
252 if (inliner.inlined()) { 284 if (inliner.inlined()) {
253 if (FLAG_trace_inlining && FLAG_print_flow_graph) { 285 if (FLAG_trace_inlining && FLAG_print_flow_graph) {
254 OS::Print("After Inlining of %s\n", flow_graph_-> 286 OS::Print("After Inlining of %s\n", flow_graph_->
255 parsed_function().function().ToFullyQualifiedCString()); 287 parsed_function().function().ToFullyQualifiedCString());
256 FlowGraphPrinter printer(*flow_graph_); 288 FlowGraphPrinter printer(*flow_graph_);
257 printer.PrintBlocks(); 289 printer.PrintBlocks();
258 } 290 }
259 } 291 }
260 } 292 }
261 293
262 } // namespace dart 294 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_builder.cc ('k') | runtime/vm/il_printer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698