Chromium Code Reviews| 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 |