OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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/globals.h" // Needed here to get TARGET_ARCH_ARM64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. |
6 #if defined(TARGET_ARCH_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
7 | 7 |
8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
9 | 9 |
10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
(...skipping 2649 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2660 __ CompareImmediate(temp, threshold); | 2660 __ CompareImmediate(temp, threshold); |
2661 __ b(slow_path->osr_entry_label(), GE); | 2661 __ b(slow_path->osr_entry_label(), GE); |
2662 } | 2662 } |
2663 if (compiler->ForceSlowPathForStackOverflow()) { | 2663 if (compiler->ForceSlowPathForStackOverflow()) { |
2664 __ b(slow_path->entry_label()); | 2664 __ b(slow_path->entry_label()); |
2665 } | 2665 } |
2666 __ Bind(slow_path->exit_label()); | 2666 __ Bind(slow_path->exit_label()); |
2667 } | 2667 } |
2668 | 2668 |
2669 | 2669 |
2670 static void EmitJavascriptOverflowCheck(FlowGraphCompiler* compiler, | |
2671 Range* range, | |
2672 Label* overflow, | |
2673 Register result) { | |
2674 if (!RangeUtils::IsWithin(range, -0x20000000000000LL, 0x20000000000000LL)) { | |
2675 ASSERT(overflow != NULL); | |
2676 __ LoadImmediate(TMP, 0x20000000000000LL); | |
2677 __ add(TMP2, result, Operand(TMP)); | |
2678 __ cmp(TMP2, Operand(TMP, LSL, 1)); | |
2679 __ b(overflow, HI); | |
2680 } | |
2681 } | |
2682 | |
2683 | |
2684 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, | 2670 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, |
2685 BinarySmiOpInstr* shift_left) { | 2671 BinarySmiOpInstr* shift_left) { |
2686 const LocationSummary& locs = *shift_left->locs(); | 2672 const LocationSummary& locs = *shift_left->locs(); |
2687 const Register left = locs.in(0).reg(); | 2673 const Register left = locs.in(0).reg(); |
2688 const Register result = locs.out(0).reg(); | 2674 const Register result = locs.out(0).reg(); |
2689 Label* deopt = shift_left->CanDeoptimize() ? | 2675 Label* deopt = shift_left->CanDeoptimize() ? |
2690 compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp) | 2676 compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp) |
2691 : NULL; | 2677 : NULL; |
2692 if (locs.in(1).IsConstant()) { | 2678 if (locs.in(1).IsConstant()) { |
2693 const Object& constant = locs.in(1).constant(); | 2679 const Object& constant = locs.in(1).constant(); |
2694 ASSERT(constant.IsSmi()); | 2680 ASSERT(constant.IsSmi()); |
2695 // Immediate shift operation takes 6 bits for the count. | 2681 // Immediate shift operation takes 6 bits for the count. |
2696 const intptr_t kCountLimit = 0x3F; | 2682 const intptr_t kCountLimit = 0x3F; |
2697 const intptr_t value = Smi::Cast(constant).Value(); | 2683 const intptr_t value = Smi::Cast(constant).Value(); |
2698 ASSERT((0 < value) && (value < kCountLimit)); | 2684 ASSERT((0 < value) && (value < kCountLimit)); |
2699 if (shift_left->can_overflow()) { | 2685 if (shift_left->can_overflow()) { |
2700 // Check for overflow (preserve left). | 2686 // Check for overflow (preserve left). |
2701 __ LslImmediate(TMP, left, value); | 2687 __ LslImmediate(TMP, left, value); |
2702 __ cmp(left, Operand(TMP, ASR, value)); | 2688 __ cmp(left, Operand(TMP, ASR, value)); |
2703 __ b(deopt, NE); // Overflow. | 2689 __ b(deopt, NE); // Overflow. |
2704 } | 2690 } |
2705 // Shift for result now we know there is no overflow. | 2691 // Shift for result now we know there is no overflow. |
2706 __ LslImmediate(result, left, value); | 2692 __ LslImmediate(result, left, value); |
2707 if (FLAG_throw_on_javascript_int_overflow) { | |
2708 EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result); | |
2709 } | |
2710 return; | 2693 return; |
2711 } | 2694 } |
2712 | 2695 |
2713 // Right (locs.in(1)) is not constant. | 2696 // Right (locs.in(1)) is not constant. |
2714 const Register right = locs.in(1).reg(); | 2697 const Register right = locs.in(1).reg(); |
2715 Range* right_range = shift_left->right()->definition()->range(); | 2698 Range* right_range = shift_left->right()->definition()->range(); |
2716 if (shift_left->left()->BindsToConstant() && shift_left->can_overflow()) { | 2699 if (shift_left->left()->BindsToConstant() && shift_left->can_overflow()) { |
2717 // TODO(srdjan): Implement code below for is_truncating(). | 2700 // TODO(srdjan): Implement code below for is_truncating(). |
2718 // If left is constant, we know the maximal allowed size for right. | 2701 // If left is constant, we know the maximal allowed size for right. |
2719 const Object& obj = shift_left->left()->BoundConstant(); | 2702 const Object& obj = shift_left->left()->BoundConstant(); |
2720 if (obj.IsSmi()) { | 2703 if (obj.IsSmi()) { |
2721 const intptr_t left_int = Smi::Cast(obj).Value(); | 2704 const intptr_t left_int = Smi::Cast(obj).Value(); |
2722 if (left_int == 0) { | 2705 if (left_int == 0) { |
2723 __ CompareRegisters(right, ZR); | 2706 __ CompareRegisters(right, ZR); |
2724 __ b(deopt, MI); | 2707 __ b(deopt, MI); |
2725 __ mov(result, ZR); | 2708 __ mov(result, ZR); |
2726 return; | 2709 return; |
2727 } | 2710 } |
2728 const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int); | 2711 const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int); |
2729 const bool right_needs_check = | 2712 const bool right_needs_check = |
2730 !RangeUtils::IsWithin(right_range, 0, max_right - 1); | 2713 !RangeUtils::IsWithin(right_range, 0, max_right - 1); |
2731 if (right_needs_check) { | 2714 if (right_needs_check) { |
2732 __ CompareImmediate(right, | 2715 __ CompareImmediate(right, |
2733 reinterpret_cast<int64_t>(Smi::New(max_right))); | 2716 reinterpret_cast<int64_t>(Smi::New(max_right))); |
2734 __ b(deopt, CS); | 2717 __ b(deopt, CS); |
2735 } | 2718 } |
2736 __ SmiUntag(TMP, right); | 2719 __ SmiUntag(TMP, right); |
2737 __ lslv(result, left, TMP); | 2720 __ lslv(result, left, TMP); |
2738 } | 2721 } |
2739 if (FLAG_throw_on_javascript_int_overflow) { | |
2740 EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result); | |
2741 } | |
2742 return; | 2722 return; |
2743 } | 2723 } |
2744 | 2724 |
2745 const bool right_needs_check = | 2725 const bool right_needs_check = |
2746 !RangeUtils::IsWithin(right_range, 0, (Smi::kBits - 1)); | 2726 !RangeUtils::IsWithin(right_range, 0, (Smi::kBits - 1)); |
2747 if (!shift_left->can_overflow()) { | 2727 if (!shift_left->can_overflow()) { |
2748 if (right_needs_check) { | 2728 if (right_needs_check) { |
2749 const bool right_may_be_negative = | 2729 const bool right_may_be_negative = |
2750 (right_range == NULL) || !right_range->IsPositive(); | 2730 (right_range == NULL) || !right_range->IsPositive(); |
2751 if (right_may_be_negative) { | 2731 if (right_may_be_negative) { |
(...skipping 24 matching lines...) Expand all Loading... |
2776 __ SmiUntag(TMP, right); | 2756 __ SmiUntag(TMP, right); |
2777 // Overflow test (preserve left, right, and TMP); | 2757 // Overflow test (preserve left, right, and TMP); |
2778 const Register temp = locs.temp(0).reg(); | 2758 const Register temp = locs.temp(0).reg(); |
2779 __ lslv(temp, left, TMP); | 2759 __ lslv(temp, left, TMP); |
2780 __ asrv(TMP2, temp, TMP); | 2760 __ asrv(TMP2, temp, TMP); |
2781 __ CompareRegisters(left, TMP2); | 2761 __ CompareRegisters(left, TMP2); |
2782 __ b(deopt, NE); // Overflow. | 2762 __ b(deopt, NE); // Overflow. |
2783 // Shift for result now we know there is no overflow. | 2763 // Shift for result now we know there is no overflow. |
2784 __ lslv(result, left, TMP); | 2764 __ lslv(result, left, TMP); |
2785 } | 2765 } |
2786 if (FLAG_throw_on_javascript_int_overflow) { | |
2787 EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result); | |
2788 } | |
2789 } | 2766 } |
2790 | 2767 |
2791 | 2768 |
2792 LocationSummary* BinarySmiOpInstr::MakeLocationSummary(Zone* zone, | 2769 LocationSummary* BinarySmiOpInstr::MakeLocationSummary(Zone* zone, |
2793 bool opt) const { | 2770 bool opt) const { |
2794 const intptr_t kNumInputs = 2; | 2771 const intptr_t kNumInputs = 2; |
2795 const intptr_t kNumTemps = | 2772 const intptr_t kNumTemps = |
2796 (((op_kind() == Token::kSHL) && can_overflow()) || | 2773 (((op_kind() == Token::kSHL) && can_overflow()) || |
2797 (op_kind() == Token::kSHR)) ? 1 : 0; | 2774 (op_kind() == Token::kSHR)) ? 1 : 0; |
2798 LocationSummary* summary = new(zone) LocationSummary( | 2775 LocationSummary* summary = new(zone) LocationSummary( |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2914 intptr_t value = Smi::Cast(constant).Value(); | 2891 intptr_t value = Smi::Cast(constant).Value(); |
2915 __ AsrImmediate( | 2892 __ AsrImmediate( |
2916 result, left, Utils::Minimum(value + kSmiTagSize, kCountLimit)); | 2893 result, left, Utils::Minimum(value + kSmiTagSize, kCountLimit)); |
2917 __ SmiTag(result); | 2894 __ SmiTag(result); |
2918 break; | 2895 break; |
2919 } | 2896 } |
2920 default: | 2897 default: |
2921 UNREACHABLE(); | 2898 UNREACHABLE(); |
2922 break; | 2899 break; |
2923 } | 2900 } |
2924 if (FLAG_throw_on_javascript_int_overflow) { | |
2925 EmitJavascriptOverflowCheck(compiler, range(), deopt, result); | |
2926 } | |
2927 return; | 2901 return; |
2928 } | 2902 } |
2929 | 2903 |
2930 const Register right = locs()->in(1).reg(); | 2904 const Register right = locs()->in(1).reg(); |
2931 Range* right_range = this->right()->definition()->range(); | 2905 Range* right_range = this->right()->definition()->range(); |
2932 switch (op_kind()) { | 2906 switch (op_kind()) { |
2933 case Token::kADD: { | 2907 case Token::kADD: { |
2934 if (deopt == NULL) { | 2908 if (deopt == NULL) { |
2935 __ add(result, left, Operand(right)); | 2909 __ add(result, left, Operand(right)); |
2936 } else { | 2910 } else { |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3059 case Token::kAND: { | 3033 case Token::kAND: { |
3060 // Flow graph builder has dissected this operation to guarantee correct | 3034 // Flow graph builder has dissected this operation to guarantee correct |
3061 // behavior (short-circuit evaluation). | 3035 // behavior (short-circuit evaluation). |
3062 UNREACHABLE(); | 3036 UNREACHABLE(); |
3063 break; | 3037 break; |
3064 } | 3038 } |
3065 default: | 3039 default: |
3066 UNREACHABLE(); | 3040 UNREACHABLE(); |
3067 break; | 3041 break; |
3068 } | 3042 } |
3069 if (FLAG_throw_on_javascript_int_overflow) { | |
3070 EmitJavascriptOverflowCheck(compiler, range(), deopt, result); | |
3071 } | |
3072 } | 3043 } |
3073 | 3044 |
3074 | 3045 |
3075 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary(Zone* zone, | 3046 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary(Zone* zone, |
3076 bool opt) const { | 3047 bool opt) const { |
3077 intptr_t left_cid = left()->Type()->ToCid(); | 3048 intptr_t left_cid = left()->Type()->ToCid(); |
3078 intptr_t right_cid = right()->Type()->ToCid(); | 3049 intptr_t right_cid = right()->Type()->ToCid(); |
3079 ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid)); | 3050 ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid)); |
3080 const intptr_t kNumInputs = 2; | 3051 const intptr_t kNumInputs = 2; |
3081 const intptr_t kNumTemps = 0; | 3052 const intptr_t kNumTemps = 0; |
(...skipping 1438 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4520 | 4491 |
4521 | 4492 |
4522 void UnarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 4493 void UnarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
4523 const Register value = locs()->in(0).reg(); | 4494 const Register value = locs()->in(0).reg(); |
4524 const Register result = locs()->out(0).reg(); | 4495 const Register result = locs()->out(0).reg(); |
4525 switch (op_kind()) { | 4496 switch (op_kind()) { |
4526 case Token::kNEGATE: { | 4497 case Token::kNEGATE: { |
4527 Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnaryOp); | 4498 Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnaryOp); |
4528 __ subs(result, ZR, Operand(value)); | 4499 __ subs(result, ZR, Operand(value)); |
4529 __ b(deopt, VS); | 4500 __ b(deopt, VS); |
4530 if (FLAG_throw_on_javascript_int_overflow) { | |
4531 EmitJavascriptOverflowCheck(compiler, range(), deopt, value); | |
4532 } | |
4533 break; | 4501 break; |
4534 } | 4502 } |
4535 case Token::kBIT_NOT: | 4503 case Token::kBIT_NOT: |
4536 __ mvn(result, value); | 4504 __ mvn(result, value); |
4537 // Remove inverted smi-tag. | 4505 // Remove inverted smi-tag. |
4538 __ andi(result, result, Immediate(~kSmiTagMask)); | 4506 __ andi(result, result, Immediate(~kSmiTagMask)); |
4539 break; | 4507 break; |
4540 default: | 4508 default: |
4541 UNREACHABLE(); | 4509 UNREACHABLE(); |
4542 } | 4510 } |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4638 __ fcmpd(VTMP, VTMP); | 4606 __ fcmpd(VTMP, VTMP); |
4639 __ b(&do_call, VS); | 4607 __ b(&do_call, VS); |
4640 | 4608 |
4641 __ fcvtzds(result, VTMP); | 4609 __ fcvtzds(result, VTMP); |
4642 // Overflow is signaled with minint. | 4610 // Overflow is signaled with minint. |
4643 | 4611 |
4644 // Check for overflow and that it fits into Smi. | 4612 // Check for overflow and that it fits into Smi. |
4645 __ CompareImmediate(result, 0xC000000000000000); | 4613 __ CompareImmediate(result, 0xC000000000000000); |
4646 __ b(&do_call, MI); | 4614 __ b(&do_call, MI); |
4647 __ SmiTag(result); | 4615 __ SmiTag(result); |
4648 if (FLAG_throw_on_javascript_int_overflow) { | |
4649 EmitJavascriptOverflowCheck(compiler, range(), &do_call, result); | |
4650 } | |
4651 __ b(&done); | 4616 __ b(&done); |
4652 __ Bind(&do_call); | 4617 __ Bind(&do_call); |
4653 __ Push(value_obj); | 4618 __ Push(value_obj); |
4654 ASSERT(instance_call()->HasICData()); | 4619 ASSERT(instance_call()->HasICData()); |
4655 const ICData& ic_data = *instance_call()->ic_data(); | 4620 const ICData& ic_data = *instance_call()->ic_data(); |
4656 ASSERT((ic_data.NumberOfChecks() == 1)); | 4621 ASSERT((ic_data.NumberOfChecks() == 1)); |
4657 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); | 4622 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); |
4658 | 4623 |
4659 const intptr_t kNumberOfArguments = 1; | 4624 const intptr_t kNumberOfArguments = 1; |
4660 compiler->GenerateStaticCall(deopt_id(), | 4625 compiler->GenerateStaticCall(deopt_id(), |
(...skipping 27 matching lines...) Expand all Loading... |
4688 // on ARM64 because fcvtzds gives 0 for NaN. | 4653 // on ARM64 because fcvtzds gives 0 for NaN. |
4689 // TODO(zra): Check spec that this is true. | 4654 // TODO(zra): Check spec that this is true. |
4690 __ fcmpd(value, value); | 4655 __ fcmpd(value, value); |
4691 __ b(deopt, VS); | 4656 __ b(deopt, VS); |
4692 | 4657 |
4693 __ fcvtzds(result, value); | 4658 __ fcvtzds(result, value); |
4694 // Check for overflow and that it fits into Smi. | 4659 // Check for overflow and that it fits into Smi. |
4695 __ CompareImmediate(result, 0xC000000000000000); | 4660 __ CompareImmediate(result, 0xC000000000000000); |
4696 __ b(deopt, MI); | 4661 __ b(deopt, MI); |
4697 __ SmiTag(result); | 4662 __ SmiTag(result); |
4698 if (FLAG_throw_on_javascript_int_overflow) { | |
4699 EmitJavascriptOverflowCheck(compiler, range(), deopt, result); | |
4700 } | |
4701 } | 4663 } |
4702 | 4664 |
4703 | 4665 |
4704 LocationSummary* DoubleToDoubleInstr::MakeLocationSummary(Zone* zone, | 4666 LocationSummary* DoubleToDoubleInstr::MakeLocationSummary(Zone* zone, |
4705 bool opt) const { | 4667 bool opt) const { |
4706 UNIMPLEMENTED(); | 4668 UNIMPLEMENTED(); |
4707 return NULL; | 4669 return NULL; |
4708 } | 4670 } |
4709 | 4671 |
4710 | 4672 |
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5004 // } | 4966 // } |
5005 Label done; | 4967 Label done; |
5006 __ CompareRegisters(result_mod, ZR);; | 4968 __ CompareRegisters(result_mod, ZR);; |
5007 __ b(&done, GE); | 4969 __ b(&done, GE); |
5008 // Result is negative, adjust it. | 4970 // Result is negative, adjust it. |
5009 __ CompareRegisters(right, ZR); | 4971 __ CompareRegisters(right, ZR); |
5010 __ sub(TMP2, result_mod, Operand(right)); | 4972 __ sub(TMP2, result_mod, Operand(right)); |
5011 __ add(TMP, result_mod, Operand(right)); | 4973 __ add(TMP, result_mod, Operand(right)); |
5012 __ csel(result_mod, TMP, TMP2, GE); | 4974 __ csel(result_mod, TMP, TMP2, GE); |
5013 __ Bind(&done); | 4975 __ Bind(&done); |
5014 // FLAG_throw_on_javascript_int_overflow: not needed. | |
5015 // Note that the result of an integer division/modulo of two | |
5016 // in-range arguments, cannot create out-of-range result. | |
5017 return; | 4976 return; |
5018 } | 4977 } |
5019 if (kind() == MergedMathInstr::kSinCos) { | 4978 if (kind() == MergedMathInstr::kSinCos) { |
5020 UNIMPLEMENTED(); | 4979 UNIMPLEMENTED(); |
5021 } | 4980 } |
5022 UNIMPLEMENTED(); | 4981 UNIMPLEMENTED(); |
5023 } | 4982 } |
5024 | 4983 |
5025 | 4984 |
5026 LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary( | 4985 LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary( |
(...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5623 1, | 5582 1, |
5624 locs()); | 5583 locs()); |
5625 __ Drop(1); | 5584 __ Drop(1); |
5626 __ Pop(result); | 5585 __ Pop(result); |
5627 } | 5586 } |
5628 | 5587 |
5629 | 5588 |
5630 } // namespace dart | 5589 } // namespace dart |
5631 | 5590 |
5632 #endif // defined TARGET_ARCH_ARM64 | 5591 #endif // defined TARGET_ARCH_ARM64 |
OLD | NEW |