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_inliner.h" | 5 #include "vm/flow_graph_inliner.h" |
6 | 6 |
7 #include "vm/aot_optimizer.h" | 7 #include "vm/aot_optimizer.h" |
8 #include "vm/block_scheduler.h" | 8 #include "vm/block_scheduler.h" |
9 #include "vm/branch_optimizer.h" | 9 #include "vm/branch_optimizer.h" |
10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
(...skipping 2334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2345 FlowGraph::kEffect); | 2345 FlowGraph::kEffect); |
2346 return true; | 2346 return true; |
2347 } | 2347 } |
2348 | 2348 |
2349 | 2349 |
2350 static bool InlineDoubleOp(FlowGraph* flow_graph, | 2350 static bool InlineDoubleOp(FlowGraph* flow_graph, |
2351 Token::Kind op_kind, | 2351 Token::Kind op_kind, |
2352 Instruction* call, | 2352 Instruction* call, |
2353 TargetEntryInstr** entry, | 2353 TargetEntryInstr** entry, |
2354 Definition** last) { | 2354 Definition** last) { |
| 2355 if (!CanUnboxDouble()) { |
| 2356 return false; |
| 2357 } |
2355 Definition* left = call->ArgumentAt(0); | 2358 Definition* left = call->ArgumentAt(0); |
2356 Definition* right = call->ArgumentAt(1); | 2359 Definition* right = call->ArgumentAt(1); |
2357 | 2360 |
2358 *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(), | 2361 *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(), |
2359 call->GetBlock()->try_index()); | 2362 call->GetBlock()->try_index()); |
2360 (*entry)->InheritDeoptTarget(Z, call); | 2363 (*entry)->InheritDeoptTarget(Z, call); |
2361 // Arguments are checked. No need for class check. | 2364 // Arguments are checked. No need for class check. |
2362 BinaryDoubleOpInstr* double_bin_op = | 2365 BinaryDoubleOpInstr* double_bin_op = |
2363 new(Z) BinaryDoubleOpInstr(op_kind, | 2366 new(Z) BinaryDoubleOpInstr(op_kind, |
2364 new(Z) Value(left), | 2367 new(Z) Value(left), |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2414 new(Z) Value(value), | 2417 new(Z) Value(value), |
2415 store_barrier_type, | 2418 store_barrier_type, |
2416 call->token_pos()); | 2419 call->token_pos()); |
2417 flow_graph->AppendTo(*entry, store, call->env(), FlowGraph::kEffect); | 2420 flow_graph->AppendTo(*entry, store, call->env(), FlowGraph::kEffect); |
2418 *last = store; | 2421 *last = store; |
2419 | 2422 |
2420 return true; | 2423 return true; |
2421 } | 2424 } |
2422 | 2425 |
2423 | 2426 |
2424 static intptr_t PrepareInlineByteArrayBaseOp( | 2427 static void PrepareInlineByteArrayBaseOp( |
2425 FlowGraph* flow_graph, | 2428 FlowGraph* flow_graph, |
2426 Instruction* call, | 2429 Instruction* call, |
2427 intptr_t array_cid, | 2430 intptr_t array_cid, |
2428 intptr_t view_cid, | 2431 intptr_t view_cid, |
2429 Definition** array, | 2432 Definition** array, |
2430 Definition* byte_index, | 2433 Definition* byte_index, |
2431 Instruction** cursor) { | 2434 Instruction** cursor) { |
2432 LoadFieldInstr* length = | 2435 LoadFieldInstr* length = |
2433 new(Z) LoadFieldInstr( | 2436 new(Z) LoadFieldInstr( |
2434 new(Z) Value(*array), | 2437 new(Z) Value(*array), |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2492 if (RawObject::IsExternalTypedDataClassId(array_cid)) { | 2495 if (RawObject::IsExternalTypedDataClassId(array_cid)) { |
2493 LoadUntaggedInstr* elements = | 2496 LoadUntaggedInstr* elements = |
2494 new(Z) LoadUntaggedInstr(new(Z) Value(*array), | 2497 new(Z) LoadUntaggedInstr(new(Z) Value(*array), |
2495 ExternalTypedData::data_offset()); | 2498 ExternalTypedData::data_offset()); |
2496 *cursor = flow_graph->AppendTo(*cursor, | 2499 *cursor = flow_graph->AppendTo(*cursor, |
2497 elements, | 2500 elements, |
2498 NULL, | 2501 NULL, |
2499 FlowGraph::kValue); | 2502 FlowGraph::kValue); |
2500 *array = elements; | 2503 *array = elements; |
2501 } | 2504 } |
2502 return array_cid; | |
2503 } | 2505 } |
2504 | 2506 |
2505 | 2507 |
2506 static bool InlineByteArrayBaseLoad(FlowGraph* flow_graph, | 2508 static bool InlineByteArrayBaseLoad(FlowGraph* flow_graph, |
2507 Instruction* call, | 2509 Instruction* call, |
2508 Definition* receiver, | 2510 Definition* receiver, |
2509 intptr_t array_cid, | 2511 intptr_t array_cid, |
2510 intptr_t view_cid, | 2512 intptr_t view_cid, |
2511 TargetEntryInstr** entry, | 2513 TargetEntryInstr** entry, |
2512 Definition** last) { | 2514 Definition** last) { |
2513 ASSERT(array_cid != kIllegalCid); | 2515 ASSERT(array_cid != kIllegalCid); |
2514 Definition* array = receiver; | 2516 Definition* array = receiver; |
2515 Definition* index = call->ArgumentAt(1); | 2517 Definition* index = call->ArgumentAt(1); |
2516 *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(), | 2518 *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(), |
2517 call->GetBlock()->try_index()); | 2519 call->GetBlock()->try_index()); |
2518 (*entry)->InheritDeoptTarget(Z, call); | 2520 (*entry)->InheritDeoptTarget(Z, call); |
2519 Instruction* cursor = *entry; | 2521 Instruction* cursor = *entry; |
2520 | 2522 |
2521 array_cid = PrepareInlineByteArrayBaseOp(flow_graph, | 2523 PrepareInlineByteArrayBaseOp(flow_graph, |
2522 call, | 2524 call, |
2523 array_cid, | 2525 array_cid, |
2524 view_cid, | 2526 view_cid, |
2525 &array, | 2527 &array, |
2526 index, | 2528 index, |
2527 &cursor); | 2529 &cursor); |
2528 | 2530 |
2529 intptr_t deopt_id = Thread::kNoDeoptId; | 2531 intptr_t deopt_id = Thread::kNoDeoptId; |
2530 if ((array_cid == kTypedDataInt32ArrayCid) || | 2532 if ((array_cid == kTypedDataInt32ArrayCid) || |
2531 (array_cid == kTypedDataUint32ArrayCid)) { | 2533 (array_cid == kTypedDataUint32ArrayCid)) { |
2532 // Deoptimization may be needed if result does not always fit in a Smi. | 2534 // Deoptimization may be needed if result does not always fit in a Smi. |
2533 deopt_id = (kSmiBits >= 32) ? Thread::kNoDeoptId : call->deopt_id(); | 2535 deopt_id = (kSmiBits >= 32) ? Thread::kNoDeoptId : call->deopt_id(); |
2534 } | 2536 } |
2535 | 2537 |
2536 *last = new(Z) LoadIndexedInstr(new(Z) Value(array), | 2538 *last = new(Z) LoadIndexedInstr(new(Z) Value(array), |
2537 new(Z) Value(index), | 2539 new(Z) Value(index), |
(...skipping 27 matching lines...) Expand all Loading... |
2565 TargetEntryInstr** entry, | 2567 TargetEntryInstr** entry, |
2566 Definition** last) { | 2568 Definition** last) { |
2567 ASSERT(array_cid != kIllegalCid); | 2569 ASSERT(array_cid != kIllegalCid); |
2568 Definition* array = receiver; | 2570 Definition* array = receiver; |
2569 Definition* index = call->ArgumentAt(1); | 2571 Definition* index = call->ArgumentAt(1); |
2570 *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(), | 2572 *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(), |
2571 call->GetBlock()->try_index()); | 2573 call->GetBlock()->try_index()); |
2572 (*entry)->InheritDeoptTarget(Z, call); | 2574 (*entry)->InheritDeoptTarget(Z, call); |
2573 Instruction* cursor = *entry; | 2575 Instruction* cursor = *entry; |
2574 | 2576 |
2575 array_cid = PrepareInlineByteArrayBaseOp(flow_graph, | 2577 PrepareInlineByteArrayBaseOp(flow_graph, |
2576 call, | 2578 call, |
2577 array_cid, | 2579 array_cid, |
2578 view_cid, | 2580 view_cid, |
2579 &array, | 2581 &array, |
2580 index, | 2582 index, |
2581 &cursor); | 2583 &cursor); |
2582 | 2584 |
2583 // Extract the instance call so we can use the function_name in the stored | 2585 // Extract the instance call so we can use the function_name in the stored |
2584 // value check ICData. | 2586 // value check ICData. |
2585 InstanceCallInstr* i_call = NULL; | 2587 InstanceCallInstr* i_call = NULL; |
2586 if (call->IsPolymorphicInstanceCall()) { | 2588 if (call->IsPolymorphicInstanceCall()) { |
2587 i_call = call->AsPolymorphicInstanceCall()->instance_call(); | 2589 i_call = call->AsPolymorphicInstanceCall()->instance_call(); |
2588 } else { | 2590 } else { |
2589 ASSERT(call->IsInstanceCall()); | 2591 ASSERT(call->IsInstanceCall()); |
2590 i_call = call->AsInstanceCall(); | 2592 i_call = call->AsInstanceCall(); |
2591 } | 2593 } |
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2867 flow_graph->InsertBefore(call, check, call->env(), FlowGraph::kEffect); | 2869 flow_graph->InsertBefore(call, check, call->env(), FlowGraph::kEffect); |
2868 } | 2870 } |
2869 | 2871 |
2870 // Remove the original push arguments. | 2872 // Remove the original push arguments. |
2871 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | 2873 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
2872 PushArgumentInstr* push = call->PushArgumentAt(i); | 2874 PushArgumentInstr* push = call->PushArgumentAt(i); |
2873 push->ReplaceUsesWith(push->value()->definition()); | 2875 push->ReplaceUsesWith(push->value()->definition()); |
2874 push->RemoveFromGraph(); | 2876 push->RemoveFromGraph(); |
2875 } | 2877 } |
2876 // Replace all uses of this definition with the result. | 2878 // Replace all uses of this definition with the result. |
2877 call->ReplaceUsesWith(last); | 2879 if (call->HasUses()) { |
| 2880 call->ReplaceUsesWith(last); |
| 2881 } |
2878 // Finally insert the sequence other definition in place of this one in the | 2882 // Finally insert the sequence other definition in place of this one in the |
2879 // graph. | 2883 // graph. |
2880 call->previous()->LinkTo(entry->next()); | 2884 if (entry->next() != NULL) { |
| 2885 call->previous()->LinkTo(entry->next()); |
| 2886 } |
2881 entry->UnuseAllInputs(); // Entry block is not in the graph. | 2887 entry->UnuseAllInputs(); // Entry block is not in the graph. |
2882 last->LinkTo(call); | 2888 if (last != NULL) { |
| 2889 last->LinkTo(call); |
| 2890 } |
2883 // Remove through the iterator. | 2891 // Remove through the iterator. |
2884 ASSERT(iterator->Current() == call); | 2892 ASSERT(iterator->Current() == call); |
2885 iterator->RemoveCurrentFromGraph(); | 2893 iterator->RemoveCurrentFromGraph(); |
2886 call->set_previous(NULL); | 2894 call->set_previous(NULL); |
2887 call->set_next(NULL); | 2895 call->set_next(NULL); |
2888 return true; | 2896 return true; |
2889 } | 2897 } |
2890 return false; | 2898 return false; |
2891 } | 2899 } |
2892 | 2900 |
(...skipping 12 matching lines...) Expand all Loading... |
2905 call->token_pos(), | 2913 call->token_pos(), |
2906 *call->ic_data(), | 2914 *call->ic_data(), |
2907 &entry, &last)) { | 2915 &entry, &last)) { |
2908 // Remove the original push arguments. | 2916 // Remove the original push arguments. |
2909 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | 2917 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
2910 PushArgumentInstr* push = call->PushArgumentAt(i); | 2918 PushArgumentInstr* push = call->PushArgumentAt(i); |
2911 push->ReplaceUsesWith(push->value()->definition()); | 2919 push->ReplaceUsesWith(push->value()->definition()); |
2912 push->RemoveFromGraph(); | 2920 push->RemoveFromGraph(); |
2913 } | 2921 } |
2914 // Replace all uses of this definition with the result. | 2922 // Replace all uses of this definition with the result. |
2915 call->ReplaceUsesWith(last); | 2923 if (call->HasUses()) { |
| 2924 call->ReplaceUsesWith(last); |
| 2925 } |
2916 // Finally insert the sequence other definition in place of this one in the | 2926 // Finally insert the sequence other definition in place of this one in the |
2917 // graph. | 2927 // graph. |
2918 call->previous()->LinkTo(entry->next()); | 2928 if (entry->next() != NULL) { |
| 2929 call->previous()->LinkTo(entry->next()); |
| 2930 } |
2919 entry->UnuseAllInputs(); // Entry block is not in the graph. | 2931 entry->UnuseAllInputs(); // Entry block is not in the graph. |
2920 last->LinkTo(call); | 2932 if (last != NULL) { |
| 2933 last->LinkTo(call); |
| 2934 } |
2921 // Remove through the iterator. | 2935 // Remove through the iterator. |
2922 ASSERT(iterator->Current() == call); | 2936 ASSERT(iterator->Current() == call); |
2923 iterator->RemoveCurrentFromGraph(); | 2937 iterator->RemoveCurrentFromGraph(); |
2924 call->set_previous(NULL); | 2938 call->set_previous(NULL); |
2925 call->set_next(NULL); | 2939 call->set_next(NULL); |
2926 return true; | 2940 return true; |
2927 } | 2941 } |
2928 return false; | 2942 return false; |
2929 } | 2943 } |
2930 | 2944 |
(...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3320 return false; | 3334 return false; |
3321 } | 3335 } |
3322 flow_graph->AppendTo(cursor, *last, | 3336 flow_graph->AppendTo(cursor, *last, |
3323 call->deopt_id() != Thread::kNoDeoptId ? | 3337 call->deopt_id() != Thread::kNoDeoptId ? |
3324 call->env() : NULL, | 3338 call->env() : NULL, |
3325 FlowGraph::kValue); | 3339 FlowGraph::kValue); |
3326 return true; | 3340 return true; |
3327 } | 3341 } |
3328 | 3342 |
3329 | 3343 |
| 3344 static bool InlineMathCFunction(FlowGraph* flow_graph, |
| 3345 Instruction* call, |
| 3346 MethodRecognizer::Kind kind, |
| 3347 TargetEntryInstr** entry, |
| 3348 Definition** last) { |
| 3349 if (!CanUnboxDouble()) { |
| 3350 return false; |
| 3351 } |
| 3352 *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(), |
| 3353 call->GetBlock()->try_index()); |
| 3354 (*entry)->InheritDeoptTarget(Z, call); |
| 3355 Instruction* cursor = *entry; |
| 3356 |
| 3357 switch (kind) { |
| 3358 case MethodRecognizer::kMathSqrt: { |
| 3359 *last = new(Z) MathUnaryInstr(MathUnaryInstr::kSqrt, |
| 3360 new(Z) Value(call->ArgumentAt(0)), |
| 3361 call->deopt_id()); |
| 3362 break; |
| 3363 } |
| 3364 default: { |
| 3365 ZoneGrowableArray<Value*>* args = |
| 3366 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); |
| 3367 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { |
| 3368 args->Add(new(Z) Value(call->ArgumentAt(i))); |
| 3369 } |
| 3370 *last = new(Z) InvokeMathCFunctionInstr(args, |
| 3371 call->deopt_id(), |
| 3372 kind, |
| 3373 call->token_pos()); |
| 3374 break; |
| 3375 } |
| 3376 } |
| 3377 flow_graph->AppendTo(cursor, *last, |
| 3378 call->deopt_id() != Thread::kNoDeoptId ? |
| 3379 call->env() : NULL, |
| 3380 FlowGraph::kValue); |
| 3381 return true; |
| 3382 } |
| 3383 |
| 3384 |
3330 bool FlowGraphInliner::TryInlineRecognizedMethod(FlowGraph* flow_graph, | 3385 bool FlowGraphInliner::TryInlineRecognizedMethod(FlowGraph* flow_graph, |
3331 intptr_t receiver_cid, | 3386 intptr_t receiver_cid, |
3332 const Function& target, | 3387 const Function& target, |
3333 Instruction* call, | 3388 Definition* call, |
3334 Definition* receiver, | 3389 Definition* receiver, |
3335 TokenPosition token_pos, | 3390 TokenPosition token_pos, |
3336 const ICData& ic_data, | 3391 const ICData& ic_data, |
3337 TargetEntryInstr** entry, | 3392 TargetEntryInstr** entry, |
3338 Definition** last) { | 3393 Definition** last) { |
3339 ICData& value_check = ICData::ZoneHandle(Z); | 3394 ICData& value_check = ICData::ZoneHandle(Z); |
3340 MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(target); | 3395 MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(target); |
3341 switch (kind) { | 3396 switch (kind) { |
3342 // Recognized [] operators. | 3397 // Recognized [] operators. |
3343 case MethodRecognizer::kImmutableArrayGetIndexed: | 3398 case MethodRecognizer::kImmutableArrayGetIndexed: |
(...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3646 case MethodRecognizer::kFloat32x4FromFloat64x2: | 3701 case MethodRecognizer::kFloat32x4FromFloat64x2: |
3647 case MethodRecognizer::kFloat64x2Constructor: | 3702 case MethodRecognizer::kFloat64x2Constructor: |
3648 case MethodRecognizer::kFloat64x2Zero: | 3703 case MethodRecognizer::kFloat64x2Zero: |
3649 case MethodRecognizer::kFloat64x2Splat: | 3704 case MethodRecognizer::kFloat64x2Splat: |
3650 case MethodRecognizer::kFloat64x2FromFloat32x4: | 3705 case MethodRecognizer::kFloat64x2FromFloat32x4: |
3651 case MethodRecognizer::kInt32x4BoolConstructor: | 3706 case MethodRecognizer::kInt32x4BoolConstructor: |
3652 case MethodRecognizer::kInt32x4Constructor: | 3707 case MethodRecognizer::kInt32x4Constructor: |
3653 case MethodRecognizer::kInt32x4FromFloat32x4Bits: | 3708 case MethodRecognizer::kInt32x4FromFloat32x4Bits: |
3654 return InlineSimdConstructor(flow_graph, call, kind, entry, last); | 3709 return InlineSimdConstructor(flow_graph, call, kind, entry, last); |
3655 | 3710 |
| 3711 case MethodRecognizer::kMathSqrt: |
| 3712 case MethodRecognizer::kMathDoublePow: |
| 3713 case MethodRecognizer::kMathSin: |
| 3714 case MethodRecognizer::kMathCos: |
| 3715 case MethodRecognizer::kMathTan: |
| 3716 case MethodRecognizer::kMathAsin: |
| 3717 case MethodRecognizer::kMathAcos: |
| 3718 case MethodRecognizer::kMathAtan: |
| 3719 case MethodRecognizer::kMathAtan2: |
| 3720 return InlineMathCFunction(flow_graph, call, kind, entry, last); |
| 3721 |
| 3722 case MethodRecognizer::kObjectConstructor: { |
| 3723 *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(), |
| 3724 call->GetBlock()->try_index()); |
| 3725 (*entry)->InheritDeoptTarget(Z, call); |
| 3726 ASSERT(!call->HasUses()); |
| 3727 *last = NULL; // Empty body. |
| 3728 return true; |
| 3729 } |
| 3730 |
| 3731 case MethodRecognizer::kObjectArrayAllocate: { |
| 3732 Value* num_elements = new(Z) Value(call->ArgumentAt(1)); |
| 3733 if (num_elements->BindsToConstant() && |
| 3734 num_elements->BoundConstant().IsSmi()) { |
| 3735 intptr_t length = |
| 3736 Smi::Cast(num_elements->BoundConstant()).Value(); |
| 3737 if (length >= 0 && length <= Array::kMaxElements) { |
| 3738 Value* type = new(Z) Value(call->ArgumentAt(0)); |
| 3739 *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(), |
| 3740 call->GetBlock()->try_index()); |
| 3741 (*entry)->InheritDeoptTarget(Z, call); |
| 3742 *last = |
| 3743 new(Z) CreateArrayInstr(call->token_pos(), type, num_elements); |
| 3744 flow_graph->AppendTo(*entry, *last, |
| 3745 call->deopt_id() != Thread::kNoDeoptId ? |
| 3746 call->env() : NULL, |
| 3747 FlowGraph::kValue); |
| 3748 return true; |
| 3749 } |
| 3750 } |
| 3751 return false; |
| 3752 } |
| 3753 |
| 3754 case MethodRecognizer::kOneByteStringSetAt: { |
| 3755 // This is an internal method, no need to check argument types nor |
| 3756 // range. |
| 3757 *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(), |
| 3758 call->GetBlock()->try_index()); |
| 3759 (*entry)->InheritDeoptTarget(Z, call); |
| 3760 Definition* str = call->ArgumentAt(0); |
| 3761 Definition* index = call->ArgumentAt(1); |
| 3762 Definition* value = call->ArgumentAt(2); |
| 3763 *last = new(Z) StoreIndexedInstr( |
| 3764 new(Z) Value(str), |
| 3765 new(Z) Value(index), |
| 3766 new(Z) Value(value), |
| 3767 kNoStoreBarrier, |
| 3768 1, // Index scale |
| 3769 kOneByteStringCid, |
| 3770 call->deopt_id(), |
| 3771 call->token_pos()); |
| 3772 flow_graph->AppendTo(*entry, |
| 3773 *last, |
| 3774 call->deopt_id() != Thread::kNoDeoptId ? |
| 3775 call->env() : NULL, |
| 3776 FlowGraph::kEffect); |
| 3777 return true; |
| 3778 } |
| 3779 |
3656 default: | 3780 default: |
3657 return false; | 3781 return false; |
3658 } | 3782 } |
3659 } | 3783 } |
3660 | 3784 |
3661 | 3785 |
3662 } // namespace dart | 3786 } // namespace dart |
OLD | NEW |