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