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.h" | 5 #include "vm/flow_graph.h" |
6 | 6 |
7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
8 #include "vm/cha.h" | 8 #include "vm/cha.h" |
9 #include "vm/flow_graph_builder.h" | 9 #include "vm/flow_graph_builder.h" |
10 #include "vm/flow_graph_compiler.h" | 10 #include "vm/flow_graph_compiler.h" |
11 #include "vm/flow_graph_range_analysis.h" | 11 #include "vm/flow_graph_range_analysis.h" |
| 12 #include "vm/growable_array.h" |
12 #include "vm/il_printer.h" | 13 #include "vm/il_printer.h" |
13 #include "vm/intermediate_language.h" | 14 #include "vm/intermediate_language.h" |
14 #include "vm/growable_array.h" | |
15 #include "vm/object_store.h" | 15 #include "vm/object_store.h" |
16 | 16 |
17 namespace dart { | 17 namespace dart { |
18 | 18 |
19 #if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_IA32) | 19 #if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_IA32) |
20 DEFINE_FLAG(bool, trace_smi_widening, false, "Trace Smi->Int32 widening pass."); | 20 DEFINE_FLAG(bool, trace_smi_widening, false, "Trace Smi->Int32 widening pass."); |
21 #endif | 21 #endif |
22 DEFINE_FLAG(bool, prune_dead_locals, true, "optimize dead locals away"); | 22 DEFINE_FLAG(bool, prune_dead_locals, true, "optimize dead locals away"); |
23 DECLARE_FLAG(bool, verify_compiler); | 23 DECLARE_FLAG(bool, verify_compiler); |
24 | 24 |
25 | |
26 FlowGraph::FlowGraph(const ParsedFunction& parsed_function, | 25 FlowGraph::FlowGraph(const ParsedFunction& parsed_function, |
27 GraphEntryInstr* graph_entry, | 26 GraphEntryInstr* graph_entry, |
28 intptr_t max_block_id) | 27 intptr_t max_block_id) |
29 : thread_(Thread::Current()), | 28 : thread_(Thread::Current()), |
30 parent_(), | 29 parent_(), |
31 current_ssa_temp_index_(0), | 30 current_ssa_temp_index_(0), |
32 max_block_id_(max_block_id), | 31 max_block_id_(max_block_id), |
33 parsed_function_(parsed_function), | 32 parsed_function_(parsed_function), |
34 num_copied_params_(parsed_function.num_copied_params()), | 33 num_copied_params_(parsed_function.num_copied_params()), |
35 num_non_copied_params_(parsed_function.num_non_copied_params()), | 34 num_non_copied_params_(parsed_function.num_non_copied_params()), |
36 graph_entry_(graph_entry), | 35 graph_entry_(graph_entry), |
37 preorder_(), | 36 preorder_(), |
38 postorder_(), | 37 postorder_(), |
39 reverse_postorder_(), | 38 reverse_postorder_(), |
40 optimized_block_order_(), | 39 optimized_block_order_(), |
41 constant_null_(NULL), | 40 constant_null_(NULL), |
42 constant_dead_(NULL), | 41 constant_dead_(NULL), |
43 constant_empty_context_(NULL), | 42 constant_empty_context_(NULL), |
44 block_effects_(NULL), | 43 block_effects_(NULL), |
45 licm_allowed_(true), | 44 licm_allowed_(true), |
46 loop_headers_(NULL), | 45 loop_headers_(NULL), |
47 loop_invariant_loads_(NULL), | 46 loop_invariant_loads_(NULL), |
48 deferred_prefixes_(parsed_function.deferred_prefixes()), | 47 deferred_prefixes_(parsed_function.deferred_prefixes()), |
49 await_token_positions_(NULL), | 48 await_token_positions_(NULL), |
50 captured_parameters_(new (zone()) BitVector(zone(), variable_count())), | 49 captured_parameters_(new (zone()) BitVector(zone(), variable_count())), |
51 inlining_id_(-1) { | 50 inlining_id_(-1) { |
52 DiscoverBlocks(); | 51 DiscoverBlocks(); |
53 } | 52 } |
54 | 53 |
55 | |
56 void FlowGraph::EnsureSSATempIndex(Definition* defn, Definition* replacement) { | 54 void FlowGraph::EnsureSSATempIndex(Definition* defn, Definition* replacement) { |
57 if ((replacement->ssa_temp_index() == -1) && (defn->ssa_temp_index() != -1)) { | 55 if ((replacement->ssa_temp_index() == -1) && (defn->ssa_temp_index() != -1)) { |
58 AllocateSSAIndexes(replacement); | 56 AllocateSSAIndexes(replacement); |
59 } | 57 } |
60 } | 58 } |
61 | 59 |
62 | |
63 void FlowGraph::ReplaceCurrentInstruction(ForwardInstructionIterator* iterator, | 60 void FlowGraph::ReplaceCurrentInstruction(ForwardInstructionIterator* iterator, |
64 Instruction* current, | 61 Instruction* current, |
65 Instruction* replacement) { | 62 Instruction* replacement) { |
66 Definition* current_defn = current->AsDefinition(); | 63 Definition* current_defn = current->AsDefinition(); |
67 if ((replacement != NULL) && (current_defn != NULL)) { | 64 if ((replacement != NULL) && (current_defn != NULL)) { |
68 Definition* replacement_defn = replacement->AsDefinition(); | 65 Definition* replacement_defn = replacement->AsDefinition(); |
69 ASSERT(replacement_defn != NULL); | 66 ASSERT(replacement_defn != NULL); |
70 current_defn->ReplaceUsesWith(replacement_defn); | 67 current_defn->ReplaceUsesWith(replacement_defn); |
71 EnsureSSATempIndex(current_defn, replacement_defn); | 68 EnsureSSATempIndex(current_defn, replacement_defn); |
72 | 69 |
(...skipping 18 matching lines...) Expand all Loading... |
91 if (replacement == NULL || i >= replacement->ArgumentCount() || | 88 if (replacement == NULL || i >= replacement->ArgumentCount() || |
92 replacement->PushArgumentAt(i) != push) { | 89 replacement->PushArgumentAt(i) != push) { |
93 push->ReplaceUsesWith(push->value()->definition()); | 90 push->ReplaceUsesWith(push->value()->definition()); |
94 push->RemoveFromGraph(); | 91 push->RemoveFromGraph(); |
95 } | 92 } |
96 } | 93 } |
97 } | 94 } |
98 iterator->RemoveCurrentFromGraph(); | 95 iterator->RemoveCurrentFromGraph(); |
99 } | 96 } |
100 | 97 |
101 | |
102 void FlowGraph::AddToDeferredPrefixes( | 98 void FlowGraph::AddToDeferredPrefixes( |
103 ZoneGrowableArray<const LibraryPrefix*>* from) { | 99 ZoneGrowableArray<const LibraryPrefix*>* from) { |
104 ZoneGrowableArray<const LibraryPrefix*>* to = deferred_prefixes(); | 100 ZoneGrowableArray<const LibraryPrefix*>* to = deferred_prefixes(); |
105 for (intptr_t i = 0; i < from->length(); i++) { | 101 for (intptr_t i = 0; i < from->length(); i++) { |
106 const LibraryPrefix* prefix = (*from)[i]; | 102 const LibraryPrefix* prefix = (*from)[i]; |
107 for (intptr_t j = 0; j < to->length(); j++) { | 103 for (intptr_t j = 0; j < to->length(); j++) { |
108 if ((*to)[j]->raw() == prefix->raw()) { | 104 if ((*to)[j]->raw() == prefix->raw()) { |
109 return; | 105 return; |
110 } | 106 } |
111 } | 107 } |
112 to->Add(prefix); | 108 to->Add(prefix); |
113 } | 109 } |
114 } | 110 } |
115 | 111 |
116 | |
117 bool FlowGraph::ShouldReorderBlocks(const Function& function, | 112 bool FlowGraph::ShouldReorderBlocks(const Function& function, |
118 bool is_optimized) { | 113 bool is_optimized) { |
119 return is_optimized && FLAG_reorder_basic_blocks && !function.is_intrinsic(); | 114 return is_optimized && FLAG_reorder_basic_blocks && !function.is_intrinsic(); |
120 } | 115 } |
121 | 116 |
122 | |
123 GrowableArray<BlockEntryInstr*>* FlowGraph::CodegenBlockOrder( | 117 GrowableArray<BlockEntryInstr*>* FlowGraph::CodegenBlockOrder( |
124 bool is_optimized) { | 118 bool is_optimized) { |
125 return ShouldReorderBlocks(function(), is_optimized) ? &optimized_block_order_ | 119 return ShouldReorderBlocks(function(), is_optimized) ? &optimized_block_order_ |
126 : &reverse_postorder_; | 120 : &reverse_postorder_; |
127 } | 121 } |
128 | 122 |
129 | |
130 ConstantInstr* FlowGraph::GetConstant(const Object& object) { | 123 ConstantInstr* FlowGraph::GetConstant(const Object& object) { |
131 ConstantInstr* constant = constant_instr_pool_.LookupValue(object); | 124 ConstantInstr* constant = constant_instr_pool_.LookupValue(object); |
132 if (constant == NULL) { | 125 if (constant == NULL) { |
133 // Otherwise, allocate and add it to the pool. | 126 // Otherwise, allocate and add it to the pool. |
134 constant = | 127 constant = |
135 new (zone()) ConstantInstr(Object::ZoneHandle(zone(), object.raw())); | 128 new (zone()) ConstantInstr(Object::ZoneHandle(zone(), object.raw())); |
136 constant->set_ssa_temp_index(alloc_ssa_temp_index()); | 129 constant->set_ssa_temp_index(alloc_ssa_temp_index()); |
137 | 130 |
138 AddToInitialDefinitions(constant); | 131 AddToInitialDefinitions(constant); |
139 constant_instr_pool_.Insert(constant); | 132 constant_instr_pool_.Insert(constant); |
140 } | 133 } |
141 return constant; | 134 return constant; |
142 } | 135 } |
143 | 136 |
144 | |
145 void FlowGraph::AddToInitialDefinitions(Definition* defn) { | 137 void FlowGraph::AddToInitialDefinitions(Definition* defn) { |
146 // TODO(zerny): Set previous to the graph entry so it is accessible by | 138 // TODO(zerny): Set previous to the graph entry so it is accessible by |
147 // GetBlock. Remove this once there is a direct pointer to the block. | 139 // GetBlock. Remove this once there is a direct pointer to the block. |
148 defn->set_previous(graph_entry_); | 140 defn->set_previous(graph_entry_); |
149 graph_entry_->initial_definitions()->Add(defn); | 141 graph_entry_->initial_definitions()->Add(defn); |
150 } | 142 } |
151 | 143 |
152 | |
153 void FlowGraph::InsertBefore(Instruction* next, | 144 void FlowGraph::InsertBefore(Instruction* next, |
154 Instruction* instr, | 145 Instruction* instr, |
155 Environment* env, | 146 Environment* env, |
156 UseKind use_kind) { | 147 UseKind use_kind) { |
157 InsertAfter(next->previous(), instr, env, use_kind); | 148 InsertAfter(next->previous(), instr, env, use_kind); |
158 } | 149 } |
159 | 150 |
160 | |
161 void FlowGraph::InsertAfter(Instruction* prev, | 151 void FlowGraph::InsertAfter(Instruction* prev, |
162 Instruction* instr, | 152 Instruction* instr, |
163 Environment* env, | 153 Environment* env, |
164 UseKind use_kind) { | 154 UseKind use_kind) { |
165 if (use_kind == kValue) { | 155 if (use_kind == kValue) { |
166 ASSERT(instr->IsDefinition()); | 156 ASSERT(instr->IsDefinition()); |
167 AllocateSSAIndexes(instr->AsDefinition()); | 157 AllocateSSAIndexes(instr->AsDefinition()); |
168 } | 158 } |
169 instr->InsertAfter(prev); | 159 instr->InsertAfter(prev); |
170 ASSERT(instr->env() == NULL); | 160 ASSERT(instr->env() == NULL); |
171 if (env != NULL) { | 161 if (env != NULL) { |
172 env->DeepCopyTo(zone(), instr); | 162 env->DeepCopyTo(zone(), instr); |
173 } | 163 } |
174 } | 164 } |
175 | 165 |
176 | |
177 Instruction* FlowGraph::AppendTo(Instruction* prev, | 166 Instruction* FlowGraph::AppendTo(Instruction* prev, |
178 Instruction* instr, | 167 Instruction* instr, |
179 Environment* env, | 168 Environment* env, |
180 UseKind use_kind) { | 169 UseKind use_kind) { |
181 if (use_kind == kValue) { | 170 if (use_kind == kValue) { |
182 ASSERT(instr->IsDefinition()); | 171 ASSERT(instr->IsDefinition()); |
183 AllocateSSAIndexes(instr->AsDefinition()); | 172 AllocateSSAIndexes(instr->AsDefinition()); |
184 } | 173 } |
185 ASSERT(instr->env() == NULL); | 174 ASSERT(instr->env() == NULL); |
186 if (env != NULL) { | 175 if (env != NULL) { |
187 env->DeepCopyTo(zone(), instr); | 176 env->DeepCopyTo(zone(), instr); |
188 } | 177 } |
189 return prev->AppendInstruction(instr); | 178 return prev->AppendInstruction(instr); |
190 } | 179 } |
191 | 180 |
192 | |
193 // A wrapper around block entries including an index of the next successor to | 181 // A wrapper around block entries including an index of the next successor to |
194 // be read. | 182 // be read. |
195 class BlockTraversalState { | 183 class BlockTraversalState { |
196 public: | 184 public: |
197 explicit BlockTraversalState(BlockEntryInstr* block) | 185 explicit BlockTraversalState(BlockEntryInstr* block) |
198 : block_(block), | 186 : block_(block), |
199 next_successor_ix_(block->last_instruction()->SuccessorCount() - 1) {} | 187 next_successor_ix_(block->last_instruction()->SuccessorCount() - 1) {} |
200 | 188 |
201 bool HasNextSuccessor() const { return next_successor_ix_ >= 0; } | 189 bool HasNextSuccessor() const { return next_successor_ix_ >= 0; } |
202 BlockEntryInstr* NextSuccessor() { | 190 BlockEntryInstr* NextSuccessor() { |
203 ASSERT(HasNextSuccessor()); | 191 ASSERT(HasNextSuccessor()); |
204 return block_->last_instruction()->SuccessorAt(next_successor_ix_--); | 192 return block_->last_instruction()->SuccessorAt(next_successor_ix_--); |
205 } | 193 } |
206 | 194 |
207 BlockEntryInstr* block() const { return block_; } | 195 BlockEntryInstr* block() const { return block_; } |
208 | 196 |
209 private: | 197 private: |
210 BlockEntryInstr* block_; | 198 BlockEntryInstr* block_; |
211 intptr_t next_successor_ix_; | 199 intptr_t next_successor_ix_; |
212 | 200 |
213 DISALLOW_ALLOCATION(); | 201 DISALLOW_ALLOCATION(); |
214 }; | 202 }; |
215 | 203 |
216 | |
217 void FlowGraph::DiscoverBlocks() { | 204 void FlowGraph::DiscoverBlocks() { |
218 StackZone zone(thread()); | 205 StackZone zone(thread()); |
219 | 206 |
220 // Initialize state. | 207 // Initialize state. |
221 preorder_.Clear(); | 208 preorder_.Clear(); |
222 postorder_.Clear(); | 209 postorder_.Clear(); |
223 reverse_postorder_.Clear(); | 210 reverse_postorder_.Clear(); |
224 parent_.Clear(); | 211 parent_.Clear(); |
225 | 212 |
226 GrowableArray<BlockTraversalState> block_stack; | 213 GrowableArray<BlockTraversalState> block_stack; |
(...skipping 24 matching lines...) Expand all Loading... |
251 for (intptr_t i = 0; i < block_count; ++i) { | 238 for (intptr_t i = 0; i < block_count; ++i) { |
252 reverse_postorder_.Add(postorder_[block_count - i - 1]); | 239 reverse_postorder_.Add(postorder_[block_count - i - 1]); |
253 } | 240 } |
254 | 241 |
255 // Block effects are using postorder numbering. Discard computed information. | 242 // Block effects are using postorder numbering. Discard computed information. |
256 block_effects_ = NULL; | 243 block_effects_ = NULL; |
257 loop_headers_ = NULL; | 244 loop_headers_ = NULL; |
258 loop_invariant_loads_ = NULL; | 245 loop_invariant_loads_ = NULL; |
259 } | 246 } |
260 | 247 |
261 | |
262 void FlowGraph::MergeBlocks() { | 248 void FlowGraph::MergeBlocks() { |
263 bool changed = false; | 249 bool changed = false; |
264 BitVector* merged = new (zone()) BitVector(zone(), postorder().length()); | 250 BitVector* merged = new (zone()) BitVector(zone(), postorder().length()); |
265 for (BlockIterator block_it = reverse_postorder_iterator(); !block_it.Done(); | 251 for (BlockIterator block_it = reverse_postorder_iterator(); !block_it.Done(); |
266 block_it.Advance()) { | 252 block_it.Advance()) { |
267 BlockEntryInstr* block = block_it.Current(); | 253 BlockEntryInstr* block = block_it.Current(); |
268 if (block->IsGraphEntry()) continue; | 254 if (block->IsGraphEntry()) continue; |
269 if (merged->Contains(block->postorder_number())) continue; | 255 if (merged->Contains(block->postorder_number())) continue; |
270 | 256 |
271 Instruction* last = block->last_instruction(); | 257 Instruction* last = block->last_instruction(); |
(...skipping 21 matching lines...) Expand all Loading... |
293 // The new block inherits the block id of the last successor to maintain | 279 // The new block inherits the block id of the last successor to maintain |
294 // the order of phi inputs at its successors consistent with block ids. | 280 // the order of phi inputs at its successors consistent with block ids. |
295 if (successor != NULL) { | 281 if (successor != NULL) { |
296 block->set_block_id(successor->block_id()); | 282 block->set_block_id(successor->block_id()); |
297 } | 283 } |
298 } | 284 } |
299 // Recompute block order after changes were made. | 285 // Recompute block order after changes were made. |
300 if (changed) DiscoverBlocks(); | 286 if (changed) DiscoverBlocks(); |
301 } | 287 } |
302 | 288 |
303 | |
304 // Debugging code to verify the construction of use lists. | 289 // Debugging code to verify the construction of use lists. |
305 static intptr_t MembershipCount(Value* use, Value* list) { | 290 static intptr_t MembershipCount(Value* use, Value* list) { |
306 intptr_t count = 0; | 291 intptr_t count = 0; |
307 while (list != NULL) { | 292 while (list != NULL) { |
308 if (list == use) ++count; | 293 if (list == use) ++count; |
309 list = list->next_use(); | 294 list = list->next_use(); |
310 } | 295 } |
311 return count; | 296 return count; |
312 } | 297 } |
313 | 298 |
314 | |
315 static void VerifyUseListsInInstruction(Instruction* instr) { | 299 static void VerifyUseListsInInstruction(Instruction* instr) { |
316 ASSERT(instr != NULL); | 300 ASSERT(instr != NULL); |
317 ASSERT(!instr->IsJoinEntry()); | 301 ASSERT(!instr->IsJoinEntry()); |
318 for (intptr_t i = 0; i < instr->InputCount(); ++i) { | 302 for (intptr_t i = 0; i < instr->InputCount(); ++i) { |
319 Value* use = instr->InputAt(i); | 303 Value* use = instr->InputAt(i); |
320 ASSERT(use->definition() != NULL); | 304 ASSERT(use->definition() != NULL); |
321 ASSERT((use->definition() != instr) || use->definition()->IsPhi() || | 305 ASSERT((use->definition() != instr) || use->definition()->IsPhi() || |
322 use->definition()->IsMaterializeObject()); | 306 use->definition()->IsMaterializeObject()); |
323 ASSERT(use->instruction() == instr); | 307 ASSERT(use->instruction() == instr); |
324 ASSERT(use->use_index() == i); | 308 ASSERT(use->use_index() == i); |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
393 phi->set_is_receiver(PhiInstr::kNotReceiver); | 377 phi->set_is_receiver(PhiInstr::kNotReceiver); |
394 break; | 378 break; |
395 } | 379 } |
396 } | 380 } |
397 | 381 |
398 if (phi->is_receiver() == PhiInstr::kNotReceiver) { | 382 if (phi->is_receiver() == PhiInstr::kNotReceiver) { |
399 unmark->Add(phi); | 383 unmark->Add(phi); |
400 } | 384 } |
401 } | 385 } |
402 | 386 |
403 | |
404 void FlowGraph::ComputeIsReceiver(PhiInstr* phi) const { | 387 void FlowGraph::ComputeIsReceiver(PhiInstr* phi) const { |
405 GrowableArray<PhiInstr*> unmark; | 388 GrowableArray<PhiInstr*> unmark; |
406 ComputeIsReceiverRecursive(phi, &unmark); | 389 ComputeIsReceiverRecursive(phi, &unmark); |
407 | 390 |
408 // Now drain unmark. | 391 // Now drain unmark. |
409 while (!unmark.is_empty()) { | 392 while (!unmark.is_empty()) { |
410 PhiInstr* phi = unmark.RemoveLast(); | 393 PhiInstr* phi = unmark.RemoveLast(); |
411 for (Value::Iterator it(phi->input_use_list()); !it.Done(); it.Advance()) { | 394 for (Value::Iterator it(phi->input_use_list()); !it.Done(); it.Advance()) { |
412 PhiInstr* use = it.Current()->instruction()->AsPhi(); | 395 PhiInstr* use = it.Current()->instruction()->AsPhi(); |
413 if ((use != NULL) && (use->is_receiver() == PhiInstr::kReceiver)) { | 396 if ((use != NULL) && (use->is_receiver() == PhiInstr::kReceiver)) { |
414 use->set_is_receiver(PhiInstr::kNotReceiver); | 397 use->set_is_receiver(PhiInstr::kNotReceiver); |
415 unmark.Add(use); | 398 unmark.Add(use); |
416 } | 399 } |
417 } | 400 } |
418 } | 401 } |
419 } | 402 } |
420 | 403 |
421 | |
422 bool FlowGraph::IsReceiver(Definition* def) const { | 404 bool FlowGraph::IsReceiver(Definition* def) const { |
423 def = def->OriginalDefinition(); // Could be redefined. | 405 def = def->OriginalDefinition(); // Could be redefined. |
424 if (def->IsParameter()) return (def->AsParameter()->index() == 0); | 406 if (def->IsParameter()) return (def->AsParameter()->index() == 0); |
425 if (!def->IsPhi() || graph_entry()->catch_entries().is_empty()) return false; | 407 if (!def->IsPhi() || graph_entry()->catch_entries().is_empty()) return false; |
426 PhiInstr* phi = def->AsPhi(); | 408 PhiInstr* phi = def->AsPhi(); |
427 if (phi->is_receiver() != PhiInstr::kUnknownReceiver) { | 409 if (phi->is_receiver() != PhiInstr::kUnknownReceiver) { |
428 return (phi->is_receiver() == PhiInstr::kReceiver); | 410 return (phi->is_receiver() == PhiInstr::kReceiver); |
429 } | 411 } |
430 // Not known if this phi is the receiver yet. Compute it now. | 412 // Not known if this phi is the receiver yet. Compute it now. |
431 ComputeIsReceiver(phi); | 413 ComputeIsReceiver(phi); |
432 return (phi->is_receiver() == PhiInstr::kReceiver); | 414 return (phi->is_receiver() == PhiInstr::kReceiver); |
433 } | 415 } |
434 | 416 |
435 | |
436 // Use CHA to determine if the call needs a class check: if the callee's | 417 // Use CHA to determine if the call needs a class check: if the callee's |
437 // receiver is the same as the caller's receiver and there are no overridden | 418 // receiver is the same as the caller's receiver and there are no overridden |
438 // callee functions, then no class check is needed. | 419 // callee functions, then no class check is needed. |
439 bool FlowGraph::InstanceCallNeedsClassCheck(InstanceCallInstr* call, | 420 bool FlowGraph::InstanceCallNeedsClassCheck(InstanceCallInstr* call, |
440 RawFunction::Kind kind) const { | 421 RawFunction::Kind kind) const { |
441 if (!FLAG_use_cha_deopt && !isolate()->all_classes_finalized()) { | 422 if (!FLAG_use_cha_deopt && !isolate()->all_classes_finalized()) { |
442 // Even if class or function are private, lazy class finalization | 423 // Even if class or function are private, lazy class finalization |
443 // may later add overriding methods. | 424 // may later add overriding methods. |
444 return true; | 425 return true; |
445 } | 426 } |
(...skipping 14 matching lines...) Expand all Loading... |
460 "no overrides of '%s' '%s'\n", | 441 "no overrides of '%s' '%s'\n", |
461 name.ToCString(), cls.ToCString()); | 442 name.ToCString(), cls.ToCString()); |
462 } | 443 } |
463 thread()->cha()->AddToGuardedClasses(cls, subclass_count); | 444 thread()->cha()->AddToGuardedClasses(cls, subclass_count); |
464 return false; | 445 return false; |
465 } | 446 } |
466 } | 447 } |
467 return true; | 448 return true; |
468 } | 449 } |
469 | 450 |
470 | |
471 Instruction* FlowGraph::CreateCheckClass(Definition* to_check, | 451 Instruction* FlowGraph::CreateCheckClass(Definition* to_check, |
472 const Cids& cids, | 452 const Cids& cids, |
473 intptr_t deopt_id, | 453 intptr_t deopt_id, |
474 TokenPosition token_pos) { | 454 TokenPosition token_pos) { |
475 if (cids.IsMonomorphic() && cids.MonomorphicReceiverCid() == kSmiCid) { | 455 if (cids.IsMonomorphic() && cids.MonomorphicReceiverCid() == kSmiCid) { |
476 return new (zone()) | 456 return new (zone()) |
477 CheckSmiInstr(new (zone()) Value(to_check), deopt_id, token_pos); | 457 CheckSmiInstr(new (zone()) Value(to_check), deopt_id, token_pos); |
478 } | 458 } |
479 return new (zone()) | 459 return new (zone()) |
480 CheckClassInstr(new (zone()) Value(to_check), deopt_id, cids, token_pos); | 460 CheckClassInstr(new (zone()) Value(to_check), deopt_id, cids, token_pos); |
481 } | 461 } |
482 | 462 |
483 | |
484 bool FlowGraph::VerifyUseLists() { | 463 bool FlowGraph::VerifyUseLists() { |
485 // Verify the initial definitions. | 464 // Verify the initial definitions. |
486 for (intptr_t i = 0; i < graph_entry_->initial_definitions()->length(); ++i) { | 465 for (intptr_t i = 0; i < graph_entry_->initial_definitions()->length(); ++i) { |
487 VerifyUseListsInInstruction((*graph_entry_->initial_definitions())[i]); | 466 VerifyUseListsInInstruction((*graph_entry_->initial_definitions())[i]); |
488 } | 467 } |
489 | 468 |
490 // Verify phis in join entries and the instructions in each block. | 469 // Verify phis in join entries and the instructions in each block. |
491 for (intptr_t i = 0; i < preorder_.length(); ++i) { | 470 for (intptr_t i = 0; i < preorder_.length(); ++i) { |
492 BlockEntryInstr* entry = preorder_[i]; | 471 BlockEntryInstr* entry = preorder_[i]; |
493 JoinEntryInstr* join = entry->AsJoinEntry(); | 472 JoinEntryInstr* join = entry->AsJoinEntry(); |
494 if (join != NULL) { | 473 if (join != NULL) { |
495 for (PhiIterator it(join); !it.Done(); it.Advance()) { | 474 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
496 PhiInstr* phi = it.Current(); | 475 PhiInstr* phi = it.Current(); |
497 ASSERT(phi != NULL); | 476 ASSERT(phi != NULL); |
498 VerifyUseListsInInstruction(phi); | 477 VerifyUseListsInInstruction(phi); |
499 } | 478 } |
500 } | 479 } |
501 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { | 480 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { |
502 VerifyUseListsInInstruction(it.Current()); | 481 VerifyUseListsInInstruction(it.Current()); |
503 } | 482 } |
504 } | 483 } |
505 | 484 |
506 return true; // Return true so we can ASSERT validation. | 485 return true; // Return true so we can ASSERT validation. |
507 } | 486 } |
508 | 487 |
509 | |
510 // Verify that a redefinition dominates all uses of the redefined value. | 488 // Verify that a redefinition dominates all uses of the redefined value. |
511 bool FlowGraph::VerifyRedefinitions() { | 489 bool FlowGraph::VerifyRedefinitions() { |
512 for (BlockIterator block_it = reverse_postorder_iterator(); !block_it.Done(); | 490 for (BlockIterator block_it = reverse_postorder_iterator(); !block_it.Done(); |
513 block_it.Advance()) { | 491 block_it.Advance()) { |
514 for (ForwardInstructionIterator instr_it(block_it.Current()); | 492 for (ForwardInstructionIterator instr_it(block_it.Current()); |
515 !instr_it.Done(); instr_it.Advance()) { | 493 !instr_it.Done(); instr_it.Advance()) { |
516 RedefinitionInstr* redefinition = instr_it.Current()->AsRedefinition(); | 494 RedefinitionInstr* redefinition = instr_it.Current()->AsRedefinition(); |
517 if (redefinition != NULL) { | 495 if (redefinition != NULL) { |
518 Definition* original = redefinition->value()->definition(); | 496 Definition* original = redefinition->value()->definition(); |
519 for (Value::Iterator it(original->input_use_list()); !it.Done(); | 497 for (Value::Iterator it(original->input_use_list()); !it.Done(); |
520 it.Advance()) { | 498 it.Advance()) { |
521 Value* original_use = it.Current(); | 499 Value* original_use = it.Current(); |
522 if (original_use->instruction() == redefinition) { | 500 if (original_use->instruction() == redefinition) { |
523 continue; | 501 continue; |
524 } | 502 } |
525 if (original_use->instruction()->IsDominatedBy(redefinition)) { | 503 if (original_use->instruction()->IsDominatedBy(redefinition)) { |
526 FlowGraphPrinter::PrintGraph("VerifyRedefinitions", this); | 504 FlowGraphPrinter::PrintGraph("VerifyRedefinitions", this); |
527 THR_Print("%s\n", redefinition->ToCString()); | 505 THR_Print("%s\n", redefinition->ToCString()); |
528 THR_Print("use=%s\n", original_use->instruction()->ToCString()); | 506 THR_Print("use=%s\n", original_use->instruction()->ToCString()); |
529 return false; | 507 return false; |
530 } | 508 } |
531 } | 509 } |
532 } | 510 } |
533 } | 511 } |
534 } | 512 } |
535 return true; | 513 return true; |
536 } | 514 } |
537 | 515 |
538 | |
539 LivenessAnalysis::LivenessAnalysis( | 516 LivenessAnalysis::LivenessAnalysis( |
540 intptr_t variable_count, | 517 intptr_t variable_count, |
541 const GrowableArray<BlockEntryInstr*>& postorder) | 518 const GrowableArray<BlockEntryInstr*>& postorder) |
542 : zone_(Thread::Current()->zone()), | 519 : zone_(Thread::Current()->zone()), |
543 variable_count_(variable_count), | 520 variable_count_(variable_count), |
544 postorder_(postorder), | 521 postorder_(postorder), |
545 live_out_(postorder.length()), | 522 live_out_(postorder.length()), |
546 kill_(postorder.length()), | 523 kill_(postorder.length()), |
547 live_in_(postorder.length()) {} | 524 live_in_(postorder.length()) {} |
548 | 525 |
549 | |
550 bool LivenessAnalysis::UpdateLiveOut(const BlockEntryInstr& block) { | 526 bool LivenessAnalysis::UpdateLiveOut(const BlockEntryInstr& block) { |
551 BitVector* live_out = live_out_[block.postorder_number()]; | 527 BitVector* live_out = live_out_[block.postorder_number()]; |
552 bool changed = false; | 528 bool changed = false; |
553 Instruction* last = block.last_instruction(); | 529 Instruction* last = block.last_instruction(); |
554 ASSERT(last != NULL); | 530 ASSERT(last != NULL); |
555 for (intptr_t i = 0; i < last->SuccessorCount(); i++) { | 531 for (intptr_t i = 0; i < last->SuccessorCount(); i++) { |
556 BlockEntryInstr* succ = last->SuccessorAt(i); | 532 BlockEntryInstr* succ = last->SuccessorAt(i); |
557 ASSERT(succ != NULL); | 533 ASSERT(succ != NULL); |
558 if (live_out->AddAll(live_in_[succ->postorder_number()])) { | 534 if (live_out->AddAll(live_in_[succ->postorder_number()])) { |
559 changed = true; | 535 changed = true; |
560 } | 536 } |
561 } | 537 } |
562 return changed; | 538 return changed; |
563 } | 539 } |
564 | 540 |
565 | |
566 bool LivenessAnalysis::UpdateLiveIn(const BlockEntryInstr& block) { | 541 bool LivenessAnalysis::UpdateLiveIn(const BlockEntryInstr& block) { |
567 BitVector* live_out = live_out_[block.postorder_number()]; | 542 BitVector* live_out = live_out_[block.postorder_number()]; |
568 BitVector* kill = kill_[block.postorder_number()]; | 543 BitVector* kill = kill_[block.postorder_number()]; |
569 BitVector* live_in = live_in_[block.postorder_number()]; | 544 BitVector* live_in = live_in_[block.postorder_number()]; |
570 return live_in->KillAndAdd(kill, live_out); | 545 return live_in->KillAndAdd(kill, live_out); |
571 } | 546 } |
572 | 547 |
573 | |
574 void LivenessAnalysis::ComputeLiveInAndLiveOutSets() { | 548 void LivenessAnalysis::ComputeLiveInAndLiveOutSets() { |
575 const intptr_t block_count = postorder_.length(); | 549 const intptr_t block_count = postorder_.length(); |
576 bool changed; | 550 bool changed; |
577 do { | 551 do { |
578 changed = false; | 552 changed = false; |
579 | 553 |
580 for (intptr_t i = 0; i < block_count; i++) { | 554 for (intptr_t i = 0; i < block_count; i++) { |
581 const BlockEntryInstr& block = *postorder_[i]; | 555 const BlockEntryInstr& block = *postorder_[i]; |
582 | 556 |
583 // Live-in set depends only on kill set which does not | 557 // Live-in set depends only on kill set which does not |
584 // change in this loop and live-out set. If live-out | 558 // change in this loop and live-out set. If live-out |
585 // set does not change there is no need to recompute | 559 // set does not change there is no need to recompute |
586 // live-in set. | 560 // live-in set. |
587 if (UpdateLiveOut(block) && UpdateLiveIn(block)) { | 561 if (UpdateLiveOut(block) && UpdateLiveIn(block)) { |
588 changed = true; | 562 changed = true; |
589 } | 563 } |
590 } | 564 } |
591 } while (changed); | 565 } while (changed); |
592 } | 566 } |
593 | 567 |
594 | |
595 void LivenessAnalysis::Analyze() { | 568 void LivenessAnalysis::Analyze() { |
596 const intptr_t block_count = postorder_.length(); | 569 const intptr_t block_count = postorder_.length(); |
597 for (intptr_t i = 0; i < block_count; i++) { | 570 for (intptr_t i = 0; i < block_count; i++) { |
598 live_out_.Add(new (zone()) BitVector(zone(), variable_count_)); | 571 live_out_.Add(new (zone()) BitVector(zone(), variable_count_)); |
599 kill_.Add(new (zone()) BitVector(zone(), variable_count_)); | 572 kill_.Add(new (zone()) BitVector(zone(), variable_count_)); |
600 live_in_.Add(new (zone()) BitVector(zone(), variable_count_)); | 573 live_in_.Add(new (zone()) BitVector(zone(), variable_count_)); |
601 } | 574 } |
602 | 575 |
603 ComputeInitialSets(); | 576 ComputeInitialSets(); |
604 ComputeLiveInAndLiveOutSets(); | 577 ComputeLiveInAndLiveOutSets(); |
605 } | 578 } |
606 | 579 |
607 | |
608 static void PrintBitVector(const char* tag, BitVector* v) { | 580 static void PrintBitVector(const char* tag, BitVector* v) { |
609 OS::Print("%s:", tag); | 581 OS::Print("%s:", tag); |
610 for (BitVector::Iterator it(v); !it.Done(); it.Advance()) { | 582 for (BitVector::Iterator it(v); !it.Done(); it.Advance()) { |
611 OS::Print(" %" Pd "", it.Current()); | 583 OS::Print(" %" Pd "", it.Current()); |
612 } | 584 } |
613 OS::Print("\n"); | 585 OS::Print("\n"); |
614 } | 586 } |
615 | 587 |
616 | |
617 void LivenessAnalysis::Dump() { | 588 void LivenessAnalysis::Dump() { |
618 const intptr_t block_count = postorder_.length(); | 589 const intptr_t block_count = postorder_.length(); |
619 for (intptr_t i = 0; i < block_count; i++) { | 590 for (intptr_t i = 0; i < block_count; i++) { |
620 BlockEntryInstr* block = postorder_[i]; | 591 BlockEntryInstr* block = postorder_[i]; |
621 OS::Print("block @%" Pd " -> ", block->block_id()); | 592 OS::Print("block @%" Pd " -> ", block->block_id()); |
622 | 593 |
623 Instruction* last = block->last_instruction(); | 594 Instruction* last = block->last_instruction(); |
624 for (intptr_t j = 0; j < last->SuccessorCount(); j++) { | 595 for (intptr_t j = 0; j < last->SuccessorCount(); j++) { |
625 BlockEntryInstr* succ = last->SuccessorAt(j); | 596 BlockEntryInstr* succ = last->SuccessorAt(j); |
626 OS::Print(" @%" Pd "", succ->block_id()); | 597 OS::Print(" @%" Pd "", succ->block_id()); |
627 } | 598 } |
628 OS::Print("\n"); | 599 OS::Print("\n"); |
629 | 600 |
630 PrintBitVector(" live out", live_out_[i]); | 601 PrintBitVector(" live out", live_out_[i]); |
631 PrintBitVector(" kill", kill_[i]); | 602 PrintBitVector(" kill", kill_[i]); |
632 PrintBitVector(" live in", live_in_[i]); | 603 PrintBitVector(" live in", live_in_[i]); |
633 } | 604 } |
634 } | 605 } |
635 | 606 |
636 | |
637 // Computes liveness information for local variables. | 607 // Computes liveness information for local variables. |
638 class VariableLivenessAnalysis : public LivenessAnalysis { | 608 class VariableLivenessAnalysis : public LivenessAnalysis { |
639 public: | 609 public: |
640 explicit VariableLivenessAnalysis(FlowGraph* flow_graph) | 610 explicit VariableLivenessAnalysis(FlowGraph* flow_graph) |
641 : LivenessAnalysis(flow_graph->variable_count(), flow_graph->postorder()), | 611 : LivenessAnalysis(flow_graph->variable_count(), flow_graph->postorder()), |
642 flow_graph_(flow_graph), | 612 flow_graph_(flow_graph), |
643 num_non_copied_params_(flow_graph->num_non_copied_params()), | 613 num_non_copied_params_(flow_graph->num_non_copied_params()), |
644 assigned_vars_() {} | 614 assigned_vars_() {} |
645 | 615 |
646 // For every block (in preorder) compute and return set of variables that | 616 // For every block (in preorder) compute and return set of variables that |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
703 } | 673 } |
704 | 674 |
705 private: | 675 private: |
706 virtual void ComputeInitialSets(); | 676 virtual void ComputeInitialSets(); |
707 | 677 |
708 const FlowGraph* flow_graph_; | 678 const FlowGraph* flow_graph_; |
709 const intptr_t num_non_copied_params_; | 679 const intptr_t num_non_copied_params_; |
710 GrowableArray<BitVector*> assigned_vars_; | 680 GrowableArray<BitVector*> assigned_vars_; |
711 }; | 681 }; |
712 | 682 |
713 | |
714 void VariableLivenessAnalysis::ComputeInitialSets() { | 683 void VariableLivenessAnalysis::ComputeInitialSets() { |
715 const intptr_t block_count = postorder_.length(); | 684 const intptr_t block_count = postorder_.length(); |
716 | 685 |
717 BitVector* last_loads = new (zone()) BitVector(zone(), variable_count_); | 686 BitVector* last_loads = new (zone()) BitVector(zone(), variable_count_); |
718 for (intptr_t i = 0; i < block_count; i++) { | 687 for (intptr_t i = 0; i < block_count; i++) { |
719 BlockEntryInstr* block = postorder_[i]; | 688 BlockEntryInstr* block = postorder_[i]; |
720 | 689 |
721 BitVector* kill = kill_[i]; | 690 BitVector* kill = kill_[i]; |
722 BitVector* live_in = live_in_[i]; | 691 BitVector* live_in = live_in_[i]; |
723 last_loads->Clear(); | 692 last_loads->Clear(); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
764 } | 733 } |
765 kill->Add(index); | 734 kill->Add(index); |
766 } | 735 } |
767 live_in->Remove(index); | 736 live_in->Remove(index); |
768 continue; | 737 continue; |
769 } | 738 } |
770 } | 739 } |
771 } | 740 } |
772 } | 741 } |
773 | 742 |
774 | |
775 void FlowGraph::ComputeSSA( | 743 void FlowGraph::ComputeSSA( |
776 intptr_t next_virtual_register_number, | 744 intptr_t next_virtual_register_number, |
777 ZoneGrowableArray<Definition*>* inlining_parameters) { | 745 ZoneGrowableArray<Definition*>* inlining_parameters) { |
778 ASSERT((next_virtual_register_number == 0) || (inlining_parameters != NULL)); | 746 ASSERT((next_virtual_register_number == 0) || (inlining_parameters != NULL)); |
779 current_ssa_temp_index_ = next_virtual_register_number; | 747 current_ssa_temp_index_ = next_virtual_register_number; |
780 GrowableArray<BitVector*> dominance_frontier; | 748 GrowableArray<BitVector*> dominance_frontier; |
781 ComputeDominators(&dominance_frontier); | 749 ComputeDominators(&dominance_frontier); |
782 | 750 |
783 VariableLivenessAnalysis variable_liveness(this); | 751 VariableLivenessAnalysis variable_liveness(this); |
784 variable_liveness.Analyze(); | 752 variable_liveness.Analyze(); |
785 | 753 |
786 GrowableArray<PhiInstr*> live_phis; | 754 GrowableArray<PhiInstr*> live_phis; |
787 | 755 |
788 InsertPhis(preorder_, variable_liveness.ComputeAssignedVars(), | 756 InsertPhis(preorder_, variable_liveness.ComputeAssignedVars(), |
789 dominance_frontier, &live_phis); | 757 dominance_frontier, &live_phis); |
790 | 758 |
791 | |
792 // Rename uses to reference inserted phis where appropriate. | 759 // Rename uses to reference inserted phis where appropriate. |
793 // Collect phis that reach a non-environment use. | 760 // Collect phis that reach a non-environment use. |
794 Rename(&live_phis, &variable_liveness, inlining_parameters); | 761 Rename(&live_phis, &variable_liveness, inlining_parameters); |
795 | 762 |
796 // Propagate alive mark transitively from alive phis and then remove | 763 // Propagate alive mark transitively from alive phis and then remove |
797 // non-live ones. | 764 // non-live ones. |
798 RemoveDeadPhis(&live_phis); | 765 RemoveDeadPhis(&live_phis); |
799 } | 766 } |
800 | 767 |
801 | |
802 // Compute immediate dominators and the dominance frontier for each basic | 768 // Compute immediate dominators and the dominance frontier for each basic |
803 // block. As a side effect of the algorithm, sets the immediate dominator | 769 // block. As a side effect of the algorithm, sets the immediate dominator |
804 // of each basic block. | 770 // of each basic block. |
805 // | 771 // |
806 // dominance_frontier: an output parameter encoding the dominance frontier. | 772 // dominance_frontier: an output parameter encoding the dominance frontier. |
807 // The array maps the preorder block number of a block to the set of | 773 // The array maps the preorder block number of a block to the set of |
808 // (preorder block numbers of) blocks in the dominance frontier. | 774 // (preorder block numbers of) blocks in the dominance frontier. |
809 void FlowGraph::ComputeDominators( | 775 void FlowGraph::ComputeDominators( |
810 GrowableArray<BitVector*>* dominance_frontier) { | 776 GrowableArray<BitVector*>* dominance_frontier) { |
811 // Use the SEMI-NCA algorithm to compute dominators. This is a two-pass | 777 // Use the SEMI-NCA algorithm to compute dominators. This is a two-pass |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
895 for (intptr_t i = 0; i < count; ++i) { | 861 for (intptr_t i = 0; i < count; ++i) { |
896 BlockEntryInstr* runner = block->PredecessorAt(i); | 862 BlockEntryInstr* runner = block->PredecessorAt(i); |
897 while (runner != block->dominator()) { | 863 while (runner != block->dominator()) { |
898 (*dominance_frontier)[runner->preorder_number()]->Add(block_index); | 864 (*dominance_frontier)[runner->preorder_number()]->Add(block_index); |
899 runner = runner->dominator(); | 865 runner = runner->dominator(); |
900 } | 866 } |
901 } | 867 } |
902 } | 868 } |
903 } | 869 } |
904 | 870 |
905 | |
906 void FlowGraph::CompressPath(intptr_t start_index, | 871 void FlowGraph::CompressPath(intptr_t start_index, |
907 intptr_t current_index, | 872 intptr_t current_index, |
908 GrowableArray<intptr_t>* parent, | 873 GrowableArray<intptr_t>* parent, |
909 GrowableArray<intptr_t>* label) { | 874 GrowableArray<intptr_t>* label) { |
910 intptr_t next_index = (*parent)[current_index]; | 875 intptr_t next_index = (*parent)[current_index]; |
911 if (next_index > start_index) { | 876 if (next_index > start_index) { |
912 CompressPath(start_index, next_index, parent, label); | 877 CompressPath(start_index, next_index, parent, label); |
913 (*label)[current_index] = | 878 (*label)[current_index] = |
914 Utils::Minimum((*label)[current_index], (*label)[next_index]); | 879 Utils::Minimum((*label)[current_index], (*label)[next_index]); |
915 (*parent)[current_index] = (*parent)[next_index]; | 880 (*parent)[current_index] = (*parent)[next_index]; |
916 } | 881 } |
917 } | 882 } |
918 | 883 |
919 | |
920 void FlowGraph::InsertPhis(const GrowableArray<BlockEntryInstr*>& preorder, | 884 void FlowGraph::InsertPhis(const GrowableArray<BlockEntryInstr*>& preorder, |
921 const GrowableArray<BitVector*>& assigned_vars, | 885 const GrowableArray<BitVector*>& assigned_vars, |
922 const GrowableArray<BitVector*>& dom_frontier, | 886 const GrowableArray<BitVector*>& dom_frontier, |
923 GrowableArray<PhiInstr*>* live_phis) { | 887 GrowableArray<PhiInstr*>* live_phis) { |
924 const intptr_t block_count = preorder.length(); | 888 const intptr_t block_count = preorder.length(); |
925 // Map preorder block number to the highest variable index that has a phi | 889 // Map preorder block number to the highest variable index that has a phi |
926 // in that block. Use it to avoid inserting multiple phis for the same | 890 // in that block. Use it to avoid inserting multiple phis for the same |
927 // variable. | 891 // variable. |
928 GrowableArray<intptr_t> has_already(block_count); | 892 GrowableArray<intptr_t> has_already(block_count); |
929 // Map preorder block number to the highest variable index for which the | 893 // Map preorder block number to the highest variable index for which the |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
969 if (work[index] < var_index) { | 933 if (work[index] < var_index) { |
970 work[index] = var_index; | 934 work[index] = var_index; |
971 worklist.Add(block); | 935 worklist.Add(block); |
972 } | 936 } |
973 } | 937 } |
974 } | 938 } |
975 } | 939 } |
976 } | 940 } |
977 } | 941 } |
978 | 942 |
979 | |
980 void FlowGraph::Rename(GrowableArray<PhiInstr*>* live_phis, | 943 void FlowGraph::Rename(GrowableArray<PhiInstr*>* live_phis, |
981 VariableLivenessAnalysis* variable_liveness, | 944 VariableLivenessAnalysis* variable_liveness, |
982 ZoneGrowableArray<Definition*>* inlining_parameters) { | 945 ZoneGrowableArray<Definition*>* inlining_parameters) { |
983 GraphEntryInstr* entry = graph_entry(); | 946 GraphEntryInstr* entry = graph_entry(); |
984 | 947 |
985 // Initial renaming environment. | 948 // Initial renaming environment. |
986 GrowableArray<Definition*> env(variable_count()); | 949 GrowableArray<Definition*> env(variable_count()); |
987 | 950 |
988 // Add global constants to the initial definitions. | 951 // Add global constants to the initial definitions. |
989 constant_null_ = GetConstant(Object::ZoneHandle()); | 952 constant_null_ = GetConstant(Object::ZoneHandle()); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1063 | 1026 |
1064 if (entry->SuccessorCount() > 1) { | 1027 if (entry->SuccessorCount() > 1) { |
1065 // Functions with try-catch have a fixed area of stack slots reserved | 1028 // Functions with try-catch have a fixed area of stack slots reserved |
1066 // so that all local variables are stored at a known location when | 1029 // so that all local variables are stored at a known location when |
1067 // on entry to the catch. | 1030 // on entry to the catch. |
1068 entry->set_fixed_slot_count(num_stack_locals() + num_copied_params()); | 1031 entry->set_fixed_slot_count(num_stack_locals() + num_copied_params()); |
1069 } | 1032 } |
1070 RenameRecursive(entry, &env, live_phis, variable_liveness); | 1033 RenameRecursive(entry, &env, live_phis, variable_liveness); |
1071 } | 1034 } |
1072 | 1035 |
1073 | |
1074 void FlowGraph::AttachEnvironment(Instruction* instr, | 1036 void FlowGraph::AttachEnvironment(Instruction* instr, |
1075 GrowableArray<Definition*>* env) { | 1037 GrowableArray<Definition*>* env) { |
1076 Environment* deopt_env = | 1038 Environment* deopt_env = |
1077 Environment::From(zone(), *env, num_non_copied_params_, parsed_function_); | 1039 Environment::From(zone(), *env, num_non_copied_params_, parsed_function_); |
1078 if (instr->IsClosureCall()) { | 1040 if (instr->IsClosureCall()) { |
1079 deopt_env = | 1041 deopt_env = |
1080 deopt_env->DeepCopy(zone(), deopt_env->Length() - instr->InputCount()); | 1042 deopt_env->DeepCopy(zone(), deopt_env->Length() - instr->InputCount()); |
1081 } | 1043 } |
1082 instr->SetEnvironment(deopt_env); | 1044 instr->SetEnvironment(deopt_env); |
1083 for (Environment::DeepIterator it(deopt_env); !it.Done(); it.Advance()) { | 1045 for (Environment::DeepIterator it(deopt_env); !it.Done(); it.Advance()) { |
1084 Value* use = it.CurrentValue(); | 1046 Value* use = it.CurrentValue(); |
1085 use->definition()->AddEnvUse(use); | 1047 use->definition()->AddEnvUse(use); |
1086 } | 1048 } |
1087 if (instr->ComputeCanDeoptimize()) { | 1049 if (instr->ComputeCanDeoptimize()) { |
1088 instr->env()->set_deopt_id(instr->deopt_id()); | 1050 instr->env()->set_deopt_id(instr->deopt_id()); |
1089 } | 1051 } |
1090 } | 1052 } |
1091 | 1053 |
1092 | |
1093 void FlowGraph::RenameRecursive(BlockEntryInstr* block_entry, | 1054 void FlowGraph::RenameRecursive(BlockEntryInstr* block_entry, |
1094 GrowableArray<Definition*>* env, | 1055 GrowableArray<Definition*>* env, |
1095 GrowableArray<PhiInstr*>* live_phis, | 1056 GrowableArray<PhiInstr*>* live_phis, |
1096 VariableLivenessAnalysis* variable_liveness) { | 1057 VariableLivenessAnalysis* variable_liveness) { |
1097 // 1. Process phis first. | 1058 // 1. Process phis first. |
1098 if (block_entry->IsJoinEntry()) { | 1059 if (block_entry->IsJoinEntry()) { |
1099 JoinEntryInstr* join = block_entry->AsJoinEntry(); | 1060 JoinEntryInstr* join = block_entry->AsJoinEntry(); |
1100 if (join->phis() != NULL) { | 1061 if (join->phis() != NULL) { |
1101 for (intptr_t i = 0; i < join->phis()->length(); ++i) { | 1062 for (intptr_t i = 0; i < join->phis()->length(); ++i) { |
1102 PhiInstr* phi = (*join->phis())[i]; | 1063 PhiInstr* phi = (*join->phis())[i]; |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1281 if (phi != NULL) { | 1242 if (phi != NULL) { |
1282 // Rename input operand. | 1243 // Rename input operand. |
1283 Value* use = new (zone()) Value((*env)[i]); | 1244 Value* use = new (zone()) Value((*env)[i]); |
1284 phi->SetInputAt(pred_index, use); | 1245 phi->SetInputAt(pred_index, use); |
1285 } | 1246 } |
1286 } | 1247 } |
1287 } | 1248 } |
1288 } | 1249 } |
1289 } | 1250 } |
1290 | 1251 |
1291 | |
1292 void FlowGraph::RemoveDeadPhis(GrowableArray<PhiInstr*>* live_phis) { | 1252 void FlowGraph::RemoveDeadPhis(GrowableArray<PhiInstr*>* live_phis) { |
1293 // Augment live_phis with those that have implicit real used at | 1253 // Augment live_phis with those that have implicit real used at |
1294 // potentially throwing instructions if there is a try-catch in this graph. | 1254 // potentially throwing instructions if there is a try-catch in this graph. |
1295 if (graph_entry()->SuccessorCount() > 1) { | 1255 if (graph_entry()->SuccessorCount() > 1) { |
1296 for (BlockIterator it(postorder_iterator()); !it.Done(); it.Advance()) { | 1256 for (BlockIterator it(postorder_iterator()); !it.Done(); it.Advance()) { |
1297 JoinEntryInstr* join = it.Current()->AsJoinEntry(); | 1257 JoinEntryInstr* join = it.Current()->AsJoinEntry(); |
1298 if (join == NULL) continue; | 1258 if (join == NULL) continue; |
1299 for (PhiIterator phi_it(join); !phi_it.Done(); phi_it.Advance()) { | 1259 for (PhiIterator phi_it(join); !phi_it.Done(); phi_it.Advance()) { |
1300 PhiInstr* phi = phi_it.Current(); | 1260 PhiInstr* phi = phi_it.Current(); |
1301 if (phi == NULL || phi->is_alive() || (phi->input_use_list() != NULL) || | 1261 if (phi == NULL || phi->is_alive() || (phi->input_use_list() != NULL) || |
(...skipping 25 matching lines...) Expand all Loading... |
1327 } | 1287 } |
1328 } | 1288 } |
1329 } | 1289 } |
1330 | 1290 |
1331 for (BlockIterator it(postorder_iterator()); !it.Done(); it.Advance()) { | 1291 for (BlockIterator it(postorder_iterator()); !it.Done(); it.Advance()) { |
1332 JoinEntryInstr* join = it.Current()->AsJoinEntry(); | 1292 JoinEntryInstr* join = it.Current()->AsJoinEntry(); |
1333 if (join != NULL) join->RemoveDeadPhis(constant_dead()); | 1293 if (join != NULL) join->RemoveDeadPhis(constant_dead()); |
1334 } | 1294 } |
1335 } | 1295 } |
1336 | 1296 |
1337 | |
1338 RedefinitionInstr* FlowGraph::EnsureRedefinition(Instruction* prev, | 1297 RedefinitionInstr* FlowGraph::EnsureRedefinition(Instruction* prev, |
1339 Definition* original, | 1298 Definition* original, |
1340 CompileType compile_type) { | 1299 CompileType compile_type) { |
1341 RedefinitionInstr* first = prev->next()->AsRedefinition(); | 1300 RedefinitionInstr* first = prev->next()->AsRedefinition(); |
1342 if (first != NULL && (first->constrained_type() != NULL)) { | 1301 if (first != NULL && (first->constrained_type() != NULL)) { |
1343 if ((first->value()->definition() == original) && | 1302 if ((first->value()->definition() == original) && |
1344 first->constrained_type()->IsEqualTo(&compile_type)) { | 1303 first->constrained_type()->IsEqualTo(&compile_type)) { |
1345 // Already redefined. Do nothing. | 1304 // Already redefined. Do nothing. |
1346 return NULL; | 1305 return NULL; |
1347 } | 1306 } |
1348 } | 1307 } |
1349 RedefinitionInstr* redef = new RedefinitionInstr(new Value(original)); | 1308 RedefinitionInstr* redef = new RedefinitionInstr(new Value(original)); |
1350 redef->set_constrained_type(new CompileType(compile_type)); | 1309 redef->set_constrained_type(new CompileType(compile_type)); |
1351 InsertAfter(prev, redef, NULL, FlowGraph::kValue); | 1310 InsertAfter(prev, redef, NULL, FlowGraph::kValue); |
1352 RenameDominatedUses(original, redef, redef); | 1311 RenameDominatedUses(original, redef, redef); |
1353 return redef; | 1312 return redef; |
1354 } | 1313 } |
1355 | 1314 |
1356 | |
1357 void FlowGraph::RemoveRedefinitions() { | 1315 void FlowGraph::RemoveRedefinitions() { |
1358 // Remove redefinition instructions inserted to inhibit hoisting. | 1316 // Remove redefinition instructions inserted to inhibit hoisting. |
1359 for (BlockIterator block_it = reverse_postorder_iterator(); !block_it.Done(); | 1317 for (BlockIterator block_it = reverse_postorder_iterator(); !block_it.Done(); |
1360 block_it.Advance()) { | 1318 block_it.Advance()) { |
1361 thread()->CheckForSafepoint(); | 1319 thread()->CheckForSafepoint(); |
1362 for (ForwardInstructionIterator instr_it(block_it.Current()); | 1320 for (ForwardInstructionIterator instr_it(block_it.Current()); |
1363 !instr_it.Done(); instr_it.Advance()) { | 1321 !instr_it.Done(); instr_it.Advance()) { |
1364 RedefinitionInstr* redefinition = instr_it.Current()->AsRedefinition(); | 1322 RedefinitionInstr* redefinition = instr_it.Current()->AsRedefinition(); |
1365 if (redefinition != NULL) { | 1323 if (redefinition != NULL) { |
1366 Definition* original; | 1324 Definition* original; |
1367 do { | 1325 do { |
1368 original = redefinition->value()->definition(); | 1326 original = redefinition->value()->definition(); |
1369 } while (original->IsRedefinition()); | 1327 } while (original->IsRedefinition()); |
1370 redefinition->ReplaceUsesWith(original); | 1328 redefinition->ReplaceUsesWith(original); |
1371 instr_it.RemoveCurrentFromGraph(); | 1329 instr_it.RemoveCurrentFromGraph(); |
1372 } | 1330 } |
1373 } | 1331 } |
1374 } | 1332 } |
1375 } | 1333 } |
1376 | 1334 |
1377 | |
1378 // Find the natural loop for the back edge m->n and attach loop information | 1335 // Find the natural loop for the back edge m->n and attach loop information |
1379 // to block n (loop header). The algorithm is described in "Advanced Compiler | 1336 // to block n (loop header). The algorithm is described in "Advanced Compiler |
1380 // Design & Implementation" (Muchnick) p192. | 1337 // Design & Implementation" (Muchnick) p192. |
1381 BitVector* FlowGraph::FindLoop(BlockEntryInstr* m, BlockEntryInstr* n) const { | 1338 BitVector* FlowGraph::FindLoop(BlockEntryInstr* m, BlockEntryInstr* n) const { |
1382 GrowableArray<BlockEntryInstr*> stack; | 1339 GrowableArray<BlockEntryInstr*> stack; |
1383 BitVector* loop = new (zone()) BitVector(zone(), preorder_.length()); | 1340 BitVector* loop = new (zone()) BitVector(zone(), preorder_.length()); |
1384 | 1341 |
1385 loop->Add(n->preorder_number()); | 1342 loop->Add(n->preorder_number()); |
1386 if (n != m) { | 1343 if (n != m) { |
1387 loop->Add(m->preorder_number()); | 1344 loop->Add(m->preorder_number()); |
1388 stack.Add(m); | 1345 stack.Add(m); |
1389 } | 1346 } |
1390 | 1347 |
1391 while (!stack.is_empty()) { | 1348 while (!stack.is_empty()) { |
1392 BlockEntryInstr* p = stack.RemoveLast(); | 1349 BlockEntryInstr* p = stack.RemoveLast(); |
1393 for (intptr_t i = 0; i < p->PredecessorCount(); ++i) { | 1350 for (intptr_t i = 0; i < p->PredecessorCount(); ++i) { |
1394 BlockEntryInstr* q = p->PredecessorAt(i); | 1351 BlockEntryInstr* q = p->PredecessorAt(i); |
1395 if (!loop->Contains(q->preorder_number())) { | 1352 if (!loop->Contains(q->preorder_number())) { |
1396 loop->Add(q->preorder_number()); | 1353 loop->Add(q->preorder_number()); |
1397 stack.Add(q); | 1354 stack.Add(q); |
1398 } | 1355 } |
1399 } | 1356 } |
1400 } | 1357 } |
1401 return loop; | 1358 return loop; |
1402 } | 1359 } |
1403 | 1360 |
1404 | |
1405 ZoneGrowableArray<BlockEntryInstr*>* FlowGraph::ComputeLoops() const { | 1361 ZoneGrowableArray<BlockEntryInstr*>* FlowGraph::ComputeLoops() const { |
1406 ZoneGrowableArray<BlockEntryInstr*>* loop_headers = | 1362 ZoneGrowableArray<BlockEntryInstr*>* loop_headers = |
1407 new (zone()) ZoneGrowableArray<BlockEntryInstr*>(); | 1363 new (zone()) ZoneGrowableArray<BlockEntryInstr*>(); |
1408 | 1364 |
1409 for (BlockIterator it = postorder_iterator(); !it.Done(); it.Advance()) { | 1365 for (BlockIterator it = postorder_iterator(); !it.Done(); it.Advance()) { |
1410 BlockEntryInstr* block = it.Current(); | 1366 BlockEntryInstr* block = it.Current(); |
1411 for (intptr_t i = 0; i < block->PredecessorCount(); ++i) { | 1367 for (intptr_t i = 0; i < block->PredecessorCount(); ++i) { |
1412 BlockEntryInstr* pred = block->PredecessorAt(i); | 1368 BlockEntryInstr* pred = block->PredecessorAt(i); |
1413 if (block->Dominates(pred)) { | 1369 if (block->Dominates(pred)) { |
1414 if (FLAG_trace_optimization) { | 1370 if (FLAG_trace_optimization) { |
(...skipping 24 matching lines...) Expand all Loading... |
1439 OS::Print("Loop header B%" Pd "\n", header->block_id()); | 1395 OS::Print("Loop header B%" Pd "\n", header->block_id()); |
1440 for (BitVector::Iterator it(header->loop_info()); !it.Done(); | 1396 for (BitVector::Iterator it(header->loop_info()); !it.Done(); |
1441 it.Advance()) { | 1397 it.Advance()) { |
1442 OS::Print(" B%" Pd "\n", preorder_[it.Current()]->block_id()); | 1398 OS::Print(" B%" Pd "\n", preorder_[it.Current()]->block_id()); |
1443 } | 1399 } |
1444 } | 1400 } |
1445 } | 1401 } |
1446 return loop_headers; | 1402 return loop_headers; |
1447 } | 1403 } |
1448 | 1404 |
1449 | |
1450 intptr_t FlowGraph::InstructionCount() const { | 1405 intptr_t FlowGraph::InstructionCount() const { |
1451 intptr_t size = 0; | 1406 intptr_t size = 0; |
1452 // Iterate each block, skipping the graph entry. | 1407 // Iterate each block, skipping the graph entry. |
1453 for (intptr_t i = 1; i < preorder_.length(); ++i) { | 1408 for (intptr_t i = 1; i < preorder_.length(); ++i) { |
1454 for (ForwardInstructionIterator it(preorder_[i]); !it.Done(); | 1409 for (ForwardInstructionIterator it(preorder_[i]); !it.Done(); |
1455 it.Advance()) { | 1410 it.Advance()) { |
1456 ++size; | 1411 ++size; |
1457 } | 1412 } |
1458 } | 1413 } |
1459 return size; | 1414 return size; |
1460 } | 1415 } |
1461 | 1416 |
1462 | |
1463 void FlowGraph::ComputeBlockEffects() { | 1417 void FlowGraph::ComputeBlockEffects() { |
1464 block_effects_ = new (zone()) BlockEffects(this); | 1418 block_effects_ = new (zone()) BlockEffects(this); |
1465 } | 1419 } |
1466 | 1420 |
1467 | |
1468 BlockEffects::BlockEffects(FlowGraph* flow_graph) | 1421 BlockEffects::BlockEffects(FlowGraph* flow_graph) |
1469 : available_at_(flow_graph->postorder().length()) { | 1422 : available_at_(flow_graph->postorder().length()) { |
1470 // We are tracking a single effect. | 1423 // We are tracking a single effect. |
1471 ASSERT(EffectSet::kLastEffect == 1); | 1424 ASSERT(EffectSet::kLastEffect == 1); |
1472 Zone* zone = flow_graph->zone(); | 1425 Zone* zone = flow_graph->zone(); |
1473 const intptr_t block_count = flow_graph->postorder().length(); | 1426 const intptr_t block_count = flow_graph->postorder().length(); |
1474 | 1427 |
1475 // Set of blocks that contain side-effects. | 1428 // Set of blocks that contain side-effects. |
1476 BitVector* kill = new (zone) BitVector(zone, block_count); | 1429 BitVector* kill = new (zone) BitVector(zone, block_count); |
1477 | 1430 |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1538 available_after[block_num]->CopyFrom(temp); | 1491 available_after[block_num]->CopyFrom(temp); |
1539 // Block is always available after itself. | 1492 // Block is always available after itself. |
1540 available_after[block_num]->Add(block_num); | 1493 available_after[block_num]->Add(block_num); |
1541 } | 1494 } |
1542 changed = true; | 1495 changed = true; |
1543 } | 1496 } |
1544 } | 1497 } |
1545 } while (changed); | 1498 } while (changed); |
1546 } | 1499 } |
1547 | 1500 |
1548 | |
1549 bool BlockEffects::IsAvailableAt(Instruction* instr, | 1501 bool BlockEffects::IsAvailableAt(Instruction* instr, |
1550 BlockEntryInstr* block) const { | 1502 BlockEntryInstr* block) const { |
1551 return (instr->Dependencies().IsNone()) || | 1503 return (instr->Dependencies().IsNone()) || |
1552 IsSideEffectFreePath(instr->GetBlock(), block); | 1504 IsSideEffectFreePath(instr->GetBlock(), block); |
1553 } | 1505 } |
1554 | 1506 |
1555 | |
1556 bool BlockEffects::CanBeMovedTo(Instruction* instr, | 1507 bool BlockEffects::CanBeMovedTo(Instruction* instr, |
1557 BlockEntryInstr* block) const { | 1508 BlockEntryInstr* block) const { |
1558 return (instr->Dependencies().IsNone()) || | 1509 return (instr->Dependencies().IsNone()) || |
1559 IsSideEffectFreePath(block, instr->GetBlock()); | 1510 IsSideEffectFreePath(block, instr->GetBlock()); |
1560 } | 1511 } |
1561 | 1512 |
1562 | |
1563 bool BlockEffects::IsSideEffectFreePath(BlockEntryInstr* from, | 1513 bool BlockEffects::IsSideEffectFreePath(BlockEntryInstr* from, |
1564 BlockEntryInstr* to) const { | 1514 BlockEntryInstr* to) const { |
1565 return available_at_[to->postorder_number()]->Contains( | 1515 return available_at_[to->postorder_number()]->Contains( |
1566 from->postorder_number()); | 1516 from->postorder_number()); |
1567 } | 1517 } |
1568 | 1518 |
1569 | |
1570 // Quick access to the current zone. | 1519 // Quick access to the current zone. |
1571 #define Z (zone()) | 1520 #define Z (zone()) |
1572 | 1521 |
1573 | |
1574 void FlowGraph::ConvertUse(Value* use, Representation from_rep) { | 1522 void FlowGraph::ConvertUse(Value* use, Representation from_rep) { |
1575 const Representation to_rep = | 1523 const Representation to_rep = |
1576 use->instruction()->RequiredInputRepresentation(use->use_index()); | 1524 use->instruction()->RequiredInputRepresentation(use->use_index()); |
1577 if (from_rep == to_rep || to_rep == kNoRepresentation) { | 1525 if (from_rep == to_rep || to_rep == kNoRepresentation) { |
1578 return; | 1526 return; |
1579 } | 1527 } |
1580 InsertConversion(from_rep, to_rep, use, /*is_environment_use=*/false); | 1528 InsertConversion(from_rep, to_rep, use, /*is_environment_use=*/false); |
1581 } | 1529 } |
1582 | 1530 |
1583 | |
1584 static bool IsUnboxedInteger(Representation rep) { | 1531 static bool IsUnboxedInteger(Representation rep) { |
1585 return (rep == kUnboxedInt32) || (rep == kUnboxedUint32) || | 1532 return (rep == kUnboxedInt32) || (rep == kUnboxedUint32) || |
1586 (rep == kUnboxedMint); | 1533 (rep == kUnboxedMint); |
1587 } | 1534 } |
1588 | 1535 |
1589 | |
1590 static bool ShouldInlineSimd() { | 1536 static bool ShouldInlineSimd() { |
1591 return FlowGraphCompiler::SupportsUnboxedSimd128(); | 1537 return FlowGraphCompiler::SupportsUnboxedSimd128(); |
1592 } | 1538 } |
1593 | 1539 |
1594 | |
1595 static bool CanUnboxDouble() { | 1540 static bool CanUnboxDouble() { |
1596 return FlowGraphCompiler::SupportsUnboxedDoubles(); | 1541 return FlowGraphCompiler::SupportsUnboxedDoubles(); |
1597 } | 1542 } |
1598 | 1543 |
1599 | |
1600 static bool CanConvertUnboxedMintToDouble() { | 1544 static bool CanConvertUnboxedMintToDouble() { |
1601 return FlowGraphCompiler::CanConvertUnboxedMintToDouble(); | 1545 return FlowGraphCompiler::CanConvertUnboxedMintToDouble(); |
1602 } | 1546 } |
1603 | 1547 |
1604 | |
1605 void FlowGraph::InsertConversion(Representation from, | 1548 void FlowGraph::InsertConversion(Representation from, |
1606 Representation to, | 1549 Representation to, |
1607 Value* use, | 1550 Value* use, |
1608 bool is_environment_use) { | 1551 bool is_environment_use) { |
1609 Instruction* insert_before; | 1552 Instruction* insert_before; |
1610 Instruction* deopt_target; | 1553 Instruction* deopt_target; |
1611 PhiInstr* phi = use->instruction()->AsPhi(); | 1554 PhiInstr* phi = use->instruction()->AsPhi(); |
1612 if (phi != NULL) { | 1555 if (phi != NULL) { |
1613 ASSERT(phi->is_alive()); | 1556 ASSERT(phi->is_alive()); |
1614 // For phis conversions have to be inserted in the predecessor. | 1557 // For phis conversions have to be inserted in the predecessor. |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1666 use->BindTo(converted); | 1609 use->BindTo(converted); |
1667 } | 1610 } |
1668 | 1611 |
1669 if ((to == kUnboxedInt32) && (phi != NULL)) { | 1612 if ((to == kUnboxedInt32) && (phi != NULL)) { |
1670 // Int32 phis are unboxed optimistically. Ensure that unboxing | 1613 // Int32 phis are unboxed optimistically. Ensure that unboxing |
1671 // has deoptimization target attached from the goto instruction. | 1614 // has deoptimization target attached from the goto instruction. |
1672 CopyDeoptTarget(converted, insert_before); | 1615 CopyDeoptTarget(converted, insert_before); |
1673 } | 1616 } |
1674 } | 1617 } |
1675 | 1618 |
1676 | |
1677 void FlowGraph::ConvertEnvironmentUse(Value* use, Representation from_rep) { | 1619 void FlowGraph::ConvertEnvironmentUse(Value* use, Representation from_rep) { |
1678 const Representation to_rep = kTagged; | 1620 const Representation to_rep = kTagged; |
1679 if (from_rep == to_rep) { | 1621 if (from_rep == to_rep) { |
1680 return; | 1622 return; |
1681 } | 1623 } |
1682 InsertConversion(from_rep, to_rep, use, /*is_environment_use=*/true); | 1624 InsertConversion(from_rep, to_rep, use, /*is_environment_use=*/true); |
1683 } | 1625 } |
1684 | 1626 |
1685 | |
1686 void FlowGraph::InsertConversionsFor(Definition* def) { | 1627 void FlowGraph::InsertConversionsFor(Definition* def) { |
1687 const Representation from_rep = def->representation(); | 1628 const Representation from_rep = def->representation(); |
1688 | 1629 |
1689 for (Value::Iterator it(def->input_use_list()); !it.Done(); it.Advance()) { | 1630 for (Value::Iterator it(def->input_use_list()); !it.Done(); it.Advance()) { |
1690 ConvertUse(it.Current(), from_rep); | 1631 ConvertUse(it.Current(), from_rep); |
1691 } | 1632 } |
1692 | 1633 |
1693 if (graph_entry()->SuccessorCount() > 1) { | 1634 if (graph_entry()->SuccessorCount() > 1) { |
1694 for (Value::Iterator it(def->env_use_list()); !it.Done(); it.Advance()) { | 1635 for (Value::Iterator it(def->env_use_list()); !it.Done(); it.Advance()) { |
1695 Value* use = it.Current(); | 1636 Value* use = it.Current(); |
1696 if (use->instruction()->MayThrow() && | 1637 if (use->instruction()->MayThrow() && |
1697 use->instruction()->GetBlock()->InsideTryBlock()) { | 1638 use->instruction()->GetBlock()->InsideTryBlock()) { |
1698 // Environment uses at calls inside try-blocks must be converted to | 1639 // Environment uses at calls inside try-blocks must be converted to |
1699 // tagged representation. | 1640 // tagged representation. |
1700 ConvertEnvironmentUse(it.Current(), from_rep); | 1641 ConvertEnvironmentUse(it.Current(), from_rep); |
1701 } | 1642 } |
1702 } | 1643 } |
1703 } | 1644 } |
1704 } | 1645 } |
1705 | 1646 |
1706 | |
1707 static void UnboxPhi(PhiInstr* phi) { | 1647 static void UnboxPhi(PhiInstr* phi) { |
1708 Representation unboxed = phi->representation(); | 1648 Representation unboxed = phi->representation(); |
1709 | 1649 |
1710 switch (phi->Type()->ToCid()) { | 1650 switch (phi->Type()->ToCid()) { |
1711 case kDoubleCid: | 1651 case kDoubleCid: |
1712 if (CanUnboxDouble()) { | 1652 if (CanUnboxDouble()) { |
1713 unboxed = kUnboxedDouble; | 1653 unboxed = kUnboxedDouble; |
1714 } | 1654 } |
1715 break; | 1655 break; |
1716 case kFloat32x4Cid: | 1656 case kFloat32x4Cid: |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1777 unboxed = | 1717 unboxed = |
1778 RangeUtils::Fits(phi->range(), RangeBoundary::kRangeBoundaryInt32) | 1718 RangeUtils::Fits(phi->range(), RangeBoundary::kRangeBoundaryInt32) |
1779 ? kUnboxedInt32 | 1719 ? kUnboxedInt32 |
1780 : kUnboxedMint; | 1720 : kUnboxedMint; |
1781 } | 1721 } |
1782 } | 1722 } |
1783 | 1723 |
1784 phi->set_representation(unboxed); | 1724 phi->set_representation(unboxed); |
1785 } | 1725 } |
1786 | 1726 |
1787 | |
1788 void FlowGraph::SelectRepresentations() { | 1727 void FlowGraph::SelectRepresentations() { |
1789 // Conservatively unbox all phis that were proven to be of Double, | 1728 // Conservatively unbox all phis that were proven to be of Double, |
1790 // Float32x4, or Int32x4 type. | 1729 // Float32x4, or Int32x4 type. |
1791 for (BlockIterator block_it = reverse_postorder_iterator(); !block_it.Done(); | 1730 for (BlockIterator block_it = reverse_postorder_iterator(); !block_it.Done(); |
1792 block_it.Advance()) { | 1731 block_it.Advance()) { |
1793 JoinEntryInstr* join_entry = block_it.Current()->AsJoinEntry(); | 1732 JoinEntryInstr* join_entry = block_it.Current()->AsJoinEntry(); |
1794 if (join_entry != NULL) { | 1733 if (join_entry != NULL) { |
1795 for (PhiIterator it(join_entry); !it.Done(); it.Advance()) { | 1734 for (PhiIterator it(join_entry); !it.Done(); it.Advance()) { |
1796 PhiInstr* phi = it.Current(); | 1735 PhiInstr* phi = it.Current(); |
1797 UnboxPhi(phi); | 1736 UnboxPhi(phi); |
(...skipping 29 matching lines...) Expand all Loading... |
1827 } | 1766 } |
1828 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { | 1767 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { |
1829 Definition* def = it.Current()->AsDefinition(); | 1768 Definition* def = it.Current()->AsDefinition(); |
1830 if (def != NULL) { | 1769 if (def != NULL) { |
1831 InsertConversionsFor(def); | 1770 InsertConversionsFor(def); |
1832 } | 1771 } |
1833 } | 1772 } |
1834 } | 1773 } |
1835 } | 1774 } |
1836 | 1775 |
1837 | |
1838 #if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_IA32) | 1776 #if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_IA32) |
1839 // Smi widening pass is only meaningful on platforms where Smi | 1777 // Smi widening pass is only meaningful on platforms where Smi |
1840 // is smaller than 32bit. For now only support it on ARM and ia32. | 1778 // is smaller than 32bit. For now only support it on ARM and ia32. |
1841 static bool CanBeWidened(BinarySmiOpInstr* smi_op) { | 1779 static bool CanBeWidened(BinarySmiOpInstr* smi_op) { |
1842 return BinaryInt32OpInstr::IsSupported(smi_op->op_kind(), smi_op->left(), | 1780 return BinaryInt32OpInstr::IsSupported(smi_op->op_kind(), smi_op->left(), |
1843 smi_op->right()); | 1781 smi_op->right()); |
1844 } | 1782 } |
1845 | 1783 |
1846 | |
1847 static bool BenefitsFromWidening(BinarySmiOpInstr* smi_op) { | 1784 static bool BenefitsFromWidening(BinarySmiOpInstr* smi_op) { |
1848 // TODO(vegorov): when shifts with non-constants shift count are supported | 1785 // TODO(vegorov): when shifts with non-constants shift count are supported |
1849 // add them here as we save untagging for the count. | 1786 // add them here as we save untagging for the count. |
1850 switch (smi_op->op_kind()) { | 1787 switch (smi_op->op_kind()) { |
1851 case Token::kMUL: | 1788 case Token::kMUL: |
1852 case Token::kSHR: | 1789 case Token::kSHR: |
1853 // For kMUL we save untagging of the argument for kSHR | 1790 // For kMUL we save untagging of the argument for kSHR |
1854 // we save tagging of the result. | 1791 // we save tagging of the result. |
1855 return true; | 1792 return true; |
1856 | 1793 |
1857 default: | 1794 default: |
1858 return false; | 1795 return false; |
1859 } | 1796 } |
1860 } | 1797 } |
1861 | 1798 |
1862 | |
1863 void FlowGraph::WidenSmiToInt32() { | 1799 void FlowGraph::WidenSmiToInt32() { |
1864 GrowableArray<BinarySmiOpInstr*> candidates; | 1800 GrowableArray<BinarySmiOpInstr*> candidates; |
1865 | 1801 |
1866 // Step 1. Collect all instructions that potentially benefit from widening of | 1802 // Step 1. Collect all instructions that potentially benefit from widening of |
1867 // their operands (or their result) into int32 range. | 1803 // their operands (or their result) into int32 range. |
1868 for (BlockIterator block_it = reverse_postorder_iterator(); !block_it.Done(); | 1804 for (BlockIterator block_it = reverse_postorder_iterator(); !block_it.Done(); |
1869 block_it.Advance()) { | 1805 block_it.Advance()) { |
1870 for (ForwardInstructionIterator instr_it(block_it.Current()); | 1806 for (ForwardInstructionIterator instr_it(block_it.Current()); |
1871 !instr_it.Done(); instr_it.Advance()) { | 1807 !instr_it.Done(); instr_it.Advance()) { |
1872 BinarySmiOpInstr* smi_op = instr_it.Current()->AsBinarySmiOp(); | 1808 BinarySmiOpInstr* smi_op = instr_it.Current()->AsBinarySmiOp(); |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2042 } | 1978 } |
2043 #else | 1979 #else |
2044 void FlowGraph::WidenSmiToInt32() { | 1980 void FlowGraph::WidenSmiToInt32() { |
2045 // TODO(vegorov) ideally on 64-bit platforms we would like to narrow smi | 1981 // TODO(vegorov) ideally on 64-bit platforms we would like to narrow smi |
2046 // operations to 32-bit where it saves tagging and untagging and allows | 1982 // operations to 32-bit where it saves tagging and untagging and allows |
2047 // to use shorted (and faster) instructions. But we currently don't | 1983 // to use shorted (and faster) instructions. But we currently don't |
2048 // save enough range information in the ICData to drive this decision. | 1984 // save enough range information in the ICData to drive this decision. |
2049 } | 1985 } |
2050 #endif | 1986 #endif |
2051 | 1987 |
2052 | |
2053 void FlowGraph::EliminateEnvironments() { | 1988 void FlowGraph::EliminateEnvironments() { |
2054 // After this pass we can no longer perform LICM and hoist instructions | 1989 // After this pass we can no longer perform LICM and hoist instructions |
2055 // that can deoptimize. | 1990 // that can deoptimize. |
2056 | 1991 |
2057 disallow_licm(); | 1992 disallow_licm(); |
2058 for (BlockIterator block_it = reverse_postorder_iterator(); !block_it.Done(); | 1993 for (BlockIterator block_it = reverse_postorder_iterator(); !block_it.Done(); |
2059 block_it.Advance()) { | 1994 block_it.Advance()) { |
2060 BlockEntryInstr* block = block_it.Current(); | 1995 BlockEntryInstr* block = block_it.Current(); |
2061 if (!block->IsCatchBlockEntry()) { | 1996 if (!block->IsCatchBlockEntry()) { |
2062 block->RemoveEnvironment(); | 1997 block->RemoveEnvironment(); |
2063 } | 1998 } |
2064 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 1999 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
2065 Instruction* current = it.Current(); | 2000 Instruction* current = it.Current(); |
2066 if (!current->ComputeCanDeoptimize() && | 2001 if (!current->ComputeCanDeoptimize() && |
2067 (!current->MayThrow() || !current->GetBlock()->InsideTryBlock())) { | 2002 (!current->MayThrow() || !current->GetBlock()->InsideTryBlock())) { |
2068 // Instructions that can throw need an environment for optimized | 2003 // Instructions that can throw need an environment for optimized |
2069 // try-catch. | 2004 // try-catch. |
2070 // TODO(srdjan): --source-lines needs deopt environments to get at | 2005 // TODO(srdjan): --source-lines needs deopt environments to get at |
2071 // the code for this instruction, however, leaving the environment | 2006 // the code for this instruction, however, leaving the environment |
2072 // changes code. | 2007 // changes code. |
2073 current->RemoveEnvironment(); | 2008 current->RemoveEnvironment(); |
2074 } | 2009 } |
2075 } | 2010 } |
2076 } | 2011 } |
2077 } | 2012 } |
2078 | 2013 |
2079 | |
2080 bool FlowGraph::Canonicalize() { | 2014 bool FlowGraph::Canonicalize() { |
2081 bool changed = false; | 2015 bool changed = false; |
2082 | 2016 |
2083 for (BlockIterator block_it = reverse_postorder_iterator(); !block_it.Done(); | 2017 for (BlockIterator block_it = reverse_postorder_iterator(); !block_it.Done(); |
2084 block_it.Advance()) { | 2018 block_it.Advance()) { |
2085 for (ForwardInstructionIterator it(block_it.Current()); !it.Done(); | 2019 for (ForwardInstructionIterator it(block_it.Current()); !it.Done(); |
2086 it.Advance()) { | 2020 it.Advance()) { |
2087 Instruction* current = it.Current(); | 2021 Instruction* current = it.Current(); |
2088 if (current->HasUnmatchedInputRepresentations()) { | 2022 if (current->HasUnmatchedInputRepresentations()) { |
2089 // Can't canonicalize this instruction until all conversions for its | 2023 // Can't canonicalize this instruction until all conversions for its |
2090 // inputs are inserted. | 2024 // inputs are inserted. |
2091 continue; | 2025 continue; |
2092 } | 2026 } |
2093 | 2027 |
2094 Instruction* replacement = current->Canonicalize(this); | 2028 Instruction* replacement = current->Canonicalize(this); |
2095 | 2029 |
2096 if (replacement != current) { | 2030 if (replacement != current) { |
2097 // For non-definitions Canonicalize should return either NULL or | 2031 // For non-definitions Canonicalize should return either NULL or |
2098 // this. | 2032 // this. |
2099 ASSERT((replacement == NULL) || current->IsDefinition()); | 2033 ASSERT((replacement == NULL) || current->IsDefinition()); |
2100 ReplaceCurrentInstruction(&it, current, replacement); | 2034 ReplaceCurrentInstruction(&it, current, replacement); |
2101 changed = true; | 2035 changed = true; |
2102 } | 2036 } |
2103 } | 2037 } |
2104 } | 2038 } |
2105 return changed; | 2039 return changed; |
2106 } | 2040 } |
2107 | 2041 |
2108 | |
2109 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the | 2042 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the |
2110 // shift can be a truncating Smi shift-left and result is always Smi. | 2043 // shift can be a truncating Smi shift-left and result is always Smi. |
2111 // Merging occurs only per basic-block. | 2044 // Merging occurs only per basic-block. |
2112 void FlowGraph::TryOptimizePatterns() { | 2045 void FlowGraph::TryOptimizePatterns() { |
2113 if (!FLAG_truncating_left_shift) return; | 2046 if (!FLAG_truncating_left_shift) return; |
2114 GrowableArray<BinarySmiOpInstr*> div_mod_merge; | 2047 GrowableArray<BinarySmiOpInstr*> div_mod_merge; |
2115 GrowableArray<InvokeMathCFunctionInstr*> sin_cos_merge; | 2048 GrowableArray<InvokeMathCFunctionInstr*> sin_cos_merge; |
2116 for (BlockIterator block_it = reverse_postorder_iterator(); !block_it.Done(); | 2049 for (BlockIterator block_it = reverse_postorder_iterator(); !block_it.Done(); |
2117 block_it.Advance()) { | 2050 block_it.Advance()) { |
2118 // Merging only per basic-block. | 2051 // Merging only per basic-block. |
(...skipping 27 matching lines...) Expand all Loading... |
2146 if (math_unary->HasUses()) { | 2079 if (math_unary->HasUses()) { |
2147 sin_cos_merge.Add(math_unary); | 2080 sin_cos_merge.Add(math_unary); |
2148 } | 2081 } |
2149 } | 2082 } |
2150 } | 2083 } |
2151 } | 2084 } |
2152 TryMergeTruncDivMod(&div_mod_merge); | 2085 TryMergeTruncDivMod(&div_mod_merge); |
2153 } | 2086 } |
2154 } | 2087 } |
2155 | 2088 |
2156 | |
2157 // Returns true if use is dominated by the given instruction. | 2089 // Returns true if use is dominated by the given instruction. |
2158 // Note: uses that occur at instruction itself are not dominated by it. | 2090 // Note: uses that occur at instruction itself are not dominated by it. |
2159 static bool IsDominatedUse(Instruction* dom, Value* use) { | 2091 static bool IsDominatedUse(Instruction* dom, Value* use) { |
2160 BlockEntryInstr* dom_block = dom->GetBlock(); | 2092 BlockEntryInstr* dom_block = dom->GetBlock(); |
2161 | 2093 |
2162 Instruction* instr = use->instruction(); | 2094 Instruction* instr = use->instruction(); |
2163 | 2095 |
2164 PhiInstr* phi = instr->AsPhi(); | 2096 PhiInstr* phi = instr->AsPhi(); |
2165 if (phi != NULL) { | 2097 if (phi != NULL) { |
2166 return dom_block->Dominates(phi->block()->PredecessorAt(use->use_index())); | 2098 return dom_block->Dominates(phi->block()->PredecessorAt(use->use_index())); |
2167 } | 2099 } |
2168 | 2100 |
2169 BlockEntryInstr* use_block = instr->GetBlock(); | 2101 BlockEntryInstr* use_block = instr->GetBlock(); |
2170 if (use_block == dom_block) { | 2102 if (use_block == dom_block) { |
2171 // Fast path for the case of block entry. | 2103 // Fast path for the case of block entry. |
2172 if (dom_block == dom) return true; | 2104 if (dom_block == dom) return true; |
2173 | 2105 |
2174 for (Instruction* curr = dom->next(); curr != NULL; curr = curr->next()) { | 2106 for (Instruction* curr = dom->next(); curr != NULL; curr = curr->next()) { |
2175 if (curr == instr) return true; | 2107 if (curr == instr) return true; |
2176 } | 2108 } |
2177 | 2109 |
2178 return false; | 2110 return false; |
2179 } | 2111 } |
2180 | 2112 |
2181 return dom_block->Dominates(use_block); | 2113 return dom_block->Dominates(use_block); |
2182 } | 2114 } |
2183 | 2115 |
2184 | |
2185 void FlowGraph::RenameDominatedUses(Definition* def, | 2116 void FlowGraph::RenameDominatedUses(Definition* def, |
2186 Instruction* dom, | 2117 Instruction* dom, |
2187 Definition* other) { | 2118 Definition* other) { |
2188 for (Value::Iterator it(def->input_use_list()); !it.Done(); it.Advance()) { | 2119 for (Value::Iterator it(def->input_use_list()); !it.Done(); it.Advance()) { |
2189 Value* use = it.Current(); | 2120 Value* use = it.Current(); |
2190 if (IsDominatedUse(dom, use)) { | 2121 if (IsDominatedUse(dom, use)) { |
2191 use->BindTo(other); | 2122 use->BindTo(other); |
2192 } | 2123 } |
2193 } | 2124 } |
2194 } | 2125 } |
2195 | 2126 |
2196 | |
2197 void FlowGraph::RenameUsesDominatedByRedefinitions() { | 2127 void FlowGraph::RenameUsesDominatedByRedefinitions() { |
2198 for (BlockIterator block_it = reverse_postorder_iterator(); !block_it.Done(); | 2128 for (BlockIterator block_it = reverse_postorder_iterator(); !block_it.Done(); |
2199 block_it.Advance()) { | 2129 block_it.Advance()) { |
2200 for (ForwardInstructionIterator instr_it(block_it.Current()); | 2130 for (ForwardInstructionIterator instr_it(block_it.Current()); |
2201 !instr_it.Done(); instr_it.Advance()) { | 2131 !instr_it.Done(); instr_it.Advance()) { |
2202 RedefinitionInstr* redefinition = instr_it.Current()->AsRedefinition(); | 2132 RedefinitionInstr* redefinition = instr_it.Current()->AsRedefinition(); |
2203 if (redefinition != NULL) { | 2133 if (redefinition != NULL) { |
2204 Definition* original = redefinition->value()->definition(); | 2134 Definition* original = redefinition->value()->definition(); |
2205 RenameDominatedUses(original, redefinition, redefinition); | 2135 RenameDominatedUses(original, redefinition, redefinition); |
2206 } | 2136 } |
2207 } | 2137 } |
2208 } | 2138 } |
2209 } | 2139 } |
2210 | 2140 |
2211 | |
2212 static bool IsPositiveOrZeroSmiConst(Definition* d) { | 2141 static bool IsPositiveOrZeroSmiConst(Definition* d) { |
2213 ConstantInstr* const_instr = d->AsConstant(); | 2142 ConstantInstr* const_instr = d->AsConstant(); |
2214 if ((const_instr != NULL) && (const_instr->value().IsSmi())) { | 2143 if ((const_instr != NULL) && (const_instr->value().IsSmi())) { |
2215 return Smi::Cast(const_instr->value()).Value() >= 0; | 2144 return Smi::Cast(const_instr->value()).Value() >= 0; |
2216 } | 2145 } |
2217 return false; | 2146 return false; |
2218 } | 2147 } |
2219 | 2148 |
2220 | |
2221 static BinarySmiOpInstr* AsSmiShiftLeftInstruction(Definition* d) { | 2149 static BinarySmiOpInstr* AsSmiShiftLeftInstruction(Definition* d) { |
2222 BinarySmiOpInstr* instr = d->AsBinarySmiOp(); | 2150 BinarySmiOpInstr* instr = d->AsBinarySmiOp(); |
2223 if ((instr != NULL) && (instr->op_kind() == Token::kSHL)) { | 2151 if ((instr != NULL) && (instr->op_kind() == Token::kSHL)) { |
2224 return instr; | 2152 return instr; |
2225 } | 2153 } |
2226 return NULL; | 2154 return NULL; |
2227 } | 2155 } |
2228 | 2156 |
2229 | |
2230 void FlowGraph::OptimizeLeftShiftBitAndSmiOp( | 2157 void FlowGraph::OptimizeLeftShiftBitAndSmiOp( |
2231 ForwardInstructionIterator* current_iterator, | 2158 ForwardInstructionIterator* current_iterator, |
2232 Definition* bit_and_instr, | 2159 Definition* bit_and_instr, |
2233 Definition* left_instr, | 2160 Definition* left_instr, |
2234 Definition* right_instr) { | 2161 Definition* right_instr) { |
2235 ASSERT(bit_and_instr != NULL); | 2162 ASSERT(bit_and_instr != NULL); |
2236 ASSERT((left_instr != NULL) && (right_instr != NULL)); | 2163 ASSERT((left_instr != NULL) && (right_instr != NULL)); |
2237 | 2164 |
2238 // Check for pattern, smi_shift_left must be single-use. | 2165 // Check for pattern, smi_shift_left must be single-use. |
2239 bool is_positive_or_zero = IsPositiveOrZeroSmiConst(left_instr); | 2166 bool is_positive_or_zero = IsPositiveOrZeroSmiConst(left_instr); |
(...skipping 16 matching lines...) Expand all Loading... |
2256 ASSERT(bit_and_instr->IsBinarySmiOp() || bit_and_instr->IsBinaryMintOp()); | 2183 ASSERT(bit_and_instr->IsBinarySmiOp() || bit_and_instr->IsBinaryMintOp()); |
2257 if (bit_and_instr->IsBinaryMintOp()) { | 2184 if (bit_and_instr->IsBinaryMintOp()) { |
2258 // Replace Mint op with Smi op. | 2185 // Replace Mint op with Smi op. |
2259 BinarySmiOpInstr* smi_op = new (Z) BinarySmiOpInstr( | 2186 BinarySmiOpInstr* smi_op = new (Z) BinarySmiOpInstr( |
2260 Token::kBIT_AND, new (Z) Value(left_instr), new (Z) Value(right_instr), | 2187 Token::kBIT_AND, new (Z) Value(left_instr), new (Z) Value(right_instr), |
2261 Thread::kNoDeoptId); // BIT_AND cannot deoptimize. | 2188 Thread::kNoDeoptId); // BIT_AND cannot deoptimize. |
2262 bit_and_instr->ReplaceWith(smi_op, current_iterator); | 2189 bit_and_instr->ReplaceWith(smi_op, current_iterator); |
2263 } | 2190 } |
2264 } | 2191 } |
2265 | 2192 |
2266 | |
2267 // Dart: | 2193 // Dart: |
2268 // var x = d % 10; | 2194 // var x = d % 10; |
2269 // var y = d ~/ 10; | 2195 // var y = d ~/ 10; |
2270 // var z = x + y; | 2196 // var z = x + y; |
2271 // | 2197 // |
2272 // IL: | 2198 // IL: |
2273 // v4 <- %(v2, v3) | 2199 // v4 <- %(v2, v3) |
2274 // v5 <- ~/(v2, v3) | 2200 // v5 <- ~/(v2, v3) |
2275 // v6 <- +(v4, v5) | 2201 // v6 <- +(v4, v5) |
2276 // | 2202 // |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2327 other_binop->RemoveFromGraph(); | 2253 other_binop->RemoveFromGraph(); |
2328 // Only one merge possible. Because canonicalization happens later, | 2254 // Only one merge possible. Because canonicalization happens later, |
2329 // more candidates are possible. | 2255 // more candidates are possible. |
2330 // TODO(srdjan): Allow merging of trunc-div/mod into truncDivMod. | 2256 // TODO(srdjan): Allow merging of trunc-div/mod into truncDivMod. |
2331 break; | 2257 break; |
2332 } | 2258 } |
2333 } | 2259 } |
2334 } | 2260 } |
2335 } | 2261 } |
2336 | 2262 |
2337 | |
2338 void FlowGraph::AppendExtractNthOutputForMerged(Definition* instr, | 2263 void FlowGraph::AppendExtractNthOutputForMerged(Definition* instr, |
2339 intptr_t index, | 2264 intptr_t index, |
2340 Representation rep, | 2265 Representation rep, |
2341 intptr_t cid) { | 2266 intptr_t cid) { |
2342 ExtractNthOutputInstr* extract = | 2267 ExtractNthOutputInstr* extract = |
2343 new (Z) ExtractNthOutputInstr(new (Z) Value(instr), index, rep, cid); | 2268 new (Z) ExtractNthOutputInstr(new (Z) Value(instr), index, rep, cid); |
2344 instr->ReplaceUsesWith(extract); | 2269 instr->ReplaceUsesWith(extract); |
2345 InsertAfter(instr, extract, NULL, FlowGraph::kValue); | 2270 InsertAfter(instr, extract, NULL, FlowGraph::kValue); |
2346 } | 2271 } |
2347 | 2272 |
2348 | |
2349 } // namespace dart | 2273 } // namespace dart |
OLD | NEW |