OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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/bit_vector.h" | 7 #include "vm/bit_vector.h" |
8 #include "vm/cha.h" | 8 #include "vm/cha.h" |
9 #include "vm/compiler.h" | 9 #include "vm/compiler.h" |
10 #include "vm/cpu.h" | 10 #include "vm/cpu.h" |
(...skipping 4479 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4490 case MethodRecognizer::kMathCos: | 4490 case MethodRecognizer::kMathCos: |
4491 unary_kind = MathUnaryInstr::kCos; | 4491 unary_kind = MathUnaryInstr::kCos; |
4492 break; | 4492 break; |
4493 default: | 4493 default: |
4494 unary_kind = MathUnaryInstr::kIllegal; | 4494 unary_kind = MathUnaryInstr::kIllegal; |
4495 break; | 4495 break; |
4496 } | 4496 } |
4497 if (unary_kind != MathUnaryInstr::kIllegal) { | 4497 if (unary_kind != MathUnaryInstr::kIllegal) { |
4498 if (FLAG_precompilation) { | 4498 if (FLAG_precompilation) { |
4499 // TODO(srdjan): Adapt MathUnaryInstr to allow tagged inputs as well. | 4499 // TODO(srdjan): Adapt MathUnaryInstr to allow tagged inputs as well. |
4500 } else { | |
4501 MathUnaryInstr* math_unary = | |
4502 new(Z) MathUnaryInstr(unary_kind, | |
4503 new(Z) Value(call->ArgumentAt(0)), | |
4504 call->deopt_id()); | |
4505 ReplaceCall(call, math_unary); | |
4506 } | |
4507 } else if ((recognized_kind == MethodRecognizer::kFloat32x4Zero) || | |
4508 (recognized_kind == MethodRecognizer::kFloat32x4Splat) || | |
4509 (recognized_kind == MethodRecognizer::kFloat32x4Constructor) || | |
4510 (recognized_kind == MethodRecognizer::kFloat32x4FromFloat64x2)) { | |
4511 TryInlineFloat32x4Constructor(call, recognized_kind); | |
4512 } else if ((recognized_kind == MethodRecognizer::kFloat64x2Constructor) || | |
4513 (recognized_kind == MethodRecognizer::kFloat64x2Zero) || | |
4514 (recognized_kind == MethodRecognizer::kFloat64x2Splat) || | |
4515 (recognized_kind == MethodRecognizer::kFloat64x2FromFloat32x4)) { | |
4516 TryInlineFloat64x2Constructor(call, recognized_kind); | |
4517 } else if ((recognized_kind == MethodRecognizer::kInt32x4BoolConstructor) || | |
4518 (recognized_kind == MethodRecognizer::kInt32x4Constructor)) { | |
4519 TryInlineInt32x4Constructor(call, recognized_kind); | |
4520 } else if (recognized_kind == MethodRecognizer::kObjectConstructor) { | |
4521 // Remove the original push arguments. | |
4522 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | |
4523 PushArgumentInstr* push = call->PushArgumentAt(i); | |
4524 push->ReplaceUsesWith(push->value()->definition()); | |
4525 push->RemoveFromGraph(); | |
4526 } | |
4527 // Manually replace call with global null constant. ReplaceCall can't | |
4528 // be used for definitions that are already in the graph. | |
4529 call->ReplaceUsesWith(flow_graph_->constant_null()); | |
4530 ASSERT(current_iterator()->Current() == call); | |
4531 current_iterator()->RemoveCurrentFromGraph();; | |
4532 } else if ((recognized_kind == MethodRecognizer::kMathMin) || | |
4533 (recognized_kind == MethodRecognizer::kMathMax)) { | |
4534 // We can handle only monomorphic min/max call sites with both arguments | |
4535 // being either doubles or smis. | |
4536 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) { | |
4537 const ICData& ic_data = *call->ic_data(); | |
4538 intptr_t result_cid = kIllegalCid; | |
4539 if (ICDataHasReceiverArgumentClassIds(ic_data, kDoubleCid, kDoubleCid)) { | |
4540 result_cid = kDoubleCid; | |
4541 } else if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { | |
4542 result_cid = kSmiCid; | |
4543 } | |
4544 if (result_cid != kIllegalCid) { | |
4545 MathMinMaxInstr* min_max = new(Z) MathMinMaxInstr( | |
4546 recognized_kind, | |
4547 new(Z) Value(call->ArgumentAt(0)), | |
4548 new(Z) Value(call->ArgumentAt(1)), | |
4549 call->deopt_id(), | |
4550 result_cid); | |
4551 const ICData& unary_checks = | |
4552 ICData::ZoneHandle(Z, ic_data.AsUnaryClassChecks()); | |
4553 AddCheckClass(min_max->left()->definition(), | |
4554 unary_checks, | |
4555 call->deopt_id(), | |
4556 call->env(), | |
4557 call); | |
4558 AddCheckClass(min_max->right()->definition(), | |
4559 unary_checks, | |
4560 call->deopt_id(), | |
4561 call->env(), | |
4562 call); | |
4563 ReplaceCall(call, min_max); | |
4564 } | |
4565 } | |
4566 } else if ((recognized_kind == MethodRecognizer::kMathDoublePow) || | |
4567 (recognized_kind == MethodRecognizer::kMathAtan) || | |
4568 (recognized_kind == MethodRecognizer::kMathAtan2)) { | |
4569 if (FLAG_precompilation) { | |
4570 // No UnboxDouble instructons allowed. | |
4571 return; | 4500 return; |
4572 } | 4501 } |
4573 // InvokeMathCFunctionInstr requires unboxed doubles. UnboxDouble | 4502 MathUnaryInstr* math_unary = |
4574 // instructions contain type checks and conversions to double. | 4503 new(Z) MathUnaryInstr(unary_kind, |
4575 ZoneGrowableArray<Value*>* args = | 4504 new(Z) Value(call->ArgumentAt(0)), |
4576 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); | 4505 call->deopt_id()); |
4577 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { | 4506 ReplaceCall(call, math_unary); |
4578 args->Add(new(Z) Value(call->ArgumentAt(i))); | 4507 return; |
| 4508 } |
| 4509 switch (recognized_kind) { |
| 4510 case MethodRecognizer::kFloat32x4Zero: |
| 4511 case MethodRecognizer::kFloat32x4Splat: |
| 4512 case MethodRecognizer::kFloat32x4Constructor: |
| 4513 case MethodRecognizer::kFloat32x4FromFloat64x2: |
| 4514 TryInlineFloat32x4Constructor(call, recognized_kind); |
| 4515 break; |
| 4516 case MethodRecognizer::kFloat64x2Constructor: |
| 4517 case MethodRecognizer::kFloat64x2Zero: |
| 4518 case MethodRecognizer::kFloat64x2Splat: |
| 4519 case MethodRecognizer::kFloat64x2FromFloat32x4: |
| 4520 TryInlineFloat64x2Constructor(call, recognized_kind); |
| 4521 break; |
| 4522 case MethodRecognizer::kInt32x4BoolConstructor: |
| 4523 case MethodRecognizer::kInt32x4Constructor: |
| 4524 TryInlineInt32x4Constructor(call, recognized_kind); |
| 4525 break; |
| 4526 case MethodRecognizer::kObjectConstructor: { |
| 4527 // Remove the original push arguments. |
| 4528 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
| 4529 PushArgumentInstr* push = call->PushArgumentAt(i); |
| 4530 push->ReplaceUsesWith(push->value()->definition()); |
| 4531 push->RemoveFromGraph(); |
| 4532 } |
| 4533 // Manually replace call with global null constant. ReplaceCall can't |
| 4534 // be used for definitions that are already in the graph. |
| 4535 call->ReplaceUsesWith(flow_graph_->constant_null()); |
| 4536 ASSERT(current_iterator()->Current() == call); |
| 4537 current_iterator()->RemoveCurrentFromGraph(); |
| 4538 break; |
4579 } | 4539 } |
4580 InvokeMathCFunctionInstr* invoke = | 4540 case MethodRecognizer::kMathMin: |
4581 new(Z) InvokeMathCFunctionInstr(args, | 4541 case MethodRecognizer::kMathMax: { |
4582 call->deopt_id(), | 4542 // We can handle only monomorphic min/max call sites with both arguments |
4583 recognized_kind, | 4543 // being either doubles or smis. |
4584 call->token_pos()); | 4544 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) { |
4585 ReplaceCall(call, invoke); | 4545 const ICData& ic_data = *call->ic_data(); |
4586 } else if (recognized_kind == MethodRecognizer::kDoubleFromInteger) { | 4546 intptr_t result_cid = kIllegalCid; |
4587 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) { | 4547 if (ICDataHasReceiverArgumentClassIds(ic_data, |
4588 const ICData& ic_data = *call->ic_data(); | 4548 kDoubleCid, kDoubleCid)) { |
4589 if (CanUnboxDouble()) { | 4549 result_cid = kDoubleCid; |
4590 if (ArgIsAlways(kSmiCid, ic_data, 1)) { | 4550 } else if (ICDataHasReceiverArgumentClassIds(ic_data, |
4591 Definition* arg = call->ArgumentAt(1); | 4551 kSmiCid, kSmiCid)) { |
4592 AddCheckSmi(arg, call->deopt_id(), call->env(), call); | 4552 result_cid = kSmiCid; |
4593 ReplaceCall(call, | 4553 } |
4594 new(Z) SmiToDoubleInstr(new(Z) Value(arg), | 4554 if (result_cid != kIllegalCid) { |
4595 call->token_pos())); | 4555 MathMinMaxInstr* min_max = new(Z) MathMinMaxInstr( |
4596 } else if (ArgIsAlways(kMintCid, ic_data, 1) && | 4556 recognized_kind, |
4597 CanConvertUnboxedMintToDouble()) { | 4557 new(Z) Value(call->ArgumentAt(0)), |
4598 Definition* arg = call->ArgumentAt(1); | 4558 new(Z) Value(call->ArgumentAt(1)), |
4599 ReplaceCall(call, | 4559 call->deopt_id(), |
4600 new(Z) MintToDoubleInstr(new(Z) Value(arg), | 4560 result_cid); |
4601 call->deopt_id())); | 4561 const ICData& unary_checks = |
| 4562 ICData::ZoneHandle(Z, ic_data.AsUnaryClassChecks()); |
| 4563 AddCheckClass(min_max->left()->definition(), |
| 4564 unary_checks, |
| 4565 call->deopt_id(), |
| 4566 call->env(), |
| 4567 call); |
| 4568 AddCheckClass(min_max->right()->definition(), |
| 4569 unary_checks, |
| 4570 call->deopt_id(), |
| 4571 call->env(), |
| 4572 call); |
| 4573 ReplaceCall(call, min_max); |
| 4574 } |
| 4575 } |
| 4576 break; |
| 4577 } |
| 4578 case MethodRecognizer::kMathDoublePow: |
| 4579 case MethodRecognizer::kMathTan: |
| 4580 case MethodRecognizer::kMathAsin: |
| 4581 case MethodRecognizer::kMathAcos: |
| 4582 case MethodRecognizer::kMathAtan: |
| 4583 case MethodRecognizer::kMathAtan2: { |
| 4584 if (FLAG_precompilation) { |
| 4585 // No UnboxDouble instructons allowed. |
| 4586 return; |
| 4587 } |
| 4588 // InvokeMathCFunctionInstr requires unboxed doubles. UnboxDouble |
| 4589 // instructions contain type checks and conversions to double. |
| 4590 ZoneGrowableArray<Value*>* args = |
| 4591 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); |
| 4592 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { |
| 4593 args->Add(new(Z) Value(call->ArgumentAt(i))); |
| 4594 } |
| 4595 InvokeMathCFunctionInstr* invoke = |
| 4596 new(Z) InvokeMathCFunctionInstr(args, |
| 4597 call->deopt_id(), |
| 4598 recognized_kind, |
| 4599 call->token_pos()); |
| 4600 ReplaceCall(call, invoke); |
| 4601 break; |
| 4602 } |
| 4603 case MethodRecognizer::kDoubleFromInteger: { |
| 4604 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) { |
| 4605 const ICData& ic_data = *call->ic_data(); |
| 4606 if (CanUnboxDouble()) { |
| 4607 if (ArgIsAlways(kSmiCid, ic_data, 1)) { |
| 4608 Definition* arg = call->ArgumentAt(1); |
| 4609 AddCheckSmi(arg, call->deopt_id(), call->env(), call); |
| 4610 ReplaceCall(call, |
| 4611 new(Z) SmiToDoubleInstr(new(Z) Value(arg), |
| 4612 call->token_pos())); |
| 4613 } else if (ArgIsAlways(kMintCid, ic_data, 1) && |
| 4614 CanConvertUnboxedMintToDouble()) { |
| 4615 Definition* arg = call->ArgumentAt(1); |
| 4616 ReplaceCall(call, |
| 4617 new(Z) MintToDoubleInstr(new(Z) Value(arg), |
| 4618 call->deopt_id())); |
| 4619 } |
| 4620 } |
| 4621 } |
| 4622 break; |
| 4623 } |
| 4624 default: { |
| 4625 if (call->function().IsFactory()) { |
| 4626 const Class& function_class = |
| 4627 Class::Handle(Z, call->function().Owner()); |
| 4628 if ((function_class.library() == Library::CoreLibrary()) || |
| 4629 (function_class.library() == Library::TypedDataLibrary())) { |
| 4630 intptr_t cid = FactoryRecognizer::ResultCid(call->function()); |
| 4631 switch (cid) { |
| 4632 case kArrayCid: { |
| 4633 Value* type = new(Z) Value(call->ArgumentAt(0)); |
| 4634 Value* num_elements = new(Z) Value(call->ArgumentAt(1)); |
| 4635 if (num_elements->BindsToConstant() && |
| 4636 num_elements->BoundConstant().IsSmi()) { |
| 4637 intptr_t length = |
| 4638 Smi::Cast(num_elements->BoundConstant()).Value(); |
| 4639 if (length >= 0 && length <= Array::kMaxElements) { |
| 4640 CreateArrayInstr* create_array = |
| 4641 new(Z) CreateArrayInstr( |
| 4642 call->token_pos(), type, num_elements); |
| 4643 ReplaceCall(call, create_array); |
| 4644 } |
| 4645 } |
| 4646 } |
| 4647 default: |
| 4648 break; |
| 4649 } |
4602 } | 4650 } |
4603 } | 4651 } |
4604 } | 4652 } |
4605 } else if (call->function().IsFactory()) { | |
4606 const Class& function_class = | |
4607 Class::Handle(Z, call->function().Owner()); | |
4608 if ((function_class.library() == Library::CoreLibrary()) || | |
4609 (function_class.library() == Library::TypedDataLibrary())) { | |
4610 intptr_t cid = FactoryRecognizer::ResultCid(call->function()); | |
4611 switch (cid) { | |
4612 case kArrayCid: { | |
4613 Value* type = new(Z) Value(call->ArgumentAt(0)); | |
4614 Value* num_elements = new(Z) Value(call->ArgumentAt(1)); | |
4615 if (num_elements->BindsToConstant() && | |
4616 num_elements->BoundConstant().IsSmi()) { | |
4617 intptr_t length = Smi::Cast(num_elements->BoundConstant()).Value(); | |
4618 if (length >= 0 && length <= Array::kMaxElements) { | |
4619 CreateArrayInstr* create_array = | |
4620 new(Z) CreateArrayInstr( | |
4621 call->token_pos(), type, num_elements); | |
4622 ReplaceCall(call, create_array); | |
4623 } | |
4624 } | |
4625 } | |
4626 default: | |
4627 break; | |
4628 } | |
4629 } | |
4630 } | 4653 } |
4631 } | 4654 } |
4632 | 4655 |
4633 | 4656 |
4634 void FlowGraphOptimizer::VisitStoreInstanceField( | 4657 void FlowGraphOptimizer::VisitStoreInstanceField( |
4635 StoreInstanceFieldInstr* instr) { | 4658 StoreInstanceFieldInstr* instr) { |
4636 if (instr->IsUnboxedStore()) { | 4659 if (instr->IsUnboxedStore()) { |
4637 ASSERT(instr->is_potential_unboxed_initialization_); | 4660 ASSERT(instr->is_potential_unboxed_initialization_); |
4638 // Determine if this field should be unboxed based on the usage of getter | 4661 // Determine if this field should be unboxed based on the usage of getter |
4639 // and setter functions: The heuristic requires that the setter has a | 4662 // and setter functions: The heuristic requires that the setter has a |
(...skipping 4208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8848 | 8871 |
8849 // Insert materializations at environment uses. | 8872 // Insert materializations at environment uses. |
8850 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { | 8873 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { |
8851 CreateMaterializationAt( | 8874 CreateMaterializationAt( |
8852 exits_collector_.exits()[i], alloc, *slots); | 8875 exits_collector_.exits()[i], alloc, *slots); |
8853 } | 8876 } |
8854 } | 8877 } |
8855 | 8878 |
8856 | 8879 |
8857 } // namespace dart | 8880 } // namespace dart |
OLD | NEW |