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

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

Issue 10916228: Inline monomorphic calls. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Incorporated review comments. 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 if (FLAG_trace_inlining) {
33 OS::Print("--- %s\n", function.ToFullyQualifiedCString());
34 }
33 35
34 // Abort if the callee has optional parameters. 36 // Abort if the callee has named parameters.
35 if (function.HasOptionalParameters()) { 37 if (function.HasOptionalParameters()) {
36 if (FLAG_trace_inlining) { 38 if (FLAG_trace_inlining) {
37 OS::Print("Inline aborted %s\nReason: optional parameters\n", 39 OS::Print("Inline aborted %s\nReason: optional parameters\n",
38 function.ToFullyQualifiedCString()); 40 function.ToFullyQualifiedCString());
39 } 41 }
40 return; 42 return false;
41 } 43 }
42 44
43 // Assuming no optional parameters the actual/formal count should match. 45 // Assuming no optional parameters the actual/formal count should match.
44 ASSERT(arguments->length() == function.num_fixed_parameters()); 46 ASSERT(arguments->length() == function.num_fixed_parameters());
45 47
46 Isolate* isolate = Isolate::Current(); 48 Isolate* isolate = Isolate::Current();
47 // Save and clear IC data. 49 // Save and clear IC data.
48 const Array& old_ic_data = Array::Handle(isolate->ic_data_array()); 50 const Array& old_ic_data = Array::Handle(isolate->ic_data_array());
49 isolate->set_ic_data_array(Array::null()); 51 isolate->set_ic_data_array(Array::null());
50 // Install bailout jump. 52 // Install bailout jump.
51 LongJump* base = isolate->long_jump_base(); 53 LongJump* base = isolate->long_jump_base();
52 LongJump jump; 54 LongJump jump;
53 isolate->set_long_jump_base(&jump); 55 isolate->set_long_jump_base(&jump);
54 if (setjmp(*jump.Set()) == 0) { 56 if (setjmp(*jump.Set()) == 0) {
55 // Parse the callee function. 57 // Parse the callee function.
56 ParsedFunction parsed_function(function); 58 ParsedFunction parsed_function(function);
57 Parser::ParseFunction(&parsed_function); 59 Parser::ParseFunction(&parsed_function);
60 parsed_function.AllocateVariables();
58 FlowGraphBuilder builder(parsed_function); 61 FlowGraphBuilder builder(parsed_function);
59 62
60 // Build the callee graph. 63 // Build the callee graph.
61 FlowGraph* callee_graph = 64 FlowGraph* callee_graph =
62 builder.BuildGraphForInlining(FlowGraphBuilder::kValueContext); 65 builder.BuildGraph(FlowGraphBuilder::kValueContext);
63 66
64 // Abort if the callee graph contains control flow. 67 // Abort if the callee graph contains control flow.
65 if (callee_graph->preorder().length() != 2) { 68 if (callee_graph->preorder().length() != 2) {
66 isolate->set_long_jump_base(base); 69 isolate->set_long_jump_base(base);
67 isolate->set_ic_data_array(old_ic_data.raw()); 70 isolate->set_ic_data_array(old_ic_data.raw());
68 if (FLAG_trace_inlining) { 71 if (FLAG_trace_inlining) {
69 OS::Print("Inline aborted %s\nReason: control flow\n", 72 OS::Print("Inline aborted %s\nReason: control flow\n",
70 parsed_function.function().ToFullyQualifiedCString()); 73 parsed_function.function().ToFullyQualifiedCString());
71 } 74 }
72 return; 75 return false;
73 } 76 }
74 77
75 if (FLAG_trace_inlining && FLAG_print_flow_graph) { 78 if (FLAG_trace_inlining && FLAG_print_flow_graph) {
76 OS::Print("Callee graph before SSA %s\n", 79 OS::Print("Callee graph before SSA %s\n",
77 parsed_function.function().ToFullyQualifiedCString()); 80 parsed_function.function().ToFullyQualifiedCString());
78 FlowGraphPrinter printer(*callee_graph); 81 FlowGraphPrinter printer(*callee_graph);
79 printer.PrintBlocks(); 82 printer.PrintBlocks();
80 } 83 }
81 84
82 // Compute SSA on the callee graph. (catching bailouts) 85 // Compute SSA on the callee graph. (catching bailouts)
(...skipping 11 matching lines...) Expand all
94 // TODO(zerny): Do optimization passes on the callee graph. 97 // TODO(zerny): Do optimization passes on the callee graph.
95 98
96 // TODO(zerny): If result is more than size threshold then abort. 99 // TODO(zerny): If result is more than size threshold then abort.
97 100
98 // TODO(zerny): If effort is less than threshold then inline recursively. 101 // TODO(zerny): If effort is less than threshold then inline recursively.
99 102
100 // Plug result in the caller graph. 103 // Plug result in the caller graph.
101 caller_graph_->InlineCall(call, callee_graph); 104 caller_graph_->InlineCall(call, callee_graph);
102 next_ssa_temp_index_ = caller_graph_->max_virtual_register_number(); 105 next_ssa_temp_index_ = caller_graph_->max_virtual_register_number();
103 106
107 // Remove (all) push arguments of the call.
108 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
109 PushArgumentInstr* push = call->ArgumentAt(i);
110 push->ReplaceUsesWith(push->value()->definition());
111 push->RemoveFromGraph();
112 }
113
104 // Replace all the formal parameters with the actuals. 114 // Replace all the formal parameters with the actuals.
105 for (intptr_t i = 0; i < arguments->length(); ++i) { 115 for (intptr_t i = 0; i < arguments->length(); ++i) {
106 Value* val = callee_graph->graph_entry()->start_env()->ValueAt(i); 116 Value* val = callee_graph->graph_entry()->start_env()->ValueAt(i);
107 ParameterInstr* param = val->definition()->AsParameter(); 117 ParameterInstr* param = val->definition()->AsParameter();
108 ASSERT(param != NULL); 118 ASSERT(param != NULL);
109 param->ReplaceUsesWith((*arguments)[i]->definition()); 119 param->ReplaceUsesWith((*arguments)[i]->definition());
110 } 120 }
111 121
122 // Replace callee's null constant with caller's null constant.
123 callee_graph->graph_entry()->constant_null()->ReplaceUsesWith(
124 caller_graph_->graph_entry()->constant_null());
125
112 if (FLAG_trace_inlining) { 126 if (FLAG_trace_inlining) {
113 OS::Print("Inlined %s\n", function.ToFullyQualifiedCString()); 127 OS::Print("Inlined %s\n", function.ToFullyQualifiedCString());
114 } 128 }
115 129
116 // Build succeeded so we restore the bailout jump. 130 // Build succeeded so we restore the bailout jump.
117 inlined_ = true; 131 inlined_ = true;
118 isolate->set_long_jump_base(base); 132 isolate->set_long_jump_base(base);
119 isolate->set_ic_data_array(old_ic_data.raw()); 133 isolate->set_ic_data_array(old_ic_data.raw());
134 return true;
120 } else { 135 } else {
121 Error& error = Error::Handle(); 136 Error& error = Error::Handle();
122 error = isolate->object_store()->sticky_error(); 137 error = isolate->object_store()->sticky_error();
123 isolate->object_store()->clear_sticky_error(); 138 isolate->object_store()->clear_sticky_error();
124 isolate->set_long_jump_base(base); 139 isolate->set_long_jump_base(base);
125 isolate->set_ic_data_array(old_ic_data.raw()); 140 isolate->set_ic_data_array(old_ic_data.raw());
126 if (FLAG_trace_inlining) { 141 if (FLAG_trace_inlining) {
127 OS::Print("Inline aborted for %s\nReason: %s\n", 142 OS::Print("Inline aborted for %s\nReason: %s\n",
128 function.ToFullyQualifiedCString(), 143 function.ToFullyQualifiedCString(),
129 error.ToErrorCString()); 144 error.ToErrorCString());
130 } 145 }
146 return false;
131 } 147 }
132 } 148 }
133 149
134 void VisitStaticCall(StaticCallInstr* instr) { 150 void VisitClosureCall(ClosureCallInstr* call) {
135 if (FLAG_trace_inlining) OS::Print("Static call\n"); 151 if (FLAG_trace_inlining) OS::Print("Closure call\n");
136 GrowableArray<Value*> arguments(instr->ArgumentCount()); 152 // Find the closure of the callee.
137 for (int i = 0; i < instr->ArgumentCount(); ++i) { 153 ASSERT(call->ArgumentCount() > 0);
138 arguments.Add(instr->ArgumentAt(i)->value()); 154 const CreateClosureInstr* closure =
155 call->ArgumentAt(0)->value()->definition()->AsCreateClosure();
156 if (closure == NULL) {
157 if (FLAG_trace_inlining) {
158 OS::Print("Inline aborted: non-closure operator.\n");
159 }
160 return;
139 } 161 }
140 TryInlining(instr->function(), &arguments, instr); 162 GrowableArray<Value*> arguments(call->ArgumentCount() - 1);
163 for (int i = 1; i < call->ArgumentCount(); ++i) {
164 arguments.Add(call->ArgumentAt(i)->value());
165 }
166 TryInlining(closure->function(), &arguments, call);
141 } 167 }
142 168
143 bool preformed_inlining() const { return inlined_; } 169 void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr* instr) {
170 if (FLAG_trace_inlining) OS::Print("Polymorphic instance call\n");
171 InstanceCallInstr* call = instr->instance_call();
172 if (!call->HasICData()) {
173 if (FLAG_trace_inlining) OS::Print("Inline aborted: has no IC data\n");
174 return;
175 }
176 const ICData& ic_data = *call->ic_data();
Florian Schneider 2012/09/11 16:54:15 This can be made even simpler for monomorphic call
177
178 ASSERT(ic_data.num_args_tested() > 0);
179
180 if (ic_data.NumberOfChecks() == 0) {
181 if (FLAG_trace_inlining) OS::Print("Inline aborted: no IC checks\n");
182 return;
183 }
184 if (ic_data.NumberOfChecks() != 1) {
Florian Schneider 2012/09/11 16:54:15 I think this check is not necesary since we only g
185 // TODO(zerny): proceed if each check has the same target?
186 if (FLAG_trace_inlining) OS::Print("Inline aborted: non monomorphic\n");
187 return;
188 }
189 GrowableArray<intptr_t> class_ids;
190 Function& target = Function::Handle();
191 ic_data.GetCheckAt(0, &class_ids, &target);
Florian Schneider 2012/09/11 16:54:15 const Function& target = Function::ZoneHandle(ic_d
192 intptr_t class_id = class_ids[0];
193 if (class_id == kIllegalCid) {
Florian Schneider 2012/09/11 16:54:15 Not sure if those can actually occur in type feedb
194 if (FLAG_trace_inlining) OS::Print("Inline aborted: invalid receiver\n");
195 return;
196 }
197 if (class_id == kDynamicCid) {
198 if (FLAG_trace_inlining) OS::Print("Inline aborted: dynamic receiver\n");
199 return;
200 }
201 if (class_id == kSmiCid) {
202 if (FLAG_trace_inlining) OS::Print("Inline aborted: smi receiver\n");
203 return;
204 }
205
206 GrowableArray<Value*> arguments(call->ArgumentCount());
207 for (int i = 0; i < call->ArgumentCount(); ++i) {
208 arguments.Add(call->ArgumentAt(i)->value());
209 }
210
211 TryInlining(target, &arguments, instr);
212 }
213
214 void VisitStaticCall(StaticCallInstr* call) {
215 if (FLAG_trace_inlining) OS::Print("Static call\n");
216 GrowableArray<Value*> arguments(call->ArgumentCount());
217 for (int i = 0; i < call->ArgumentCount(); ++i) {
218 arguments.Add(call->ArgumentAt(i)->value());
219 }
220 TryInlining(call->function(), &arguments, call);
221 }
222
223 bool inlined() const { return inlined_; }
144 224
145 private: 225 private:
146 FlowGraph* caller_graph_; 226 FlowGraph* caller_graph_;
147 intptr_t next_ssa_temp_index_; 227 intptr_t next_ssa_temp_index_;
148 bool inlined_; 228 bool inlined_;
149 }; 229 };
150 230
151 231
152 void FlowGraphInliner::Inline() { 232 void FlowGraphInliner::Inline() {
153 if ((FLAG_inlining_filter != NULL) && 233 if ((FLAG_inlining_filter != NULL) &&
154 (strstr(flow_graph_-> 234 (strstr(flow_graph_->
155 parsed_function().function().ToFullyQualifiedCString(), 235 parsed_function().function().ToFullyQualifiedCString(),
156 FLAG_inlining_filter) == NULL)) { 236 FLAG_inlining_filter) == NULL)) {
157 return; 237 return;
158 } 238 }
159 239
160 if (FLAG_trace_inlining && FLAG_print_flow_graph) { 240 if (FLAG_trace_inlining && FLAG_print_flow_graph) {
161 OS::Print("Before Inlining of %s\n", flow_graph_-> 241 OS::Print("Before Inlining of %s\n", flow_graph_->
162 parsed_function().function().ToFullyQualifiedCString()); 242 parsed_function().function().ToFullyQualifiedCString());
163 FlowGraphPrinter printer(*flow_graph_); 243 FlowGraphPrinter printer(*flow_graph_);
164 printer.PrintBlocks(); 244 printer.PrintBlocks();
165 } 245 }
166 246
167 CallSiteInliner inliner(flow_graph_); 247 CallSiteInliner inliner(flow_graph_);
168 inliner.VisitBlocks(); 248 inliner.VisitBlocks();
169 249
170 if (inliner.preformed_inlining()) { 250 if (inliner.inlined()) {
171 if (FLAG_trace_inlining && FLAG_print_flow_graph) { 251 if (FLAG_trace_inlining && FLAG_print_flow_graph) {
172 OS::Print("After Inlining of %s\n", flow_graph_-> 252 OS::Print("After Inlining of %s\n", flow_graph_->
173 parsed_function().function().ToFullyQualifiedCString()); 253 parsed_function().function().ToFullyQualifiedCString());
174 FlowGraphPrinter printer(*flow_graph_); 254 FlowGraphPrinter printer(*flow_graph_);
175 printer.PrintBlocks(); 255 printer.PrintBlocks();
176 } 256 }
177 } 257 }
178 } 258 }
179 259
180 } // namespace dart 260 } // 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