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

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

Issue 10913010: Inlining monomorphic calls. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 3 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/intermediate_language.h » ('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/flags.h" 7 #include "vm/flags.h"
8 #include "vm/flow_graph.h" 8 #include "vm/flow_graph.h"
9 #include "vm/flow_graph_builder.h" 9 #include "vm/flow_graph_builder.h"
10 #include "vm/il_printer.h" 10 #include "vm/il_printer.h"
11 #include "vm/longjump.h" 11 #include "vm/longjump.h"
12 #include "vm/object.h" 12 #include "vm/object.h"
13 #include "vm/object_store.h" 13 #include "vm/object_store.h"
14 14
15 namespace dart { 15 namespace dart {
16 16
17 DEFINE_FLAG(bool, trace_inlining, false, "Trace inlining"); 17 DEFINE_FLAG(bool, trace_inlining, false, "Trace inlining");
18 DEFINE_FLAG(charp, inlining_filter, NULL, "Inline only in named function"); 18 DEFINE_FLAG(charp, inlining_filter, NULL, "Inline only in named function");
19 DECLARE_FLAG(bool, print_flow_graph); 19 DECLARE_FLAG(bool, print_flow_graph);
20 20
21 class CallSiteInliner : public FlowGraphVisitor { 21 class CallSiteInliner : public FlowGraphVisitor {
22 public: 22 public:
23 explicit CallSiteInliner(FlowGraph* flow_graph) 23 explicit CallSiteInliner(FlowGraph* flow_graph)
24 : FlowGraphVisitor(flow_graph->postorder()), 24 : FlowGraphVisitor(flow_graph->postorder()),
25 caller_graph_(flow_graph), 25 caller_graph_(flow_graph),
26 next_ssa_temp_index_(flow_graph->max_virtual_register_number()), 26 next_ssa_temp_index_(flow_graph->max_virtual_register_number()),
27 inlined_(false) { } 27 inlined_(false) { }
28 28
29 void TryInlining(const Function& function, 29 bool TryInlining(const Function& function,
30 GrowableArray<Value*>* arguments, 30 GrowableArray<Value*>* arguments,
31 StaticCallInstr* call) { 31 Definition* call,
32 // TODO(zerny): Generalize to all calls. 32 Definition* check) {
33 if (FLAG_trace_inlining) {
34 OS::Print("--- %s\n", function.ToFullyQualifiedCString());
35 }
33 36
34 // Abort if the callee has optional parameters. 37 // Abort if the callee has named parameters.
35 if (function.HasOptionalParameters()) { 38 if (function.HasOptionalParameters()) {
36 if (FLAG_trace_inlining) { 39 if (FLAG_trace_inlining) {
37 OS::Print("Inline aborted %s\nReason: optional parameters\n", 40 OS::Print("Inline aborted %s\nReason: optional parameters\n",
38 function.ToFullyQualifiedCString()); 41 function.ToFullyQualifiedCString());
39 } 42 }
40 return; 43 return false;
41 } 44 }
42 45
43 // Assuming no optional parameters the actual/formal count should match. 46 // Assuming no optional parameters the actual/formal count should match.
44 ASSERT(arguments->length() == function.num_fixed_parameters()); 47 ASSERT(arguments->length() == function.num_fixed_parameters());
45 48
46 Isolate* isolate = Isolate::Current(); 49 Isolate* isolate = Isolate::Current();
47 // Save and clear IC data. 50 // Save and clear IC data.
48 const Array& old_ic_data = Array::Handle(isolate->ic_data_array()); 51 const Array& old_ic_data = Array::Handle(isolate->ic_data_array());
49 isolate->set_ic_data_array(Array::null()); 52 isolate->set_ic_data_array(Array::null());
50 // Install bailout jump. 53 // Install bailout jump.
51 LongJump* base = isolate->long_jump_base(); 54 LongJump* base = isolate->long_jump_base();
52 LongJump jump; 55 LongJump jump;
53 isolate->set_long_jump_base(&jump); 56 isolate->set_long_jump_base(&jump);
54 if (setjmp(*jump.Set()) == 0) { 57 if (setjmp(*jump.Set()) == 0) {
55 // Parse the callee function. 58 // Parse the callee function.
56 ParsedFunction parsed_function(function); 59 ParsedFunction parsed_function(function);
57 Parser::ParseFunction(&parsed_function); 60 Parser::ParseFunction(&parsed_function);
61 parsed_function.AllocateVariables();
58 FlowGraphBuilder builder(parsed_function); 62 FlowGraphBuilder builder(parsed_function);
59 63
60 // Build the callee graph. 64 // Build the callee graph.
61 FlowGraph* callee_graph = 65 FlowGraph* callee_graph =
62 builder.BuildGraphForInlining(FlowGraphBuilder::kValueContext); 66 builder.BuildGraph(FlowGraphBuilder::kValueContext);
63 67
64 // Abort if the callee graph contains control flow. 68 // Abort if the callee graph contains control flow.
65 if (callee_graph->preorder().length() != 2) { 69 if (callee_graph->preorder().length() != 2) {
66 isolate->set_long_jump_base(base); 70 isolate->set_long_jump_base(base);
67 isolate->set_ic_data_array(old_ic_data.raw()); 71 isolate->set_ic_data_array(old_ic_data.raw());
68 if (FLAG_trace_inlining) { 72 if (FLAG_trace_inlining) {
69 OS::Print("Inline aborted %s\nReason: control flow\n", 73 OS::Print("Inline aborted %s\nReason: control flow\n",
70 parsed_function.function().ToFullyQualifiedCString()); 74 parsed_function.function().ToFullyQualifiedCString());
71 } 75 }
72 return; 76 return false;
73 } 77 }
74 78
75 if (FLAG_trace_inlining && FLAG_print_flow_graph) { 79 if (FLAG_trace_inlining && FLAG_print_flow_graph) {
76 OS::Print("Callee graph before SSA %s\n", 80 OS::Print("Callee graph before SSA %s\n",
77 parsed_function.function().ToFullyQualifiedCString()); 81 parsed_function.function().ToFullyQualifiedCString());
78 FlowGraphPrinter printer(*callee_graph); 82 FlowGraphPrinter printer(*callee_graph);
79 printer.PrintBlocks(); 83 printer.PrintBlocks();
80 } 84 }
81 85
82 // Compute SSA on the callee graph. (catching bailouts) 86 // Compute SSA on the callee graph. (catching bailouts)
(...skipping 11 matching lines...) Expand all
94 // TODO(zerny): Do optimization passes on the callee graph. 98 // TODO(zerny): Do optimization passes on the callee graph.
95 99
96 // TODO(zerny): If result is more than size threshold then abort. 100 // TODO(zerny): If result is more than size threshold then abort.
97 101
98 // TODO(zerny): If effort is less than threshold then inline recursively. 102 // TODO(zerny): If effort is less than threshold then inline recursively.
99 103
100 // Plug result in the caller graph. 104 // Plug result in the caller graph.
101 caller_graph_->InlineCall(call, callee_graph); 105 caller_graph_->InlineCall(call, callee_graph);
102 next_ssa_temp_index_ = caller_graph_->max_virtual_register_number(); 106 next_ssa_temp_index_ = caller_graph_->max_virtual_register_number();
103 107
108 // Insert check if needed.
109 if (check != NULL) {
110 if (call->env() != NULL) call->env()->CopyTo(check);
111 check->InsertAfter(call->previous());
112 }
113
114 // Remove (all) push arguments of the call.
115 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
116 PushArgumentInstr* push = call->ArgumentAt(i);
117 push->ReplaceUsesWith(push->value()->definition());
118 push->RemoveFromGraph();
119 }
120
104 // Replace all the formal parameters with the actuals. 121 // Replace all the formal parameters with the actuals.
105 for (intptr_t i = 0; i < arguments->length(); ++i) { 122 for (intptr_t i = 0; i < arguments->length(); ++i) {
106 Value* val = callee_graph->graph_entry()->start_env()->values()[i]; 123 Value* val = callee_graph->graph_entry()->start_env()->values()[i];
107 ParameterInstr* param = val->definition()->AsParameter(); 124 ParameterInstr* param = val->definition()->AsParameter();
108 ASSERT(param != NULL); 125 ASSERT(param != NULL);
109 param->ReplaceUsesWith((*arguments)[i]->definition()); 126 param->ReplaceUsesWith((*arguments)[i]->definition());
110 } 127 }
111 128
129 // Replace callees null constant with callers null constant.
130 callee_graph->graph_entry()->constant_null()->ReplaceUsesWith(
131 caller_graph_->graph_entry()->constant_null());
132
112 if (FLAG_trace_inlining) { 133 if (FLAG_trace_inlining) {
113 OS::Print("Inlined %s\n", function.ToFullyQualifiedCString()); 134 OS::Print("Inlined %s\n", function.ToFullyQualifiedCString());
114 } 135 }
115 136
116 // Build succeeded so we restore the bailout jump. 137 // Build succeeded so we restore the bailout jump.
117 inlined_ = true; 138 inlined_ = true;
118 isolate->set_long_jump_base(base); 139 isolate->set_long_jump_base(base);
119 isolate->set_ic_data_array(old_ic_data.raw()); 140 isolate->set_ic_data_array(old_ic_data.raw());
141 return true;
120 } else { 142 } else {
121 Error& error = Error::Handle(); 143 Error& error = Error::Handle();
122 error = isolate->object_store()->sticky_error(); 144 error = isolate->object_store()->sticky_error();
123 isolate->object_store()->clear_sticky_error(); 145 isolate->object_store()->clear_sticky_error();
124 isolate->set_long_jump_base(base); 146 isolate->set_long_jump_base(base);
125 isolate->set_ic_data_array(old_ic_data.raw()); 147 isolate->set_ic_data_array(old_ic_data.raw());
126 if (FLAG_trace_inlining) { 148 if (FLAG_trace_inlining) {
127 OS::Print("Inline aborted for %s\nReason: %s\n", 149 OS::Print("Inline aborted for %s\nReason: %s\n",
128 function.ToFullyQualifiedCString(), 150 function.ToFullyQualifiedCString(),
129 error.ToErrorCString()); 151 error.ToErrorCString());
130 } 152 }
153 return false;
131 } 154 }
132 } 155 }
133 156
134 void VisitStaticCall(StaticCallInstr* instr) { 157 void VisitClosureCall(ClosureCallInstr* call) {
135 if (FLAG_trace_inlining) OS::Print("Static call\n"); 158 if (FLAG_trace_inlining) OS::Print("Closure call\n");
136 GrowableArray<Value*> arguments(instr->ArgumentCount()); 159 // Find the closure of the callee.
137 for (int i = 0; i < instr->ArgumentCount(); ++i) { 160 ASSERT(call->ArgumentCount() > 0);
138 arguments.Add(instr->ArgumentAt(i)->value()); 161 const CreateClosureInstr* closure =
162 call->ArgumentAt(0)->value()->definition()->AsCreateClosure();
163 if (closure == NULL) {
164 if (FLAG_trace_inlining) {
165 OS::Print("Inline aborted: non-closure operator.\n");
166 }
167 return;
139 } 168 }
140 TryInlining(instr->function(), &arguments, instr); 169 GrowableArray<Value*> arguments(call->ArgumentCount() - 1);
170 for (int i = 1; i < call->ArgumentCount(); ++i) {
171 arguments.Add(call->ArgumentAt(i)->value());
172 }
173 TryInlining(closure->function(), &arguments, call, NULL); // no check
141 } 174 }
142 175
143 bool preformed_inlining() const { return inlined_; } 176 void VisitInstanceCall(InstanceCallInstr* call) {
177 TryInliningInstanceCall(call, call);
178 }
179
180 // Needed since the instance call in a polymorphic instance call is not linked
181 // in the graph.
182 void TryInliningInstanceCall(InstanceCallInstr* call, Definition* call_defn) {
183 if (FLAG_trace_inlining) OS::Print("Instance call\n");
184 if (!call->HasICData()) {
185 if (FLAG_trace_inlining) OS::Print("Inline aborted: has no IC data\n");
186 return;
187 }
188 const ICData& ic_data = *call->ic_data();
189
190 ASSERT(ic_data.num_args_tested() > 0);
191
192 if (ic_data.NumberOfChecks() == 0) {
193 if (FLAG_trace_inlining) OS::Print("Inline aborted: no IC checks\n");
194 return;
195 }
196 if (ic_data.NumberOfChecks() != 1) {
197 // TODO(zerny): proceed if each check has the same cid?
198 if (FLAG_trace_inlining) OS::Print("Inline aborted: non monomorphic\n");
199 return;
200 }
201 GrowableArray<intptr_t> class_ids;
202 Function& target = Function::Handle();
203 ic_data.GetCheckAt(0, &class_ids, &target);
204 intptr_t class_id = class_ids[0];
205 if (class_id == kIllegalCid) {
206 if (FLAG_trace_inlining) OS::Print("Inline aborted: invalid receiver\n");
207 return;
208 }
209 if (class_id == kDynamicCid) {
210 if (FLAG_trace_inlining) OS::Print("Inline aborted: dynamic receiver\n");
211 return;
212 }
213
214 Definition* check;
215 // Construct a class check for the polymorphic call.
216 if (call->ic_data()->GetReceiverClassIdAt(0) == kSmiCid) {
217 check =
218 new CheckSmiInstr(call->ArgumentAt(0)->value(), call->deopt_id());
219 } else {
220 const ICData& unary_checks =
221 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks());
222 check =
223 new CheckClassInstr(call->ArgumentAt(0)->value(), call, unary_checks);
224 }
225
226 GrowableArray<Value*> arguments(call->ArgumentCount());
227 for (int i = 0; i < call->ArgumentCount(); ++i) {
228 arguments.Add(call->ArgumentAt(i)->value());
229 }
230
231 TryInlining(target, &arguments, call_defn, check);
232 }
233
234 void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr* call) {
235 if (FLAG_trace_inlining) OS::Print("Polymorphic ");
236 TryInliningInstanceCall(call->instance_call(), call);
237 }
238
239 void VisitStaticCall(StaticCallInstr* call) {
240 if (FLAG_trace_inlining) OS::Print("Static call\n");
241 GrowableArray<Value*> arguments(call->ArgumentCount());
242 for (int i = 0; i < call->ArgumentCount(); ++i) {
243 arguments.Add(call->ArgumentAt(i)->value());
244 }
245 TryInlining(call->function(), &arguments, call, NULL); // no check
246 }
247
248 bool inlined() const { return inlined_; }
144 249
145 private: 250 private:
146 FlowGraph* caller_graph_; 251 FlowGraph* caller_graph_;
147 intptr_t next_ssa_temp_index_; 252 intptr_t next_ssa_temp_index_;
148 bool inlined_; 253 bool inlined_;
149 }; 254 };
150 255
151 256
152 void FlowGraphInliner::Inline() { 257 void FlowGraphInliner::Inline() {
153 if ((FLAG_inlining_filter != NULL) && 258 if ((FLAG_inlining_filter != NULL) &&
154 (strstr(flow_graph_-> 259 (strstr(flow_graph_->
155 parsed_function().function().ToFullyQualifiedCString(), 260 parsed_function().function().ToFullyQualifiedCString(),
156 FLAG_inlining_filter) == NULL)) { 261 FLAG_inlining_filter) == NULL)) {
157 return; 262 return;
158 } 263 }
159 264
160 if (FLAG_trace_inlining && FLAG_print_flow_graph) { 265 if (FLAG_trace_inlining && FLAG_print_flow_graph) {
161 OS::Print("Before Inlining of %s\n", flow_graph_-> 266 OS::Print("Before Inlining of %s\n", flow_graph_->
162 parsed_function().function().ToFullyQualifiedCString()); 267 parsed_function().function().ToFullyQualifiedCString());
163 FlowGraphPrinter printer(*flow_graph_); 268 FlowGraphPrinter printer(*flow_graph_);
164 printer.PrintBlocks(); 269 printer.PrintBlocks();
165 } 270 }
166 271
167 CallSiteInliner inliner(flow_graph_); 272 CallSiteInliner inliner(flow_graph_);
168 inliner.VisitBlocks(); 273 inliner.VisitBlocks();
169 274
170 if (inliner.preformed_inlining()) { 275 if (inliner.inlined()) {
171 if (FLAG_trace_inlining && FLAG_print_flow_graph) { 276 if (FLAG_trace_inlining && FLAG_print_flow_graph) {
172 OS::Print("After Inlining of %s\n", flow_graph_-> 277 OS::Print("After Inlining of %s\n", flow_graph_->
173 parsed_function().function().ToFullyQualifiedCString()); 278 parsed_function().function().ToFullyQualifiedCString());
174 FlowGraphPrinter printer(*flow_graph_); 279 FlowGraphPrinter printer(*flow_graph_);
175 printer.PrintBlocks(); 280 printer.PrintBlocks();
176 } 281 }
177 } 282 }
178 } 283 }
179 284
180 } // namespace dart 285 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_builder.cc ('k') | runtime/vm/intermediate_language.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698