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_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
6 | 6 |
7 #include "vm/cha.h" | 7 #include "vm/cha.h" |
8 #include "vm/flow_graph_builder.h" | 8 #include "vm/flow_graph_builder.h" |
9 #include "vm/hash_map.h" | 9 #include "vm/hash_map.h" |
10 #include "vm/il_printer.h" | 10 #include "vm/il_printer.h" |
(...skipping 13 matching lines...) Expand all Loading... |
24 void FlowGraphOptimizer::ApplyICData() { | 24 void FlowGraphOptimizer::ApplyICData() { |
25 VisitBlocks(); | 25 VisitBlocks(); |
26 } | 26 } |
27 | 27 |
28 | 28 |
29 void FlowGraphOptimizer::OptimizeComputations() { | 29 void FlowGraphOptimizer::OptimizeComputations() { |
30 for (intptr_t i = 0; i < block_order_.length(); ++i) { | 30 for (intptr_t i = 0; i < block_order_.length(); ++i) { |
31 BlockEntryInstr* entry = block_order_[i]; | 31 BlockEntryInstr* entry = block_order_[i]; |
32 entry->Accept(this); | 32 entry->Accept(this); |
33 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { | 33 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { |
34 Definition* defn = it.Current()->AsDefinition(); | 34 BindInstr* instr = it.Current()->AsBind(); |
35 if (defn != NULL) { | 35 if (instr != NULL) { |
36 Definition* result = defn->Canonicalize(); | 36 Definition* result = instr->computation()->TryReplace(instr); |
37 if (result != defn) { | 37 if (result != instr) { |
38 if (result != NULL) { | 38 if (result != NULL) { |
39 defn->ReplaceUsesWith(result); | 39 instr->ReplaceUsesWith(result); |
40 if (FLAG_trace_optimization) { | 40 if (FLAG_trace_optimization) { |
41 OS::Print("Replacing v%d with v%d\n", | 41 OS::Print("Replacing v%d with v%d\n", |
42 defn->ssa_temp_index(), | 42 instr->ssa_temp_index(), |
43 result->ssa_temp_index()); | 43 result->ssa_temp_index()); |
44 } | 44 } |
45 } else if (FLAG_trace_optimization) { | 45 } else if (FLAG_trace_optimization) { |
46 OS::Print("Removing v%d.\n", defn->ssa_temp_index()); | 46 OS::Print("Removing v%d.\n", instr->ssa_temp_index()); |
47 } | 47 } |
48 it.RemoveCurrentFromGraph(); | 48 it.RemoveCurrentFromGraph(); |
49 } | 49 } |
50 } | 50 } |
51 } | 51 } |
52 } | 52 } |
53 } | 53 } |
54 | 54 |
55 | 55 |
56 static Definition* CreateConversion(Representation from, | 56 static Computation* CreateConversion(Representation from, |
57 Representation to, | 57 Representation to, |
58 Definition* def, | 58 Definition* def, |
59 Instruction* deopt_target) { | 59 Instruction* deopt_target) { |
60 if ((from == kUnboxedDouble) && (to == kTagged)) { | 60 if ((from == kUnboxedDouble) && (to == kTagged)) { |
61 return new BoxDoubleInstr(new Value(def), NULL); | 61 return new BoxDoubleComp(new Value(def), NULL); |
62 } else if ((from == kTagged) && (to == kUnboxedDouble)) { | 62 } else if ((from == kTagged) && (to == kUnboxedDouble)) { |
63 const intptr_t deopt_id = (deopt_target != NULL) ? | 63 const intptr_t deopt_id = (deopt_target != NULL) ? |
64 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; | 64 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; |
65 ASSERT((deopt_target != NULL) || (def->GetPropagatedCid() == kDoubleCid)); | 65 ASSERT((deopt_target != NULL) || (def->GetPropagatedCid() == kDoubleCid)); |
66 return new UnboxDoubleInstr(new Value(def), deopt_id); | 66 return new UnboxDoubleComp(new Value(def), deopt_id); |
67 } else { | 67 } else { |
68 UNREACHABLE(); | 68 UNREACHABLE(); |
69 return NULL; | 69 return NULL; |
70 } | 70 } |
71 } | 71 } |
72 | 72 |
73 | 73 |
74 void FlowGraphOptimizer::InsertConversionsFor(Definition* def) { | 74 void FlowGraphOptimizer::InsertConversionsFor(Definition* def) { |
75 const Representation from_rep = def->representation(); | 75 const Representation from_rep = def->representation(); |
76 | 76 |
(...skipping 12 matching lines...) Expand all Loading... |
89 if (!instr->AsPhi()->is_alive()) continue; | 89 if (!instr->AsPhi()->is_alive()) continue; |
90 | 90 |
91 // For phis conversions have to be inserted in the predecessor. | 91 // For phis conversions have to be inserted in the predecessor. |
92 const BlockEntryInstr* pred = | 92 const BlockEntryInstr* pred = |
93 instr->AsPhi()->block()->PredecessorAt(use->use_index()); | 93 instr->AsPhi()->block()->PredecessorAt(use->use_index()); |
94 instr = pred->last_instruction(); | 94 instr = pred->last_instruction(); |
95 } else { | 95 } else { |
96 deopt_target = instr; | 96 deopt_target = instr; |
97 } | 97 } |
98 | 98 |
99 Definition* converted = | 99 BindInstr* converted = InsertBefore( |
100 CreateConversion(from_rep, to_rep, def, deopt_target); | 100 instr, |
101 InsertBefore(instr, converted, use->instruction()->env(), | 101 CreateConversion(from_rep, to_rep, def, deopt_target), |
102 Definition::kValue); | 102 use->instruction()->env(), |
| 103 Definition::kValue); |
| 104 |
103 use->set_definition(converted); | 105 use->set_definition(converted); |
104 } | 106 } |
105 } | 107 } |
106 | 108 |
107 | |
108 void FlowGraphOptimizer::SelectRepresentations() { | 109 void FlowGraphOptimizer::SelectRepresentations() { |
109 // Convervatively unbox all phis that were proven to be of type Double. | 110 // Convervatively unbox all phis that were proven to be of type Double. |
110 for (intptr_t i = 0; i < block_order_.length(); ++i) { | 111 for (intptr_t i = 0; i < block_order_.length(); ++i) { |
111 JoinEntryInstr* join_entry = block_order_[i]->AsJoinEntry(); | 112 JoinEntryInstr* join_entry = block_order_[i]->AsJoinEntry(); |
112 if (join_entry == NULL) continue; | 113 if (join_entry == NULL) continue; |
113 | 114 |
114 if (join_entry->phis() != NULL) { | 115 if (join_entry->phis() != NULL) { |
115 for (intptr_t i = 0; i < join_entry->phis()->length(); ++i) { | 116 for (intptr_t i = 0; i < join_entry->phis()->length(); ++i) { |
116 PhiInstr* phi = (*join_entry->phis())[i]; | 117 PhiInstr* phi = (*join_entry->phis())[i]; |
117 if ((phi != NULL) && (phi->GetPropagatedCid() == kDoubleCid)) { | 118 if ((phi != NULL) && (phi->GetPropagatedCid() == kDoubleCid)) { |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
256 (class_ids[0] == kDoubleCid) || (class_ids[1] == kDoubleCid); | 257 (class_ids[0] == kDoubleCid) || (class_ids[1] == kDoubleCid); |
257 | 258 |
258 const bool seen_only_smi_or_double = | 259 const bool seen_only_smi_or_double = |
259 ((class_ids[0] == kDoubleCid) || (class_ids[0] == kSmiCid)) && | 260 ((class_ids[0] == kDoubleCid) || (class_ids[0] == kSmiCid)) && |
260 ((class_ids[1] == kDoubleCid) || (class_ids[1] == kSmiCid)); | 261 ((class_ids[1] == kDoubleCid) || (class_ids[1] == kSmiCid)); |
261 | 262 |
262 return seen_double && seen_only_smi_or_double; | 263 return seen_double && seen_only_smi_or_double; |
263 } | 264 } |
264 | 265 |
265 | 266 |
266 static void RemovePushArguments(InstanceCallInstr* call) { | 267 static void RemovePushArguments(InstanceCallComp* comp) { |
267 // Remove original push arguments. | 268 // Remove original push arguments. |
268 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | 269 for (intptr_t i = 0; i < comp->ArgumentCount(); ++i) { |
269 PushArgumentInstr* push = call->ArgumentAt(i); | 270 PushArgumentInstr* push = comp->ArgumentAt(i); |
270 push->ReplaceUsesWith(push->value()->definition()); | 271 push->ReplaceUsesWith(push->value()->definition()); |
271 push->RemoveFromGraph(); | 272 push->RemoveFromGraph(); |
272 } | 273 } |
273 } | 274 } |
274 | 275 |
275 | 276 |
276 // Returns true if all targets are the same. | 277 // Returns true if all targets are the same. |
277 // TODO(srdjan): if targets are native use their C_function to compare. | 278 // TODO(srdjan): if targets are native use their C_function to compare. |
278 static bool HasOneTarget(const ICData& ic_data) { | 279 static bool HasOneTarget(const ICData& ic_data) { |
279 ASSERT(ic_data.NumberOfChecks() > 0); | 280 ASSERT(ic_data.NumberOfChecks() > 0); |
280 const Function& first_target = Function::Handle(ic_data.GetTargetAt(0)); | 281 const Function& first_target = Function::Handle(ic_data.GetTargetAt(0)); |
281 Function& test_target = Function::Handle(); | 282 Function& test_target = Function::Handle(); |
282 for (intptr_t i = 1; i < ic_data.NumberOfChecks(); i++) { | 283 for (intptr_t i = 1; i < ic_data.NumberOfChecks(); i++) { |
283 test_target = ic_data.GetTargetAt(i); | 284 test_target = ic_data.GetTargetAt(i); |
284 if (first_target.raw() != test_target.raw()) { | 285 if (first_target.raw() != test_target.raw()) { |
285 return false; | 286 return false; |
286 } | 287 } |
287 } | 288 } |
288 return true; | 289 return true; |
289 } | 290 } |
290 | 291 |
291 | 292 |
292 static intptr_t ReceiverClassId(InstanceCallInstr* call) { | 293 static intptr_t ReceiverClassId(InstanceCallComp* comp) { |
293 if (!call->HasICData()) return kIllegalCid; | 294 if (!comp->HasICData()) return kIllegalCid; |
294 | 295 |
295 const ICData& ic_data = *call->ic_data(); | 296 const ICData& ic_data = *comp->ic_data(); |
296 | 297 |
297 if (ic_data.NumberOfChecks() == 0) return kIllegalCid; | 298 if (ic_data.NumberOfChecks() == 0) return kIllegalCid; |
298 // TODO(vegorov): Add multiple receiver type support. | 299 // TODO(vegorov): Add multiple receiver type support. |
299 if (ic_data.NumberOfChecks() != 1) return kIllegalCid; | 300 if (ic_data.NumberOfChecks() != 1) return kIllegalCid; |
300 ASSERT(HasOneTarget(ic_data)); | 301 ASSERT(HasOneTarget(ic_data)); |
301 | 302 |
302 Function& target = Function::Handle(); | 303 Function& target = Function::Handle(); |
303 intptr_t class_id; | 304 intptr_t class_id; |
304 ic_data.GetOneClassCheckAt(0, &class_id, &target); | 305 ic_data.GetOneClassCheckAt(0, &class_id, &target); |
305 return class_id; | 306 return class_id; |
306 } | 307 } |
307 | 308 |
308 | 309 |
309 void FlowGraphOptimizer::AddCheckClass(InstanceCallInstr* call, | 310 void FlowGraphOptimizer::AddCheckClass(BindInstr* instr, |
| 311 InstanceCallComp* comp, |
310 Value* value) { | 312 Value* value) { |
311 // Type propagation has not run yet, we cannot eliminate the check. | 313 // Type propagation has not run yet, we cannot eliminate the check. |
312 const ICData& unary_checks = | 314 const ICData& unary_checks = |
313 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); | 315 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); |
314 CheckClassInstr* check = new CheckClassInstr(value, call, unary_checks); | 316 CheckClassComp* check = new CheckClassComp(value, comp, unary_checks); |
315 InsertBefore(call, check, call->env(), Definition::kEffect); | 317 InsertBefore(instr, check, instr->env(), Definition::kEffect); |
316 } | 318 } |
317 | 319 |
318 | 320 |
319 bool FlowGraphOptimizer::TryReplaceWithArrayOp(InstanceCallInstr* call, | 321 bool FlowGraphOptimizer::TryReplaceWithArrayOp(BindInstr* instr, |
| 322 InstanceCallComp* comp, |
320 Token::Kind op_kind) { | 323 Token::Kind op_kind) { |
321 // TODO(fschneider): Optimize []= operator in checked mode as well. | 324 // TODO(fschneider): Optimize []= operator in checked mode as well. |
322 if (op_kind == Token::kASSIGN_INDEX && FLAG_enable_type_checks) return false; | 325 if (op_kind == Token::kASSIGN_INDEX && FLAG_enable_type_checks) return false; |
323 | 326 |
324 const intptr_t class_id = ReceiverClassId(call); | 327 const intptr_t class_id = ReceiverClassId(comp); |
325 switch (class_id) { | 328 switch (class_id) { |
326 case kImmutableArrayCid: | 329 case kImmutableArrayCid: |
327 // Stores are only specialized for Array and GrowableObjectArray, | 330 // Stores are only specialized for Array and GrowableObjectArray, |
328 // not for ImmutableArray. | 331 // not for ImmutableArray. |
329 if (op_kind == Token::kASSIGN_INDEX) return false; | 332 if (op_kind == Token::kASSIGN_INDEX) return false; |
330 // Fall through. | 333 // Fall through. |
331 case kArrayCid: | 334 case kArrayCid: |
332 case kGrowableObjectArrayCid: { | 335 case kGrowableObjectArrayCid: { |
333 Value* array = call->ArgumentAt(0)->value(); | 336 Value* array = comp->ArgumentAt(0)->value(); |
334 Value* index = call->ArgumentAt(1)->value(); | 337 Value* index = comp->ArgumentAt(1)->value(); |
335 // Insert class check and index smi checks and attach a copy of the | 338 // Insert class check and index smi checks and attach a copy of the |
336 // original environment because the operation can still deoptimize. | 339 // original environment because the operation can still deoptimize. |
337 AddCheckClass(call, array->Copy()); | 340 AddCheckClass(instr, comp, array->Copy()); |
338 InsertBefore(call, | 341 InsertBefore(instr, |
339 new CheckSmiInstr(index->Copy(), call->deopt_id()), | 342 new CheckSmiComp(index->Copy(), comp->deopt_id()), |
340 call->env(), | 343 instr->env(), |
341 Definition::kEffect); | 344 Definition::kEffect); |
342 // Insert array bounds check. | 345 // Insert array bounds check. |
343 InsertBefore(call, | 346 InsertBefore(instr, |
344 new CheckArrayBoundInstr(array->Copy(), | 347 new CheckArrayBoundComp(array->Copy(), |
345 index->Copy(), | 348 index->Copy(), |
346 class_id, | 349 class_id, |
347 call), | 350 comp), |
348 call->env(), | 351 instr->env(), |
349 Definition::kEffect); | 352 Definition::kEffect); |
350 Definition* array_op = NULL; | 353 Computation* array_op = NULL; |
351 if (op_kind == Token::kINDEX) { | 354 if (op_kind == Token::kINDEX) { |
352 array_op = new LoadIndexedInstr(array, index, class_id); | 355 array_op = new LoadIndexedComp(array, index, class_id); |
353 } else { | 356 } else { |
354 Value* value = call->ArgumentAt(2)->value(); | 357 Value* value = comp->ArgumentAt(2)->value(); |
355 array_op = new StoreIndexedInstr(array, index, value, class_id); | 358 array_op = new StoreIndexedComp(array, index, value, class_id); |
356 } | 359 } |
357 call->ReplaceWith(array_op, current_iterator()); | 360 instr->set_computation(array_op); |
358 RemovePushArguments(call); | 361 RemovePushArguments(comp); |
359 return true; | 362 return true; |
360 } | 363 } |
361 default: | 364 default: |
362 return false; | 365 return false; |
363 } | 366 } |
364 } | 367 } |
365 | 368 |
366 | 369 |
367 void FlowGraphOptimizer::InsertBefore(Instruction* instr, | 370 BindInstr* FlowGraphOptimizer::InsertBefore(Instruction* instr, |
368 Definition* defn, | 371 Computation* comp, |
369 Environment* env, | 372 Environment* env, |
370 Definition::UseKind use_kind) { | 373 BindInstr::UseKind use_kind) { |
371 if (env != NULL) env->CopyTo(defn); | 374 BindInstr* bind = new BindInstr(use_kind, comp); |
| 375 if (env != NULL) env->CopyTo(bind); |
372 if (use_kind == Definition::kValue) { | 376 if (use_kind == Definition::kValue) { |
373 defn->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); | 377 bind->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); |
374 } | 378 } |
375 defn->InsertBefore(instr); | 379 bind->InsertBefore(instr); |
| 380 return bind; |
376 } | 381 } |
377 | 382 |
378 | 383 |
379 void FlowGraphOptimizer::InsertAfter(Instruction* instr, | 384 BindInstr* FlowGraphOptimizer::InsertAfter(Instruction* instr, |
380 Definition* defn, | 385 Computation* comp, |
381 Environment* env, | 386 Environment* env, |
382 Definition::UseKind use_kind) { | 387 BindInstr::UseKind use_kind) { |
383 if (env != NULL) env->CopyTo(defn); | 388 BindInstr* bind = new BindInstr(use_kind, comp); |
| 389 if (env != NULL) env->CopyTo(bind); |
384 if (use_kind == Definition::kValue) { | 390 if (use_kind == Definition::kValue) { |
385 defn->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); | 391 bind->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); |
386 } | 392 } |
387 defn->InsertAfter(instr); | 393 bind->InsertAfter(instr); |
| 394 return bind; |
388 } | 395 } |
389 | 396 |
390 | 397 |
391 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, | 398 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(BindInstr* instr, |
| 399 InstanceCallComp* comp, |
392 Token::Kind op_kind) { | 400 Token::Kind op_kind) { |
393 intptr_t operands_type = kIllegalCid; | 401 intptr_t operands_type = kIllegalCid; |
394 ASSERT(call->HasICData()); | 402 ASSERT(comp->HasICData()); |
395 const ICData& ic_data = *call->ic_data(); | 403 const ICData& ic_data = *comp->ic_data(); |
396 switch (op_kind) { | 404 switch (op_kind) { |
397 case Token::kADD: | 405 case Token::kADD: |
398 case Token::kSUB: | 406 case Token::kSUB: |
399 case Token::kMUL: | 407 case Token::kMUL: |
400 if (HasOnlyTwoSmi(ic_data)) { | 408 if (HasOnlyTwoSmi(ic_data)) { |
401 operands_type = kSmiCid; | 409 operands_type = kSmiCid; |
402 } else if (ShouldSpecializeForDouble(ic_data)) { | 410 } else if (ShouldSpecializeForDouble(ic_data)) { |
403 operands_type = kDoubleCid; | 411 operands_type = kDoubleCid; |
404 } else { | 412 } else { |
405 return false; | 413 return false; |
(...skipping 26 matching lines...) Expand all Loading... |
432 if (HasOnlyTwoSmi(ic_data)) { | 440 if (HasOnlyTwoSmi(ic_data)) { |
433 operands_type = kSmiCid; | 441 operands_type = kSmiCid; |
434 } else { | 442 } else { |
435 return false; | 443 return false; |
436 } | 444 } |
437 break; | 445 break; |
438 default: | 446 default: |
439 UNREACHABLE(); | 447 UNREACHABLE(); |
440 }; | 448 }; |
441 | 449 |
442 ASSERT(call->ArgumentCount() == 2); | 450 ASSERT(comp->ArgumentCount() == 2); |
443 if (operands_type == kDoubleCid) { | 451 if (operands_type == kDoubleCid) { |
444 Value* left = call->ArgumentAt(0)->value(); | 452 Value* left = comp->ArgumentAt(0)->value(); |
445 Value* right = call->ArgumentAt(1)->value(); | 453 Value* right = comp->ArgumentAt(1)->value(); |
446 | 454 |
447 // Check that either left or right are not a smi. Result or a | 455 // Check that either left or right are not a smi. Result or a |
448 // binary operation with two smis is a smi not a double. | 456 // binary operation with two smis is a smi not a double. |
449 InsertBefore(call, | 457 InsertBefore(instr, |
450 new CheckEitherNonSmiInstr(left->Copy(), | 458 new CheckEitherNonSmiComp(left->Copy(), |
451 right->Copy(), | 459 right->Copy(), |
452 call), | 460 comp), |
453 call->env(), | 461 instr->env(), |
454 Definition::kEffect); | 462 Definition::kEffect); |
455 | 463 |
456 UnboxedDoubleBinaryOpInstr* double_bin_op = | 464 UnboxedDoubleBinaryOpComp* double_bin_op = |
457 new UnboxedDoubleBinaryOpInstr(op_kind, | 465 new UnboxedDoubleBinaryOpComp(op_kind, |
458 left->Copy(), | 466 left->Copy(), |
459 right->Copy(), | 467 right->Copy(), |
460 call); | 468 comp); |
461 call->ReplaceWith(double_bin_op, current_iterator()); | 469 instr->set_computation(double_bin_op); |
462 RemovePushArguments(call); | 470 |
| 471 RemovePushArguments(comp); |
463 } else if (operands_type == kMintCid) { | 472 } else if (operands_type == kMintCid) { |
464 Value* left = call->ArgumentAt(0)->value(); | 473 Value* left = comp->ArgumentAt(0)->value(); |
465 Value* right = call->ArgumentAt(1)->value(); | 474 Value* right = comp->ArgumentAt(1)->value(); |
466 BinaryMintOpInstr* bin_op = new BinaryMintOpInstr(op_kind, | 475 BinaryMintOpComp* bin_op = new BinaryMintOpComp(op_kind, |
467 call, | 476 comp, |
468 left, | 477 left, |
469 right); | 478 right); |
470 call->ReplaceWith(bin_op, current_iterator()); | 479 instr->set_computation(bin_op); |
471 RemovePushArguments(call); | 480 RemovePushArguments(comp); |
472 } else { | 481 } else { |
473 ASSERT(operands_type == kSmiCid); | 482 ASSERT(operands_type == kSmiCid); |
474 Value* left = call->ArgumentAt(0)->value(); | 483 Value* left = comp->ArgumentAt(0)->value(); |
475 Value* right = call->ArgumentAt(1)->value(); | 484 Value* right = comp->ArgumentAt(1)->value(); |
476 // Insert two smi checks and attach a copy of the original | 485 // Insert two smi checks and attach a copy of the original |
477 // environment because the smi operation can still deoptimize. | 486 // environment because the smi operation can still deoptimize. |
478 InsertBefore(call, | 487 InsertBefore(instr, |
479 new CheckSmiInstr(left->Copy(), call->deopt_id()), | 488 new CheckSmiComp(left->Copy(), comp->deopt_id()), |
480 call->env(), | 489 instr->env(), |
481 Definition::kEffect); | 490 Definition::kEffect); |
482 InsertBefore(call, | 491 InsertBefore(instr, |
483 new CheckSmiInstr(right->Copy(), call->deopt_id()), | 492 new CheckSmiComp(right->Copy(), comp->deopt_id()), |
484 call->env(), | 493 instr->env(), |
485 Definition::kEffect); | 494 Definition::kEffect); |
486 BinarySmiOpInstr* bin_op = new BinarySmiOpInstr(op_kind, call, left, right); | 495 BinarySmiOpComp* bin_op = new BinarySmiOpComp(op_kind, |
487 call->ReplaceWith(bin_op, current_iterator()); | 496 comp, |
488 RemovePushArguments(call); | 497 left, |
| 498 right); |
| 499 instr->set_computation(bin_op); |
| 500 RemovePushArguments(comp); |
489 } | 501 } |
490 return true; | 502 return true; |
491 } | 503 } |
492 | 504 |
493 | 505 |
494 bool FlowGraphOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call, | 506 bool FlowGraphOptimizer::TryReplaceWithUnaryOp(BindInstr* instr, |
| 507 InstanceCallComp* comp, |
495 Token::Kind op_kind) { | 508 Token::Kind op_kind) { |
496 if (call->ic_data()->NumberOfChecks() != 1) { | 509 if (comp->ic_data()->NumberOfChecks() != 1) { |
497 // TODO(srdjan): Not yet supported. | 510 // TODO(srdjan): Not yet supported. |
498 return false; | 511 return false; |
499 } | 512 } |
500 ASSERT(call->ArgumentCount() == 1); | 513 ASSERT(comp->ArgumentCount() == 1); |
501 Definition* unary_op = NULL; | 514 Computation* unary_op = NULL; |
502 if (HasOneSmi(*call->ic_data())) { | 515 if (HasOneSmi(*comp->ic_data())) { |
503 Value* value = call->ArgumentAt(0)->value(); | 516 Value* value = comp->ArgumentAt(0)->value(); |
504 InsertBefore(call, | 517 InsertBefore(instr, |
505 new CheckSmiInstr(value->Copy(), call->deopt_id()), | 518 new CheckSmiComp(value->Copy(), comp->deopt_id()), |
506 call->env(), | 519 instr->env(), |
507 Definition::kEffect); | 520 Definition::kEffect); |
508 unary_op = new UnarySmiOpInstr(op_kind, | 521 unary_op = new UnarySmiOpComp(op_kind, |
509 (op_kind == Token::kNEGATE) ? call : NULL, | 522 (op_kind == Token::kNEGATE) ? comp : NULL, |
510 value); | 523 value); |
511 } else if (HasOneDouble(*call->ic_data()) && (op_kind == Token::kNEGATE)) { | 524 } else if (HasOneDouble(*comp->ic_data()) && (op_kind == Token::kNEGATE)) { |
512 unary_op = new NumberNegateInstr(call, call->ArgumentAt(0)->value()); | 525 unary_op = new NumberNegateComp(comp, comp->ArgumentAt(0)->value()); |
513 } | 526 } |
514 if (unary_op == NULL) return false; | 527 if (unary_op == NULL) return false; |
515 | 528 |
516 call->ReplaceWith(unary_op, current_iterator()); | 529 instr->set_computation(unary_op); |
517 RemovePushArguments(call); | 530 RemovePushArguments(comp); |
518 return true; | 531 return true; |
519 } | 532 } |
520 | 533 |
521 | 534 |
522 // Using field class | 535 // Using field class |
523 static RawField* GetField(intptr_t class_id, const String& field_name) { | 536 static RawField* GetField(intptr_t class_id, const String& field_name) { |
524 Class& cls = Class::Handle(Isolate::Current()->class_table()->At(class_id)); | 537 Class& cls = Class::Handle(Isolate::Current()->class_table()->At(class_id)); |
525 Field& field = Field::Handle(); | 538 Field& field = Field::Handle(); |
526 while (!cls.IsNull()) { | 539 while (!cls.IsNull()) { |
527 field = cls.LookupInstanceField(field_name); | 540 field = cls.LookupInstanceField(field_name); |
528 if (!field.IsNull()) { | 541 if (!field.IsNull()) { |
529 return field.raw(); | 542 return field.raw(); |
530 } | 543 } |
531 cls = cls.SuperClass(); | 544 cls = cls.SuperClass(); |
532 } | 545 } |
533 return Field::null(); | 546 return Field::null(); |
534 } | 547 } |
535 | 548 |
536 | 549 |
537 // Only unique implicit instance getters can be currently handled. | 550 // Only unique implicit instance getters can be currently handled. |
538 bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) { | 551 bool FlowGraphOptimizer::TryInlineInstanceGetter(BindInstr* instr, |
539 ASSERT(call->HasICData()); | 552 InstanceCallComp* comp) { |
540 const ICData& ic_data = *call->ic_data(); | 553 ASSERT(comp->HasICData()); |
| 554 const ICData& ic_data = *comp->ic_data(); |
541 if (ic_data.NumberOfChecks() == 0) { | 555 if (ic_data.NumberOfChecks() == 0) { |
542 // No type feedback collected. | 556 // No type feedback collected. |
543 return false; | 557 return false; |
544 } | 558 } |
545 Function& target = Function::Handle(); | 559 Function& target = Function::Handle(); |
546 GrowableArray<intptr_t> class_ids; | 560 GrowableArray<intptr_t> class_ids; |
547 ic_data.GetCheckAt(0, &class_ids, &target); | 561 ic_data.GetCheckAt(0, &class_ids, &target); |
548 ASSERT(class_ids.length() == 1); | 562 ASSERT(class_ids.length() == 1); |
549 | 563 |
550 if (target.kind() == RawFunction::kImplicitGetter) { | 564 if (target.kind() == RawFunction::kImplicitGetter) { |
551 if (!HasOneTarget(ic_data)) { | 565 if (!HasOneTarget(ic_data)) { |
552 // TODO(srdjan): Implement for mutiple targets. | 566 // TODO(srdjan): Implement for mutiple targets. |
553 return false; | 567 return false; |
554 } | 568 } |
555 // Inline implicit instance getter. | 569 // Inline implicit instance getter. |
556 const String& field_name = | 570 const String& field_name = |
557 String::Handle(Field::NameFromGetter(call->function_name())); | 571 String::Handle(Field::NameFromGetter(comp->function_name())); |
558 const Field& field = Field::Handle(GetField(class_ids[0], field_name)); | 572 const Field& field = Field::Handle(GetField(class_ids[0], field_name)); |
559 ASSERT(!field.IsNull()); | 573 ASSERT(!field.IsNull()); |
560 | 574 |
561 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy()); | 575 AddCheckClass(instr, comp, comp->ArgumentAt(0)->value()->Copy()); |
562 // Detach environment from the original instruction because it can't | 576 // Detach environment from the original instruction because it can't |
563 // deoptimize. | 577 // deoptimize. |
564 call->set_env(NULL); | 578 instr->set_env(NULL); |
565 LoadInstanceFieldInstr* load = | 579 LoadInstanceFieldComp* load = |
566 new LoadInstanceFieldInstr(field, call->ArgumentAt(0)->value()); | 580 new LoadInstanceFieldComp(field, comp->ArgumentAt(0)->value()); |
567 call->ReplaceWith(load, current_iterator()); | 581 instr->set_computation(load); |
568 RemovePushArguments(call); | 582 RemovePushArguments(comp); |
569 return true; | 583 return true; |
570 } | 584 } |
571 | 585 |
572 // Not an implicit getter. | 586 // Not an implicit getter. |
573 MethodRecognizer::Kind recognized_kind = | 587 MethodRecognizer::Kind recognized_kind = |
574 MethodRecognizer::RecognizeKind(target); | 588 MethodRecognizer::RecognizeKind(target); |
575 | 589 |
576 // VM objects length getter. | 590 // VM objects length getter. |
577 if ((recognized_kind == MethodRecognizer::kObjectArrayLength) || | 591 if ((recognized_kind == MethodRecognizer::kObjectArrayLength) || |
578 (recognized_kind == MethodRecognizer::kImmutableArrayLength) || | 592 (recognized_kind == MethodRecognizer::kImmutableArrayLength) || |
579 (recognized_kind == MethodRecognizer::kGrowableArrayLength)) { | 593 (recognized_kind == MethodRecognizer::kGrowableArrayLength)) { |
580 if (!HasOneTarget(ic_data)) { | 594 if (!HasOneTarget(ic_data)) { |
581 // TODO(srdjan): Implement for mutiple targets. | 595 // TODO(srdjan): Implement for mutiple targets. |
582 return false; | 596 return false; |
583 } | 597 } |
584 intptr_t length_offset = -1; | 598 intptr_t length_offset = -1; |
585 switch (recognized_kind) { | 599 switch (recognized_kind) { |
586 case MethodRecognizer::kObjectArrayLength: | 600 case MethodRecognizer::kObjectArrayLength: |
587 case MethodRecognizer::kImmutableArrayLength: | 601 case MethodRecognizer::kImmutableArrayLength: |
588 length_offset = Array::length_offset(); | 602 length_offset = Array::length_offset(); |
589 break; | 603 break; |
590 case MethodRecognizer::kGrowableArrayLength: | 604 case MethodRecognizer::kGrowableArrayLength: |
591 length_offset = GrowableObjectArray::length_offset(); | 605 length_offset = GrowableObjectArray::length_offset(); |
592 break; | 606 break; |
593 default: | 607 default: |
594 UNREACHABLE(); | 608 UNREACHABLE(); |
595 } | 609 } |
596 // Check receiver class. | 610 // Check receiver class. |
597 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy()); | 611 AddCheckClass(instr, comp, comp->ArgumentAt(0)->value()->Copy()); |
598 | 612 |
599 LoadVMFieldInstr* load = new LoadVMFieldInstr( | 613 LoadVMFieldComp* load = new LoadVMFieldComp( |
600 call->ArgumentAt(0)->value(), | 614 comp->ArgumentAt(0)->value(), |
601 length_offset, | 615 length_offset, |
602 Type::ZoneHandle(Type::SmiType())); | 616 Type::ZoneHandle(Type::SmiType())); |
603 load->set_result_cid(kSmiCid); | 617 load->set_result_cid(kSmiCid); |
604 call->ReplaceWith(load, current_iterator()); | 618 instr->set_computation(load); |
605 RemovePushArguments(call); | 619 RemovePushArguments(comp); |
606 return true; | 620 return true; |
607 } | 621 } |
608 | 622 |
609 if (recognized_kind == MethodRecognizer::kStringBaseLength) { | 623 if (recognized_kind == MethodRecognizer::kStringBaseLength) { |
610 if (!HasOneTarget(ic_data)) { | 624 if (!HasOneTarget(ic_data)) { |
611 // Target is not only StringBase_get_length. | 625 // Target is not only StringBase_get_length. |
612 return false; | 626 return false; |
613 } | 627 } |
614 // Check receiver class. | 628 // Check receiver class. |
615 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy()); | 629 AddCheckClass(instr, comp, comp->ArgumentAt(0)->value()->Copy()); |
616 | 630 |
617 LoadVMFieldInstr* load = new LoadVMFieldInstr( | 631 LoadVMFieldComp* load = new LoadVMFieldComp( |
618 call->ArgumentAt(0)->value(), | 632 comp->ArgumentAt(0)->value(), |
619 String::length_offset(), | 633 String::length_offset(), |
620 Type::ZoneHandle(Type::SmiType())); | 634 Type::ZoneHandle(Type::SmiType())); |
621 load->set_result_cid(kSmiCid); | 635 load->set_result_cid(kSmiCid); |
622 call->ReplaceWith(load, current_iterator()); | 636 instr->set_computation(load); |
623 RemovePushArguments(call); | 637 RemovePushArguments(comp); |
624 return true; | 638 return true; |
625 } | 639 } |
626 return false; | 640 return false; |
627 } | 641 } |
628 | 642 |
629 | 643 |
630 // Inline only simple, frequently called core library methods. | 644 // Inline only simple, frequently called core library methods. |
631 bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { | 645 bool FlowGraphOptimizer::TryInlineInstanceMethod(BindInstr* instr, |
632 ASSERT(call->HasICData()); | 646 InstanceCallComp* comp) { |
633 const ICData& ic_data = *call->ic_data(); | 647 ASSERT(comp->HasICData()); |
| 648 const ICData& ic_data = *comp->ic_data(); |
634 if ((ic_data.NumberOfChecks() == 0) || !HasOneTarget(ic_data)) { | 649 if ((ic_data.NumberOfChecks() == 0) || !HasOneTarget(ic_data)) { |
635 // No type feedback collected. | 650 // No type feedback collected. |
636 return false; | 651 return false; |
637 } | 652 } |
638 Function& target = Function::Handle(); | 653 Function& target = Function::Handle(); |
639 GrowableArray<intptr_t> class_ids; | 654 GrowableArray<intptr_t> class_ids; |
640 ic_data.GetCheckAt(0, &class_ids, &target); | 655 ic_data.GetCheckAt(0, &class_ids, &target); |
641 MethodRecognizer::Kind recognized_kind = | 656 MethodRecognizer::Kind recognized_kind = |
642 MethodRecognizer::RecognizeKind(target); | 657 MethodRecognizer::RecognizeKind(target); |
643 | 658 |
644 if ((recognized_kind == MethodRecognizer::kDoubleToDouble) && | 659 if ((recognized_kind == MethodRecognizer::kDoubleToDouble) && |
645 (class_ids[0] == kDoubleCid)) { | 660 (class_ids[0] == kDoubleCid)) { |
646 DoubleToDoubleInstr* d2d_instr = | 661 DoubleToDoubleComp* d2d_comp = |
647 new DoubleToDoubleInstr(call->ArgumentAt(0)->value(), call); | 662 new DoubleToDoubleComp(comp->ArgumentAt(0)->value(), comp); |
648 call->ReplaceWith(d2d_instr, current_iterator()); | 663 instr->set_computation(d2d_comp); |
649 RemovePushArguments(call); | 664 RemovePushArguments(comp); |
650 return true; | 665 return true; |
651 } | 666 } |
652 if ((recognized_kind == MethodRecognizer::kIntegerToDouble) && | 667 if ((recognized_kind == MethodRecognizer::kIntegerToDouble) && |
653 (class_ids[0] == kSmiCid)) { | 668 (class_ids[0] == kSmiCid)) { |
654 SmiToDoubleInstr* s2d_instr = new SmiToDoubleInstr(call); | 669 SmiToDoubleComp* s2d_comp = new SmiToDoubleComp(comp); |
655 call->ReplaceWith(s2d_instr, current_iterator()); | 670 instr->set_computation(s2d_comp); |
656 // Pushed arguments are not removed because SmiToDouble is implemented | 671 // Pushed arguments are not removed because SmiToDouble is implemented |
657 // as a call. | 672 // as a call. |
658 return true; | 673 return true; |
659 } | 674 } |
660 return false; | 675 return false; |
661 } | 676 } |
662 | 677 |
663 | 678 |
664 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { | 679 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallComp* comp, |
665 if (instr->HasICData() && (instr->ic_data()->NumberOfChecks() > 0)) { | 680 BindInstr* instr) { |
666 const Token::Kind op_kind = instr->token_kind(); | 681 if (comp->HasICData() && (comp->ic_data()->NumberOfChecks() > 0)) { |
| 682 const Token::Kind op_kind = comp->token_kind(); |
667 if (Token::IsIndexOperator(op_kind) && | 683 if (Token::IsIndexOperator(op_kind) && |
668 TryReplaceWithArrayOp(instr, op_kind)) { | 684 TryReplaceWithArrayOp(instr, comp, op_kind)) { |
669 return; | 685 return; |
670 } | 686 } |
671 if (Token::IsBinaryToken(op_kind) && | 687 if (Token::IsBinaryToken(op_kind) && |
672 TryReplaceWithBinaryOp(instr, op_kind)) { | 688 TryReplaceWithBinaryOp(instr, comp, op_kind)) { |
673 return; | 689 return; |
674 } | 690 } |
675 if (Token::IsUnaryToken(op_kind) && | 691 if (Token::IsUnaryToken(op_kind) && |
676 TryReplaceWithUnaryOp(instr, op_kind)) { | 692 TryReplaceWithUnaryOp(instr, comp, op_kind)) { |
677 return; | 693 return; |
678 } | 694 } |
679 if ((op_kind == Token::kGET) && TryInlineInstanceGetter(instr)) { | 695 if ((op_kind == Token::kGET) && TryInlineInstanceGetter(instr, comp)) { |
680 return; | 696 return; |
681 } | 697 } |
682 if ((op_kind == Token::kSET) && TryInlineInstanceSetter(instr)) { | 698 if ((op_kind == Token::kSET) && TryInlineInstanceSetter(instr, comp)) { |
683 return; | 699 return; |
684 } | 700 } |
685 if (TryInlineInstanceMethod(instr)) { | 701 if (TryInlineInstanceMethod(instr, comp)) { |
686 return; | 702 return; |
687 } | 703 } |
688 const intptr_t kMaxChecks = 4; | 704 const intptr_t kMaxChecks = 4; |
689 if (instr->ic_data()->NumberOfChecks() <= kMaxChecks) { | 705 if (comp->ic_data()->NumberOfChecks() <= kMaxChecks) { |
690 const ICData& unary_checks = | 706 const ICData& unary_checks = |
691 ICData::ZoneHandle(instr->ic_data()->AsUnaryClassChecks()); | 707 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); |
692 bool call_with_checks; | 708 bool call_with_checks; |
693 // TODO(srdjan): Add check class instr for mixed smi/non-smi. | 709 // TODO(srdjan): Add check class comp for mixed smi/non-smi. |
694 if (HasOneTarget(unary_checks) && | 710 if (HasOneTarget(unary_checks) && |
695 (unary_checks.GetReceiverClassIdAt(0) != kSmiCid)) { | 711 (unary_checks.GetReceiverClassIdAt(0) != kSmiCid)) { |
696 // Type propagation has not run yet, we cannot eliminate the check. | 712 // Type propagation has not run yet, we cannot eliminate the check. |
697 AddCheckClass(instr, instr->ArgumentAt(0)->value()->Copy()); | 713 AddCheckClass(instr, comp, comp->ArgumentAt(0)->value()->Copy()); |
698 // Call can still deoptimize, do not detach environment from instr. | 714 // Call can still deoptimize, do not detach environment from instr. |
699 call_with_checks = false; | 715 call_with_checks = false; |
700 } else { | 716 } else { |
701 call_with_checks = true; | 717 call_with_checks = true; |
702 } | 718 } |
703 PolymorphicInstanceCallInstr* call = | 719 PolymorphicInstanceCallComp* call = |
704 new PolymorphicInstanceCallInstr(instr, unary_checks, | 720 new PolymorphicInstanceCallComp(comp, |
705 call_with_checks); | 721 unary_checks, |
706 instr->ReplaceWith(call, current_iterator()); | 722 call_with_checks); |
| 723 instr->set_computation(call); |
707 } | 724 } |
708 } | 725 } |
709 // An instance call without ICData should continue calling via IC calls | 726 // An instance call without ICData should continue calling via IC calls |
710 // which should trigger reoptimization of optimized code. | 727 // which should trigger reoptimization of optimized code. |
711 } | 728 } |
712 | 729 |
713 | 730 |
714 void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* instr) { | 731 void FlowGraphOptimizer::VisitStaticCall(StaticCallComp* comp, |
| 732 BindInstr* instr) { |
715 MethodRecognizer::Kind recognized_kind = | 733 MethodRecognizer::Kind recognized_kind = |
716 MethodRecognizer::RecognizeKind(instr->function()); | 734 MethodRecognizer::RecognizeKind(comp->function()); |
717 if (recognized_kind == MethodRecognizer::kMathSqrt) { | 735 if (recognized_kind == MethodRecognizer::kMathSqrt) { |
718 instr->set_recognized(MethodRecognizer::kMathSqrt); | 736 comp->set_recognized(MethodRecognizer::kMathSqrt); |
719 } | 737 } |
720 } | 738 } |
721 | 739 |
722 | 740 |
723 bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr) { | 741 bool FlowGraphOptimizer::TryInlineInstanceSetter(BindInstr* instr, |
| 742 InstanceCallComp* comp) { |
724 if (FLAG_enable_type_checks) { | 743 if (FLAG_enable_type_checks) { |
725 // TODO(srdjan): Add assignable check node if --enable_type_checks. | 744 // TODO(srdjan): Add assignable check node if --enable_type_checks. |
726 return false; | 745 return false; |
727 } | 746 } |
728 | 747 |
729 ASSERT(instr->HasICData()); | 748 ASSERT(comp->HasICData()); |
730 const ICData& ic_data = *instr->ic_data(); | 749 const ICData& ic_data = *comp->ic_data(); |
731 if (ic_data.NumberOfChecks() == 0) { | 750 if (ic_data.NumberOfChecks() == 0) { |
732 // No type feedback collected. | 751 // No type feedback collected. |
733 return false; | 752 return false; |
734 } | 753 } |
735 if (!HasOneTarget(ic_data)) { | 754 if (!HasOneTarget(ic_data)) { |
736 // TODO(srdjan): Implement when not all targets are the same. | 755 // TODO(srdjan): Implement when not all targets are the same. |
737 return false; | 756 return false; |
738 } | 757 } |
739 Function& target = Function::Handle(); | 758 Function& target = Function::Handle(); |
740 intptr_t class_id; | 759 intptr_t class_id; |
741 ic_data.GetOneClassCheckAt(0, &class_id, &target); | 760 ic_data.GetOneClassCheckAt(0, &class_id, &target); |
742 if (target.kind() != RawFunction::kImplicitSetter) { | 761 if (target.kind() != RawFunction::kImplicitSetter) { |
743 // Not an implicit setter. | 762 // Not an implicit setter. |
744 // TODO(srdjan): Inline special setters. | 763 // TODO(srdjan): Inline special setters. |
745 return false; | 764 return false; |
746 } | 765 } |
747 // Inline implicit instance setter. | 766 // Inline implicit instance setter. |
748 const String& field_name = | 767 const String& field_name = |
749 String::Handle(Field::NameFromSetter(instr->function_name())); | 768 String::Handle(Field::NameFromSetter(comp->function_name())); |
750 const Field& field = Field::Handle(GetField(class_id, field_name)); | 769 const Field& field = Field::Handle(GetField(class_id, field_name)); |
751 ASSERT(!field.IsNull()); | 770 ASSERT(!field.IsNull()); |
752 | 771 |
753 AddCheckClass(instr, instr->ArgumentAt(0)->value()->Copy()); | 772 AddCheckClass(instr, comp, comp->ArgumentAt(0)->value()->Copy()); |
754 // Detach environment from the original instruction because it can't | 773 // Detach environment from the original instruction because it can't |
755 // deoptimize. | 774 // deoptimize. |
756 instr->set_env(NULL); | 775 instr->set_env(NULL); |
757 StoreInstanceFieldInstr* store = new StoreInstanceFieldInstr( | 776 StoreInstanceFieldComp* store = new StoreInstanceFieldComp( |
758 field, | 777 field, |
759 instr->ArgumentAt(0)->value(), | 778 comp->ArgumentAt(0)->value(), |
760 instr->ArgumentAt(1)->value()); | 779 comp->ArgumentAt(1)->value()); |
761 instr->ReplaceWith(store, current_iterator()); | 780 instr->set_computation(store); |
762 RemovePushArguments(instr); | 781 RemovePushArguments(comp); |
763 return true; | 782 return true; |
764 } | 783 } |
765 | 784 |
766 | 785 |
767 // TODO(fschneider): Once we get rid of the distinction between Instruction | 786 // TODO(fschneider): Once we get rid of the distinction between Instruction |
768 // and computation, this helper can go away. | 787 // and computation, this helper can go away. |
769 static void HandleRelationalOp(FlowGraphOptimizer* optimizer, | 788 static void HandleRelationalOp(FlowGraphOptimizer* optimizer, |
770 RelationalOpInstr* comp, | 789 RelationalOpComp* comp, |
771 Instruction* instr) { | 790 Instruction* instr) { |
772 if (!comp->HasICData()) return; | 791 if (!comp->HasICData()) return; |
773 | 792 |
774 const ICData& ic_data = *comp->ic_data(); | 793 const ICData& ic_data = *comp->ic_data(); |
775 if (ic_data.NumberOfChecks() == 0) return; | 794 if (ic_data.NumberOfChecks() == 0) return; |
776 // TODO(srdjan): Add multiple receiver type support. | 795 // TODO(srdjan): Add multiple receiver type support. |
777 if (ic_data.NumberOfChecks() != 1) return; | 796 if (ic_data.NumberOfChecks() != 1) return; |
778 ASSERT(HasOneTarget(ic_data)); | 797 ASSERT(HasOneTarget(ic_data)); |
779 | 798 |
780 if (HasOnlyTwoSmi(ic_data)) { | 799 if (HasOnlyTwoSmi(ic_data)) { |
781 optimizer->InsertBefore( | 800 optimizer->InsertBefore( |
782 instr, | 801 instr, |
783 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()), | 802 new CheckSmiComp(comp->left()->Copy(), comp->deopt_id()), |
784 instr->env(), | 803 instr->env(), |
785 Definition::kEffect); | 804 Definition::kEffect); |
786 optimizer->InsertBefore( | 805 optimizer->InsertBefore( |
787 instr, | 806 instr, |
788 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()), | 807 new CheckSmiComp(comp->right()->Copy(), comp->deopt_id()), |
789 instr->env(), | 808 instr->env(), |
790 Definition::kEffect); | 809 Definition::kEffect); |
791 comp->set_operands_class_id(kSmiCid); | 810 comp->set_operands_class_id(kSmiCid); |
792 } else if (ShouldSpecializeForDouble(ic_data)) { | 811 } else if (ShouldSpecializeForDouble(ic_data)) { |
793 comp->set_operands_class_id(kDoubleCid); | 812 comp->set_operands_class_id(kDoubleCid); |
794 } else if (comp->ic_data()->AllReceiversAreNumbers()) { | 813 } else if (comp->ic_data()->AllReceiversAreNumbers()) { |
795 comp->set_operands_class_id(kNumberCid); | 814 comp->set_operands_class_id(kNumberCid); |
796 } | 815 } |
797 } | 816 } |
798 | 817 |
799 void FlowGraphOptimizer::VisitRelationalOp(RelationalOpInstr* instr) { | 818 void FlowGraphOptimizer::VisitRelationalOp(RelationalOpComp* comp, |
800 HandleRelationalOp(this, instr, instr); | 819 BindInstr* instr) { |
| 820 HandleRelationalOp(this, comp, instr); |
801 } | 821 } |
802 | 822 |
803 | 823 |
804 // TODO(fschneider): Once we get rid of the distinction between Instruction | 824 // TODO(fschneider): Once we get rid of the distinction between Instruction |
805 // and computation, this helper can go away. | 825 // and computation, this helper can go away. |
806 template <typename T> | 826 template <typename T> |
807 static void HandleEqualityCompare(FlowGraphOptimizer* optimizer, | 827 static void HandleEqualityCompare(FlowGraphOptimizer* optimizer, |
808 EqualityCompareInstr* comp, | 828 EqualityCompareComp* comp, |
809 T instr, | 829 T instr) { |
810 ForwardInstructionIterator* iterator) { | |
811 // If one of the inputs is null, no ICdata will be collected. | 830 // If one of the inputs is null, no ICdata will be collected. |
812 if (comp->left()->BindsToConstantNull() || | 831 if (comp->left()->BindsToConstantNull() || |
813 comp->right()->BindsToConstantNull()) { | 832 comp->right()->BindsToConstantNull()) { |
814 Token::Kind strict_kind = (comp->kind() == Token::kEQ) ? | 833 Token::Kind strict_kind = (comp->kind() == Token::kEQ) ? |
815 Token::kEQ_STRICT : Token::kNE_STRICT; | 834 Token::kEQ_STRICT : Token::kNE_STRICT; |
816 StrictCompareInstr* strict_comp = | 835 StrictCompareComp* strict_comp = |
817 new StrictCompareInstr(strict_kind, comp->left(), comp->right()); | 836 new StrictCompareComp(strict_kind, comp->left(), comp->right()); |
818 instr->ReplaceWith(strict_comp, iterator); | 837 instr->set_computation(strict_comp); |
819 return; | 838 return; |
820 } | 839 } |
821 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) return; | 840 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) return; |
822 if (comp->ic_data()->NumberOfChecks() == 1) { | 841 if (comp->ic_data()->NumberOfChecks() == 1) { |
823 ASSERT(comp->ic_data()->num_args_tested() == 2); | 842 ASSERT(comp->ic_data()->num_args_tested() == 2); |
824 GrowableArray<intptr_t> class_ids; | 843 GrowableArray<intptr_t> class_ids; |
825 Function& target = Function::Handle(); | 844 Function& target = Function::Handle(); |
826 comp->ic_data()->GetCheckAt(0, &class_ids, &target); | 845 comp->ic_data()->GetCheckAt(0, &class_ids, &target); |
827 // TODO(srdjan): allow for mixed mode comparison. | 846 // TODO(srdjan): allow for mixed mode comparison. |
828 if ((class_ids[0] == kSmiCid) && (class_ids[1] == kSmiCid)) { | 847 if ((class_ids[0] == kSmiCid) && (class_ids[1] == kSmiCid)) { |
829 optimizer->InsertBefore( | 848 optimizer->InsertBefore( |
830 instr, | 849 instr, |
831 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()), | 850 new CheckSmiComp(comp->left()->Copy(), comp->deopt_id()), |
832 instr->env(), | 851 instr->env(), |
833 Definition::kEffect); | 852 Definition::kEffect); |
834 optimizer->InsertBefore( | 853 optimizer->InsertBefore( |
835 instr, | 854 instr, |
836 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()), | 855 new CheckSmiComp(comp->right()->Copy(), comp->deopt_id()), |
837 instr->env(), | 856 instr->env(), |
838 Definition::kEffect); | 857 Definition::kEffect); |
839 comp->set_receiver_class_id(kSmiCid); | 858 comp->set_receiver_class_id(kSmiCid); |
840 } else if ((class_ids[0] == kDoubleCid) && (class_ids[1] == kDoubleCid)) { | 859 } else if ((class_ids[0] == kDoubleCid) && (class_ids[1] == kDoubleCid)) { |
841 comp->set_receiver_class_id(kDoubleCid); | 860 comp->set_receiver_class_id(kDoubleCid); |
842 } else { | 861 } else { |
843 ASSERT(comp->receiver_class_id() == kIllegalCid); | 862 ASSERT(comp->receiver_class_id() == kIllegalCid); |
844 } | 863 } |
845 } else if (comp->ic_data()->AllReceiversAreNumbers()) { | 864 } else if (comp->ic_data()->AllReceiversAreNumbers()) { |
846 comp->set_receiver_class_id(kNumberCid); | 865 comp->set_receiver_class_id(kNumberCid); |
847 } | 866 } |
848 } | 867 } |
849 | 868 |
850 | 869 |
851 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareInstr* instr) { | 870 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareComp* comp, |
852 HandleEqualityCompare(this, instr, instr, current_iterator()); | 871 BindInstr* instr) { |
| 872 HandleEqualityCompare(this, comp, instr); |
| 873 } |
| 874 |
| 875 |
| 876 void FlowGraphOptimizer::VisitBind(BindInstr* instr) { |
| 877 instr->computation()->Accept(this, instr); |
853 } | 878 } |
854 | 879 |
855 | 880 |
856 void FlowGraphOptimizer::VisitBranch(BranchInstr* instr) { | 881 void FlowGraphOptimizer::VisitBranch(BranchInstr* instr) { |
857 ComparisonInstr* comparison = instr->comparison(); | 882 ComparisonComp* comparison = instr->computation(); |
858 if (comparison->IsRelationalOp()) { | 883 if (comparison->IsRelationalOp()) { |
859 HandleRelationalOp(this, comparison->AsRelationalOp(), instr); | 884 HandleRelationalOp(this, comparison->AsRelationalOp(), instr); |
860 } else if (comparison->IsEqualityCompare()) { | 885 } else if (comparison->IsEqualityCompare()) { |
861 HandleEqualityCompare(this, comparison->AsEqualityCompare(), instr, | 886 HandleEqualityCompare(this, comparison->AsEqualityCompare(), instr); |
862 current_iterator()); | |
863 } else { | 887 } else { |
864 ASSERT(comparison->IsStrictCompare()); | 888 ASSERT(comparison->IsStrictCompare()); |
865 // Nothing to do. | 889 // Nothing to do. |
866 } | 890 } |
867 } | 891 } |
868 | 892 |
869 | 893 |
870 void FlowGraphTypePropagator::VisitBlocks() { | 894 void FlowGraphTypePropagator::VisitAssertAssignable(AssertAssignableComp* comp, |
871 ASSERT(current_iterator_ == NULL); | 895 BindInstr* instr) { |
872 for (intptr_t i = 0; i < block_order_.length(); ++i) { | 896 if (FLAG_eliminate_type_checks && |
873 BlockEntryInstr* entry = block_order_[i]; | 897 !comp->is_eliminated() && |
874 entry->Accept(this); | 898 comp->value()->CompileTypeIsMoreSpecificThan(comp->dst_type())) { |
875 ForwardInstructionIterator it(entry); | 899 // TODO(regis): Remove is_eliminated_ field and support. |
876 current_iterator_ = ⁢ | 900 comp->eliminate(); |
877 for (; !it.Done(); it.Advance()) { | |
878 Instruction* current = it.Current(); | |
879 // No need to propagate the input types of the instruction, as long as | |
880 // PhiInstr's are handled as part of JoinEntryInstr. | |
881 | 901 |
882 // Visit the instruction and possibly eliminate type checks. | 902 Value* use = comp->value(); |
883 current->Accept(this); | |
884 // The instruction may have been removed from the graph. | |
885 Definition* defn = current->AsDefinition(); | |
886 if ((defn != NULL) && (defn->previous() != NULL)) { | |
887 // Cache the propagated computation type. | |
888 AbstractType& type = AbstractType::Handle(defn->CompileType()); | |
889 still_changing_ = defn->SetPropagatedType(type) || still_changing_; | |
890 | |
891 // Propagate class ids. | |
892 const intptr_t cid = defn->ResultCid(); | |
893 still_changing_ = defn->SetPropagatedCid(cid) || still_changing_; | |
894 } | |
895 } | |
896 current_iterator_ = NULL; | |
897 } | |
898 } | |
899 | |
900 | |
901 void FlowGraphTypePropagator::VisitAssertAssignable( | |
902 AssertAssignableInstr* instr) { | |
903 if (FLAG_eliminate_type_checks && | |
904 !instr->is_eliminated() && | |
905 instr->value()->CompileTypeIsMoreSpecificThan(instr->dst_type())) { | |
906 // TODO(regis): Remove is_eliminated_ field and support. | |
907 instr->eliminate(); | |
908 | |
909 Value* use = instr->value(); | |
910 ASSERT(use != NULL); | 903 ASSERT(use != NULL); |
911 Definition* result = use->definition(); | 904 Definition* result = use->definition(); |
912 ASSERT(result != NULL); | 905 ASSERT(result != NULL); |
913 // Replace uses and remove the current instruction via the iterator. | 906 // Replace uses and remove the current instructions via the iterator. |
914 instr->ReplaceUsesWith(result); | 907 instr->ReplaceUsesWith(result); |
915 ASSERT(current_iterator()->Current() == instr); | 908 ASSERT(current_iterator()->Current() == instr); |
916 current_iterator()->RemoveCurrentFromGraph(); | 909 current_iterator()->RemoveCurrentFromGraph(); |
917 if (FLAG_trace_optimization) { | 910 if (FLAG_trace_optimization) { |
918 OS::Print("Replacing v%d with v%d\n", | 911 OS::Print("Replacing v%d with v%d\n", |
919 instr->ssa_temp_index(), | 912 instr->ssa_temp_index(), |
920 result->ssa_temp_index()); | 913 result->ssa_temp_index()); |
921 } | 914 } |
922 | 915 |
923 if (FLAG_trace_type_check_elimination) { | 916 if (FLAG_trace_type_check_elimination) { |
924 FlowGraphPrinter::PrintTypeCheck(parsed_function(), | 917 FlowGraphPrinter::PrintTypeCheck(parsed_function(), |
925 instr->token_pos(), | 918 comp->token_pos(), |
926 instr->value(), | 919 comp->value(), |
927 instr->dst_type(), | 920 comp->dst_type(), |
928 instr->dst_name(), | 921 comp->dst_name(), |
929 instr->is_eliminated()); | 922 comp->is_eliminated()); |
930 } | 923 } |
931 } | 924 } |
932 } | 925 } |
933 | 926 |
934 | 927 |
935 void FlowGraphTypePropagator::VisitAssertBoolean(AssertBooleanInstr* instr) { | 928 void FlowGraphTypePropagator::VisitAssertBoolean(AssertBooleanComp* comp, |
| 929 BindInstr* instr) { |
936 // TODO(regis): Propagate NullType as well and revise the comment and code | 930 // TODO(regis): Propagate NullType as well and revise the comment and code |
937 // below to also eliminate the test for non-null and non-constant value. | 931 // below to also eliminate the test for non-null and non-constant value. |
938 | 932 |
939 // We can only eliminate an 'assert boolean' test when the checked value is | 933 // We can only eliminate an 'assert boolean' test when the checked value is |
940 // a constant time constant. Indeed, a variable of the proper compile time | 934 // a constant time constant. Indeed, a variable of the proper compile time |
941 // type (bool) may still hold null at run time and therefore fail the test. | 935 // type (bool) may still hold null at run time and therefore fail the test. |
942 if (FLAG_eliminate_type_checks && | 936 if (FLAG_eliminate_type_checks && |
943 !instr->is_eliminated() && | 937 !comp->is_eliminated() && |
944 instr->value()->BindsToConstant() && | 938 comp->value()->BindsToConstant() && |
945 !instr->value()->BindsToConstantNull() && | 939 !comp->value()->BindsToConstantNull() && |
946 instr->value()->CompileTypeIsMoreSpecificThan( | 940 comp->value()->CompileTypeIsMoreSpecificThan( |
947 Type::Handle(Type::BoolType()))) { | 941 Type::Handle(Type::BoolType()))) { |
948 // TODO(regis): Remove is_eliminated_ field and support. | 942 // TODO(regis): Remove is_eliminated_ field and support. |
949 instr->eliminate(); | 943 comp->eliminate(); |
950 | 944 |
951 Value* use = instr->value(); | 945 Value* use = comp->value(); |
952 Definition* result = use->definition(); | 946 Definition* result = use->definition(); |
953 ASSERT(result != NULL); | 947 ASSERT(result != NULL); |
954 // Replace uses and remove the current instruction via the iterator. | 948 // Replace uses and remove the current instructions via the iterator. |
955 instr->ReplaceUsesWith(result); | 949 instr->ReplaceUsesWith(result); |
956 ASSERT(current_iterator()->Current() == instr); | 950 ASSERT(current_iterator()->Current() == instr); |
957 current_iterator()->RemoveCurrentFromGraph(); | 951 current_iterator()->RemoveCurrentFromGraph(); |
958 if (FLAG_trace_optimization) { | 952 if (FLAG_trace_optimization) { |
959 OS::Print("Replacing v%d with v%d\n", | 953 OS::Print("Replacing v%d with v%d\n", |
960 instr->ssa_temp_index(), | 954 instr->ssa_temp_index(), |
961 result->ssa_temp_index()); | 955 result->ssa_temp_index()); |
962 } | 956 } |
963 | 957 |
964 if (FLAG_trace_type_check_elimination) { | 958 if (FLAG_trace_type_check_elimination) { |
965 const String& name = String::Handle(Symbols::New("boolean expression")); | 959 const String& name = String::Handle(Symbols::New("boolean expression")); |
966 FlowGraphPrinter::PrintTypeCheck(parsed_function(), | 960 FlowGraphPrinter::PrintTypeCheck(parsed_function(), |
967 instr->token_pos(), | 961 comp->token_pos(), |
968 instr->value(), | 962 comp->value(), |
969 Type::Handle(Type::BoolType()), | 963 Type::Handle(Type::BoolType()), |
970 name, | 964 name, |
971 instr->is_eliminated()); | 965 comp->is_eliminated()); |
972 } | 966 } |
973 } | 967 } |
974 } | 968 } |
975 | 969 |
976 | 970 |
977 void FlowGraphTypePropagator::VisitInstanceOf(InstanceOfInstr* instr) { | 971 void FlowGraphTypePropagator::VisitInstanceOf(InstanceOfComp* comp, |
| 972 BindInstr* instr) { |
978 // TODO(regis): Propagate NullType as well and revise the comment and code | 973 // TODO(regis): Propagate NullType as well and revise the comment and code |
979 // below to also eliminate the test for non-null and non-constant value. | 974 // below to also eliminate the test for non-null and non-constant value. |
980 | 975 |
981 // We can only eliminate an 'instance of' test when the checked value is | 976 // We can only eliminate an 'instance of' test when the checked value is |
982 // a constant time constant. Indeed, a variable of the proper compile time | 977 // a constant time constant. Indeed, a variable of the proper compile time |
983 // type may still hold null at run time and therefore fail the test. | 978 // type may still hold null at run time and therefore fail the test. |
984 // We do not bother checking for Object destination type, since the graph | 979 // We do not bother checking for Object destination type, since the graph |
985 // builder did already. | 980 // builder did already. |
986 if (FLAG_eliminate_type_checks && | 981 if (FLAG_eliminate_type_checks && |
987 instr->value()->BindsToConstant() && | 982 comp->value()->BindsToConstant() && |
988 !instr->value()->BindsToConstantNull() && | 983 !comp->value()->BindsToConstantNull() && |
989 instr->value()->CompileTypeIsMoreSpecificThan(instr->type())) { | 984 comp->value()->CompileTypeIsMoreSpecificThan(comp->type())) { |
990 Value* use = instr->value(); | 985 Value* use = comp->value(); |
991 Definition* result = use->definition(); | 986 Definition* result = use->definition(); |
992 ASSERT(result != NULL); | 987 ASSERT(result != NULL); |
993 // Replace uses and remove the current instruction via the iterator. | 988 // Replace uses and remove the current instructions via the iterator. |
994 instr->ReplaceUsesWith(result); | 989 instr->ReplaceUsesWith(result); |
995 ASSERT(current_iterator()->Current() == instr); | 990 ASSERT(current_iterator()->Current() == instr); |
996 current_iterator()->RemoveCurrentFromGraph(); | 991 current_iterator()->RemoveCurrentFromGraph(); |
997 if (FLAG_trace_optimization) { | 992 if (FLAG_trace_optimization) { |
998 OS::Print("Replacing v%d with v%d\n", | 993 OS::Print("Replacing v%d with v%d\n", |
999 instr->ssa_temp_index(), | 994 instr->ssa_temp_index(), |
1000 result->ssa_temp_index()); | 995 result->ssa_temp_index()); |
1001 } | 996 } |
1002 | 997 |
1003 if (FLAG_trace_type_check_elimination) { | 998 if (FLAG_trace_type_check_elimination) { |
1004 const String& name = String::Handle(Symbols::New("InstanceOf")); | 999 const String& name = String::Handle(Symbols::New("InstanceOf")); |
1005 FlowGraphPrinter::PrintTypeCheck(parsed_function(), | 1000 FlowGraphPrinter::PrintTypeCheck(parsed_function(), |
1006 instr->token_pos(), | 1001 comp->token_pos(), |
1007 instr->value(), | 1002 comp->value(), |
1008 instr->type(), | 1003 comp->type(), |
1009 name, | 1004 name, |
1010 /* eliminated = */ true); | 1005 /* eliminated = */ true); |
1011 } | 1006 } |
1012 } | 1007 } |
1013 } | 1008 } |
1014 | 1009 |
1015 | 1010 |
1016 void FlowGraphTypePropagator::VisitGraphEntry(GraphEntryInstr* graph_entry) { | 1011 void FlowGraphTypePropagator::VisitGraphEntry(GraphEntryInstr* graph_entry) { |
1017 if (graph_entry->start_env() == NULL) { | 1012 if (graph_entry->start_env() == NULL) { |
1018 return; | 1013 return; |
(...skipping 21 matching lines...) Expand all Loading... |
1040 } | 1035 } |
1041 } | 1036 } |
1042 | 1037 |
1043 | 1038 |
1044 // TODO(srdjan): Investigate if the propagated cid should be more specific. | 1039 // TODO(srdjan): Investigate if the propagated cid should be more specific. |
1045 void FlowGraphTypePropagator::VisitPushArgument(PushArgumentInstr* push) { | 1040 void FlowGraphTypePropagator::VisitPushArgument(PushArgumentInstr* push) { |
1046 if (!push->has_propagated_cid()) push->SetPropagatedCid(kDynamicCid); | 1041 if (!push->has_propagated_cid()) push->SetPropagatedCid(kDynamicCid); |
1047 } | 1042 } |
1048 | 1043 |
1049 | 1044 |
| 1045 void FlowGraphTypePropagator::VisitBind(BindInstr* bind) { |
| 1046 // No need to propagate the input types of the bound computation, as long as |
| 1047 // PhiInstr's are handled as part of JoinEntryInstr. |
| 1048 // Visit computation and possibly eliminate type check. |
| 1049 bind->computation()->Accept(this, bind); |
| 1050 // The current bind may have been removed from the graph. |
| 1051 if (current_iterator()->Current() == bind) { |
| 1052 // Current bind was not removed. |
| 1053 // Cache propagated computation type. |
| 1054 AbstractType& computation_type = |
| 1055 AbstractType::Handle(bind->computation()->CompileType()); |
| 1056 bool changed = bind->SetPropagatedType(computation_type); |
| 1057 if (changed) { |
| 1058 still_changing_ = true; |
| 1059 } |
| 1060 // Propagate class ids. |
| 1061 const intptr_t cid = bind->computation()->ResultCid(); |
| 1062 changed = bind->SetPropagatedCid(cid); |
| 1063 if (changed) { |
| 1064 still_changing_ = true; |
| 1065 } |
| 1066 } |
| 1067 } |
| 1068 |
| 1069 |
1050 void FlowGraphTypePropagator::VisitPhi(PhiInstr* phi) { | 1070 void FlowGraphTypePropagator::VisitPhi(PhiInstr* phi) { |
1051 // We could set the propagated type of the phi to the least upper bound of its | 1071 // We could set the propagated type of the phi to the least upper bound of its |
1052 // input propagated types. However, keeping all propagated types allows us to | 1072 // input propagated types. However, keeping all propagated types allows us to |
1053 // optimize method dispatch. | 1073 // optimize method dispatch. |
1054 // TODO(regis): Support a set of propagated types. For now, we compute the | 1074 // TODO(regis): Support a set of propagated types. For now, we compute the |
1055 // least specific of the input propagated types. | 1075 // least specific of the input propagated types. |
1056 AbstractType& type = AbstractType::Handle(phi->LeastSpecificInputType()); | 1076 AbstractType& type = AbstractType::Handle(phi->LeastSpecificInputType()); |
1057 bool changed = phi->SetPropagatedType(type); | 1077 bool changed = phi->SetPropagatedType(type); |
1058 if (changed) { | 1078 if (changed) { |
1059 still_changing_ = true; | 1079 still_changing_ = true; |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1138 is_leaf_ = false; | 1158 is_leaf_ = false; |
1139 return; | 1159 return; |
1140 } | 1160 } |
1141 } | 1161 } |
1142 } | 1162 } |
1143 } | 1163 } |
1144 | 1164 |
1145 | 1165 |
1146 void DominatorBasedCSE::Optimize(BlockEntryInstr* graph_entry) { | 1166 void DominatorBasedCSE::Optimize(BlockEntryInstr* graph_entry) { |
1147 ASSERT(graph_entry->IsGraphEntry()); | 1167 ASSERT(graph_entry->IsGraphEntry()); |
1148 DirectChainedHashMap<Definition*> map; | 1168 DirectChainedHashMap<BindInstr*> map; |
1149 OptimizeRecursive(graph_entry, &map); | 1169 OptimizeRecursive(graph_entry, &map); |
1150 } | 1170 } |
1151 | 1171 |
1152 | 1172 |
1153 void DominatorBasedCSE::OptimizeRecursive( | 1173 void DominatorBasedCSE::OptimizeRecursive( |
1154 BlockEntryInstr* block, | 1174 BlockEntryInstr* block, |
1155 DirectChainedHashMap<Definition*>* map) { | 1175 DirectChainedHashMap<BindInstr*>* map) { |
1156 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 1176 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
1157 Definition* defn = it.Current()->AsDefinition(); | 1177 BindInstr* instr = it.Current()->AsBind(); |
1158 if ((defn == NULL) || defn->HasSideEffect()) continue; | 1178 if (instr == NULL || instr->computation()->HasSideEffect()) continue; |
1159 Definition* result = map->Lookup(defn); | 1179 BindInstr* result = map->Lookup(instr); |
1160 if (result == NULL) { | 1180 if (result == NULL) { |
1161 map->Insert(defn); | 1181 map->Insert(instr); |
1162 continue; | 1182 continue; |
1163 } | 1183 } |
1164 // Replace current with lookup result. | 1184 // Replace current with lookup result. |
1165 defn->ReplaceUsesWith(result); | 1185 instr->ReplaceUsesWith(result); |
1166 it.RemoveCurrentFromGraph(); | 1186 it.RemoveCurrentFromGraph(); |
1167 if (FLAG_trace_optimization) { | 1187 if (FLAG_trace_optimization) { |
1168 OS::Print("Replacing v%d with v%d\n", | 1188 OS::Print("Replacing v%d with v%d\n", |
1169 defn->ssa_temp_index(), | 1189 instr->ssa_temp_index(), |
1170 result->ssa_temp_index()); | 1190 result->ssa_temp_index()); |
1171 } | 1191 } |
1172 } | 1192 } |
1173 | 1193 |
1174 // Process children in the dominator tree recursively. | 1194 // Process children in the dominator tree recursively. |
1175 intptr_t num_children = block->dominated_blocks().length(); | 1195 intptr_t num_children = block->dominated_blocks().length(); |
1176 for (intptr_t i = 0; i < num_children; ++i) { | 1196 for (intptr_t i = 0; i < num_children; ++i) { |
1177 BlockEntryInstr* child = block->dominated_blocks()[i]; | 1197 BlockEntryInstr* child = block->dominated_blocks()[i]; |
1178 if (i < num_children - 1) { | 1198 if (i < num_children - 1) { |
1179 DirectChainedHashMap<Definition*> child_map(*map); // Copy map. | 1199 DirectChainedHashMap<BindInstr*> child_map(*map); // Copy map. |
1180 OptimizeRecursive(child, &child_map); | 1200 OptimizeRecursive(child, &child_map); |
1181 } else { | 1201 } else { |
1182 OptimizeRecursive(child, map); // Reuse map for the last child. | 1202 OptimizeRecursive(child, map); // Reuse map for the last child. |
1183 } | 1203 } |
1184 } | 1204 } |
1185 } | 1205 } |
1186 | 1206 |
1187 | 1207 |
1188 } // namespace dart | 1208 } // namespace dart |
OLD | NEW |