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/cpu.h" | 9 #include "vm/cpu.h" |
10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
(...skipping 1542 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1553 if (!ShouldInlineSimd()) { | 1553 if (!ShouldInlineSimd()) { |
1554 return false; | 1554 return false; |
1555 } | 1555 } |
1556 return InlineByteArrayViewStore(target, call, receiver, receiver_cid, | 1556 return InlineByteArrayViewStore(target, call, receiver, receiver_cid, |
1557 kTypedDataInt32x4ArrayCid, | 1557 kTypedDataInt32x4ArrayCid, |
1558 ic_data, entry, last); | 1558 ic_data, entry, last); |
1559 case MethodRecognizer::kStringBaseCodeUnitAt: | 1559 case MethodRecognizer::kStringBaseCodeUnitAt: |
1560 return InlineStringCodeUnitAt(call, receiver_cid, entry, last); | 1560 return InlineStringCodeUnitAt(call, receiver_cid, entry, last); |
1561 case MethodRecognizer::kStringBaseCharAt: | 1561 case MethodRecognizer::kStringBaseCharAt: |
1562 return InlineStringBaseCharAt(call, receiver_cid, entry, last); | 1562 return InlineStringBaseCharAt(call, receiver_cid, entry, last); |
| 1563 case MethodRecognizer::kDoubleAdd: |
| 1564 return InlineDoubleOp(Token::kADD, call, entry, last); |
| 1565 case MethodRecognizer::kDoubleSub: |
| 1566 return InlineDoubleOp(Token::kSUB, call, entry, last); |
| 1567 case MethodRecognizer::kDoubleMul: |
| 1568 return InlineDoubleOp(Token::kMUL, call, entry, last); |
| 1569 case MethodRecognizer::kDoubleDiv: |
| 1570 return InlineDoubleOp(Token::kDIV, call, entry, last); |
1563 default: | 1571 default: |
1564 return false; | 1572 return false; |
1565 } | 1573 } |
1566 } | 1574 } |
1567 | 1575 |
1568 | 1576 |
1569 intptr_t FlowGraphOptimizer::PrepareInlineIndexedOp(Instruction* call, | 1577 intptr_t FlowGraphOptimizer::PrepareInlineIndexedOp(Instruction* call, |
1570 intptr_t array_cid, | 1578 intptr_t array_cid, |
1571 Definition** array, | 1579 Definition** array, |
1572 Definition* index, | 1580 Definition* index, |
(...skipping 756 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2329 // Reset value types if guarded_cid was used. | 2337 // Reset value types if guarded_cid was used. |
2330 for (Value::Iterator it(load->input_use_list()); | 2338 for (Value::Iterator it(load->input_use_list()); |
2331 !it.Done(); | 2339 !it.Done(); |
2332 it.Advance()) { | 2340 it.Advance()) { |
2333 it.Current()->SetReachingType(NULL); | 2341 it.Current()->SetReachingType(NULL); |
2334 } | 2342 } |
2335 } | 2343 } |
2336 } | 2344 } |
2337 | 2345 |
2338 | 2346 |
2339 LoadFieldInstr* FlowGraphOptimizer::BuildLoadStringLength(Definition* str) { | |
2340 // Treat length loads as mutable (i.e. affected by side effects) to avoid | |
2341 // hoisting them since we can't hoist the preceding class-check. This | |
2342 // is because of externalization of strings that affects their class-id. | |
2343 LoadFieldInstr* load = new(I) LoadFieldInstr( | |
2344 new(I) Value(str), | |
2345 String::length_offset(), | |
2346 Type::ZoneHandle(I, Type::SmiType()), | |
2347 str->token_pos()); | |
2348 load->set_result_cid(kSmiCid); | |
2349 load->set_recognized_kind(MethodRecognizer::kStringBaseLength); | |
2350 return load; | |
2351 } | |
2352 | |
2353 | |
2354 bool FlowGraphOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call, | 2347 bool FlowGraphOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call, |
2355 MethodRecognizer::Kind getter) { | 2348 MethodRecognizer::Kind getter) { |
2356 if (!ShouldInlineSimd()) { | 2349 if (!ShouldInlineSimd()) { |
2357 return false; | 2350 return false; |
2358 } | 2351 } |
2359 AddCheckClass(call->ArgumentAt(0), | 2352 AddCheckClass(call->ArgumentAt(0), |
2360 ICData::ZoneHandle( | 2353 ICData::ZoneHandle( |
2361 I, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | 2354 I, call->ic_data()->AsUnaryClassChecksForArgNr(0)), |
2362 call->deopt_id(), | 2355 call->deopt_id(), |
2363 call->env(), | 2356 call->env(), |
(...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2704 | 2697 |
2705 cursor = flow_graph()->AppendTo(cursor, | 2698 cursor = flow_graph()->AppendTo(cursor, |
2706 new(I) CheckSmiInstr( | 2699 new(I) CheckSmiInstr( |
2707 new(I) Value(index), | 2700 new(I) Value(index), |
2708 call->deopt_id(), | 2701 call->deopt_id(), |
2709 call->token_pos()), | 2702 call->token_pos()), |
2710 call->env(), | 2703 call->env(), |
2711 FlowGraph::kEffect); | 2704 FlowGraph::kEffect); |
2712 | 2705 |
2713 // Load the length of the string. | 2706 // Load the length of the string. |
2714 LoadFieldInstr* length = BuildLoadStringLength(str); | 2707 // Treat length loads as mutable (i.e. affected by side effects) to avoid |
| 2708 // hoisting them since we can't hoist the preceding class-check. This |
| 2709 // is because of externalization of strings that affects their class-id. |
| 2710 LoadFieldInstr* length = new(I) LoadFieldInstr( |
| 2711 new(I) Value(str), |
| 2712 String::length_offset(), |
| 2713 Type::ZoneHandle(I, Type::SmiType()), |
| 2714 str->token_pos()); |
| 2715 length->set_result_cid(kSmiCid); |
| 2716 length->set_recognized_kind(MethodRecognizer::kStringBaseLength); |
| 2717 |
2715 cursor = flow_graph()->AppendTo(cursor, length, NULL, FlowGraph::kValue); | 2718 cursor = flow_graph()->AppendTo(cursor, length, NULL, FlowGraph::kValue); |
2716 // Bounds check. | 2719 // Bounds check. |
2717 cursor = flow_graph()->AppendTo(cursor, | 2720 cursor = flow_graph()->AppendTo(cursor, |
2718 new(I) CheckArrayBoundInstr( | 2721 new(I) CheckArrayBoundInstr( |
2719 new(I) Value(length), | 2722 new(I) Value(length), |
2720 new(I) Value(index), | 2723 new(I) Value(index), |
2721 call->deopt_id()), | 2724 call->deopt_id()), |
2722 call->env(), | 2725 call->env(), |
2723 FlowGraph::kEffect); | 2726 FlowGraph::kEffect); |
2724 | 2727 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2783 StringFromCharCodeInstr* char_at = new(I) StringFromCharCodeInstr( | 2786 StringFromCharCodeInstr* char_at = new(I) StringFromCharCodeInstr( |
2784 new(I) Value(*last), cid); | 2787 new(I) Value(*last), cid); |
2785 | 2788 |
2786 flow_graph()->AppendTo(*last, char_at, NULL, FlowGraph::kValue); | 2789 flow_graph()->AppendTo(*last, char_at, NULL, FlowGraph::kValue); |
2787 *last = char_at; | 2790 *last = char_at; |
2788 | 2791 |
2789 return true; | 2792 return true; |
2790 } | 2793 } |
2791 | 2794 |
2792 | 2795 |
| 2796 bool FlowGraphOptimizer::InlineDoubleOp( |
| 2797 Token::Kind op_kind, |
| 2798 Instruction* call, |
| 2799 TargetEntryInstr** entry, |
| 2800 Definition** last) { |
| 2801 Definition* left = call->ArgumentAt(0); |
| 2802 Definition* right = call->ArgumentAt(1); |
| 2803 |
| 2804 *entry = new(I) TargetEntryInstr(flow_graph()->allocate_block_id(), |
| 2805 call->GetBlock()->try_index()); |
| 2806 (*entry)->InheritDeoptTarget(I, call); |
| 2807 // Arguments are checked. No need for class check. |
| 2808 BinaryDoubleOpInstr* double_bin_op = |
| 2809 new(I) BinaryDoubleOpInstr(op_kind, |
| 2810 new(I) Value(left), |
| 2811 new(I) Value(right), |
| 2812 call->deopt_id(), call->token_pos()); |
| 2813 flow_graph()->AppendTo(*entry, double_bin_op, call->env(), FlowGraph::kValue); |
| 2814 *last = double_bin_op; |
| 2815 |
| 2816 return true; |
| 2817 } |
| 2818 |
| 2819 |
2793 void FlowGraphOptimizer::ReplaceWithMathCFunction( | 2820 void FlowGraphOptimizer::ReplaceWithMathCFunction( |
2794 InstanceCallInstr* call, | 2821 InstanceCallInstr* call, |
2795 MethodRecognizer::Kind recognized_kind) { | 2822 MethodRecognizer::Kind recognized_kind) { |
2796 AddReceiverCheck(call); | 2823 AddReceiverCheck(call); |
2797 ZoneGrowableArray<Value*>* args = | 2824 ZoneGrowableArray<Value*>* args = |
2798 new(I) ZoneGrowableArray<Value*>(call->ArgumentCount()); | 2825 new(I) ZoneGrowableArray<Value*>(call->ArgumentCount()); |
2799 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { | 2826 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { |
2800 args->Add(new(I) Value(call->ArgumentAt(i))); | 2827 args->Add(new(I) Value(call->ArgumentAt(i))); |
2801 } | 2828 } |
2802 InvokeMathCFunctionInstr* invoke = | 2829 InvokeMathCFunctionInstr* invoke = |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2953 if (!TargetCPUFeatures::double_truncate_round_supported()) { | 2980 if (!TargetCPUFeatures::double_truncate_round_supported()) { |
2954 ReplaceWithMathCFunction(call, recognized_kind); | 2981 ReplaceWithMathCFunction(call, recognized_kind); |
2955 } else { | 2982 } else { |
2956 AddReceiverCheck(call); | 2983 AddReceiverCheck(call); |
2957 DoubleToDoubleInstr* d2d_instr = | 2984 DoubleToDoubleInstr* d2d_instr = |
2958 new(I) DoubleToDoubleInstr(new(I) Value(call->ArgumentAt(0)), | 2985 new(I) DoubleToDoubleInstr(new(I) Value(call->ArgumentAt(0)), |
2959 recognized_kind, call->deopt_id()); | 2986 recognized_kind, call->deopt_id()); |
2960 ReplaceCall(call, d2d_instr); | 2987 ReplaceCall(call, d2d_instr); |
2961 } | 2988 } |
2962 return true; | 2989 return true; |
| 2990 case MethodRecognizer::kDoubleAdd: |
| 2991 case MethodRecognizer::kDoubleSub: |
| 2992 case MethodRecognizer::kDoubleMul: |
| 2993 case MethodRecognizer::kDoubleDiv: |
| 2994 return TryReplaceInstanceCallWithInline(call); |
2963 default: | 2995 default: |
2964 // Unsupported method. | 2996 // Unsupported method. |
2965 return false; | 2997 return false; |
2966 } | 2998 } |
2967 } | 2999 } |
2968 | 3000 |
2969 if (IsSupportedByteArrayViewCid(class_ids[0]) && | 3001 if (IsSupportedByteArrayViewCid(class_ids[0]) && |
2970 (ic_data.NumberOfChecks() == 1)) { | 3002 (ic_data.NumberOfChecks() == 1)) { |
2971 // For elements that may not fit into a smi on all platforms, check if | 3003 // For elements that may not fit into a smi on all platforms, check if |
2972 // elements fit into a smi or the platform supports unboxed mints. | 3004 // elements fit into a smi or the platform supports unboxed mints. |
(...skipping 1362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4335 call->deopt_id(), | 4367 call->deopt_id(), |
4336 recognized_kind, | 4368 recognized_kind, |
4337 call->token_pos()); | 4369 call->token_pos()); |
4338 ReplaceCall(call, invoke); | 4370 ReplaceCall(call, invoke); |
4339 } else if (recognized_kind == MethodRecognizer::kObjectArrayConstructor) { | 4371 } else if (recognized_kind == MethodRecognizer::kObjectArrayConstructor) { |
4340 Value* type = new(I) Value(call->ArgumentAt(0)); | 4372 Value* type = new(I) Value(call->ArgumentAt(0)); |
4341 Value* num_elements = new(I) Value(call->ArgumentAt(1)); | 4373 Value* num_elements = new(I) Value(call->ArgumentAt(1)); |
4342 CreateArrayInstr* create_array = | 4374 CreateArrayInstr* create_array = |
4343 new(I) CreateArrayInstr(call->token_pos(), type, num_elements); | 4375 new(I) CreateArrayInstr(call->token_pos(), type, num_elements); |
4344 ReplaceCall(call, create_array); | 4376 ReplaceCall(call, create_array); |
| 4377 } else if (recognized_kind == MethodRecognizer::kDoubleFromInteger) { |
| 4378 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) { |
| 4379 const ICData& ic_data = *call->ic_data(); |
| 4380 if (CanUnboxDouble() && ArgIsAlways(kSmiCid, ic_data, 0)) { |
| 4381 Definition* arg = call->ArgumentAt(0); |
| 4382 InsertBefore(call, |
| 4383 new(I) CheckSmiInstr( |
| 4384 new(I) Value(arg), |
| 4385 call->deopt_id(), |
| 4386 call->token_pos()), |
| 4387 call->env(), |
| 4388 FlowGraph::kEffect); |
| 4389 ReplaceCall(call, |
| 4390 new(I) SmiToDoubleInstr(new(I) Value(arg), |
| 4391 call->token_pos())); |
| 4392 } |
| 4393 } |
4345 } else if (call->function().IsFactory()) { | 4394 } else if (call->function().IsFactory()) { |
4346 const Class& function_class = | 4395 const Class& function_class = |
4347 Class::Handle(I, call->function().Owner()); | 4396 Class::Handle(I, call->function().Owner()); |
4348 if ((function_class.library() == Library::CoreLibrary()) || | 4397 if ((function_class.library() == Library::CoreLibrary()) || |
4349 (function_class.library() == Library::TypedDataLibrary())) { | 4398 (function_class.library() == Library::TypedDataLibrary())) { |
4350 intptr_t cid = FactoryRecognizer::ResultCid(call->function()); | 4399 intptr_t cid = FactoryRecognizer::ResultCid(call->function()); |
4351 switch (cid) { | 4400 switch (cid) { |
4352 case kArrayCid: { | 4401 case kArrayCid: { |
4353 Value* type = new(I) Value(call->ArgumentAt(0)); | 4402 Value* type = new(I) Value(call->ArgumentAt(0)); |
4354 Value* num_elements = new(I) Value(call->ArgumentAt(1)); | 4403 Value* num_elements = new(I) Value(call->ArgumentAt(1)); |
(...skipping 5192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9547 | 9596 |
9548 // Insert materializations at environment uses. | 9597 // Insert materializations at environment uses. |
9549 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { | 9598 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { |
9550 CreateMaterializationAt( | 9599 CreateMaterializationAt( |
9551 exits_collector_.exits()[i], alloc, alloc->cls(), *slots); | 9600 exits_collector_.exits()[i], alloc, alloc->cls(), *slots); |
9552 } | 9601 } |
9553 } | 9602 } |
9554 | 9603 |
9555 | 9604 |
9556 } // namespace dart | 9605 } // namespace dart |
OLD | NEW |