| 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 |