| 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/globals.h" // Needed here to get TARGET_ARCH_MIPS. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. |
| 6 #if defined(TARGET_ARCH_MIPS) | 6 #if defined(TARGET_ARCH_MIPS) |
| 7 | 7 |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 | 9 |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| (...skipping 2611 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2622 } | 2622 } |
| 2623 if (compiler->ForceSlowPathForStackOverflow()) { | 2623 if (compiler->ForceSlowPathForStackOverflow()) { |
| 2624 __ b(slow_path->entry_label()); | 2624 __ b(slow_path->entry_label()); |
| 2625 } | 2625 } |
| 2626 __ Bind(slow_path->exit_label()); | 2626 __ Bind(slow_path->exit_label()); |
| 2627 } | 2627 } |
| 2628 | 2628 |
| 2629 | 2629 |
| 2630 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, | 2630 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, |
| 2631 BinarySmiOpInstr* shift_left) { | 2631 BinarySmiOpInstr* shift_left) { |
| 2632 const bool is_truncating = shift_left->IsTruncating(); | |
| 2633 const LocationSummary& locs = *shift_left->locs(); | 2632 const LocationSummary& locs = *shift_left->locs(); |
| 2634 Register left = locs.in(0).reg(); | 2633 Register left = locs.in(0).reg(); |
| 2635 Register result = locs.out(0).reg(); | 2634 Register result = locs.out(0).reg(); |
| 2636 Label* deopt = shift_left->CanDeoptimize() ? | 2635 Label* deopt = shift_left->CanDeoptimize() ? |
| 2637 compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp) | 2636 compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp) |
| 2638 : NULL; | 2637 : NULL; |
| 2639 | 2638 |
| 2640 __ TraceSimMsg("EmitSmiShiftLeft"); | 2639 __ TraceSimMsg("EmitSmiShiftLeft"); |
| 2641 | 2640 |
| 2642 if (locs.in(1).IsConstant()) { | 2641 if (locs.in(1).IsConstant()) { |
| 2643 const Object& constant = locs.in(1).constant(); | 2642 const Object& constant = locs.in(1).constant(); |
| 2644 ASSERT(constant.IsSmi()); | 2643 ASSERT(constant.IsSmi()); |
| 2645 // Immediate shift operation takes 5 bits for the count. | 2644 // Immediate shift operation takes 5 bits for the count. |
| 2646 const intptr_t kCountLimit = 0x1F; | 2645 const intptr_t kCountLimit = 0x1F; |
| 2647 const intptr_t value = Smi::Cast(constant).Value(); | 2646 const intptr_t value = Smi::Cast(constant).Value(); |
| 2648 if (value == 0) { | 2647 ASSERT((0 < value) && (value < kCountLimit)); |
| 2649 if (result != left) { | 2648 if (shift_left->can_overflow()) { |
| 2650 __ mov(result, left); | 2649 // Check for overflow (preserve left). |
| 2651 } | 2650 __ sll(TMP, left, value); |
| 2652 } else if ((value < 0) || (value >= kCountLimit)) { | 2651 __ sra(CMPRES1, TMP, value); |
| 2653 // This condition may not be known earlier in some cases because | 2652 __ bne(CMPRES1, left, deopt); // Overflow. |
| 2654 // of constant propagation, inlining, etc. | |
| 2655 if ((value >= kCountLimit) && is_truncating) { | |
| 2656 __ mov(result, ZR); | |
| 2657 } else { | |
| 2658 // Result is Mint or exception. | |
| 2659 __ b(deopt); | |
| 2660 } | |
| 2661 } else { | |
| 2662 if (!is_truncating) { | |
| 2663 // Check for overflow (preserve left). | |
| 2664 __ sll(TMP, left, value); | |
| 2665 __ sra(CMPRES1, TMP, value); | |
| 2666 __ bne(CMPRES1, left, deopt); // Overflow. | |
| 2667 } | |
| 2668 // Shift for result now we know there is no overflow. | |
| 2669 __ sll(result, left, value); | |
| 2670 } | 2653 } |
| 2654 // Shift for result now we know there is no overflow. |
| 2655 __ sll(result, left, value); |
| 2671 return; | 2656 return; |
| 2672 } | 2657 } |
| 2673 | 2658 |
| 2674 // Right (locs.in(1)) is not constant. | 2659 // Right (locs.in(1)) is not constant. |
| 2675 Register right = locs.in(1).reg(); | 2660 Register right = locs.in(1).reg(); |
| 2676 Range* right_range = shift_left->right()->definition()->range(); | 2661 Range* right_range = shift_left->right()->definition()->range(); |
| 2677 if (shift_left->left()->BindsToConstant() && !is_truncating) { | 2662 if (shift_left->left()->BindsToConstant() && shift_left->can_overflow()) { |
| 2678 // TODO(srdjan): Implement code below for is_truncating(). | 2663 // TODO(srdjan): Implement code below for is_truncating(). |
| 2679 // If left is constant, we know the maximal allowed size for right. | 2664 // If left is constant, we know the maximal allowed size for right. |
| 2680 const Object& obj = shift_left->left()->BoundConstant(); | 2665 const Object& obj = shift_left->left()->BoundConstant(); |
| 2681 if (obj.IsSmi()) { | 2666 if (obj.IsSmi()) { |
| 2682 const intptr_t left_int = Smi::Cast(obj).Value(); | 2667 const intptr_t left_int = Smi::Cast(obj).Value(); |
| 2683 if (left_int == 0) { | 2668 if (left_int == 0) { |
| 2684 __ bltz(right, deopt); | 2669 __ bltz(right, deopt); |
| 2685 __ mov(result, ZR); | 2670 __ mov(result, ZR); |
| 2686 return; | 2671 return; |
| 2687 } | 2672 } |
| 2688 const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int); | 2673 const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int); |
| 2689 const bool right_needs_check = | 2674 const bool right_needs_check = |
| 2690 !RangeUtils::IsWithin(right_range, 0, max_right - 1); | 2675 !RangeUtils::IsWithin(right_range, 0, max_right - 1); |
| 2691 if (right_needs_check) { | 2676 if (right_needs_check) { |
| 2692 __ BranchUnsignedGreaterEqual( | 2677 __ BranchUnsignedGreaterEqual( |
| 2693 right, reinterpret_cast<int32_t>(Smi::New(max_right)), deopt); | 2678 right, reinterpret_cast<int32_t>(Smi::New(max_right)), deopt); |
| 2694 } | 2679 } |
| 2695 __ SmiUntag(TMP, right); | 2680 __ SmiUntag(TMP, right); |
| 2696 __ sllv(result, left, TMP); | 2681 __ sllv(result, left, TMP); |
| 2697 } | 2682 } |
| 2698 return; | 2683 return; |
| 2699 } | 2684 } |
| 2700 | 2685 |
| 2701 const bool right_needs_check = | 2686 const bool right_needs_check = |
| 2702 !RangeUtils::IsWithin(right_range, 0, (Smi::kBits - 1)); | 2687 !RangeUtils::IsWithin(right_range, 0, (Smi::kBits - 1)); |
| 2703 if (is_truncating) { | 2688 if (!shift_left->can_overflow()) { |
| 2704 if (right_needs_check) { | 2689 if (right_needs_check) { |
| 2705 const bool right_may_be_negative = | 2690 const bool right_may_be_negative = |
| 2706 (right_range == NULL) || !right_range->IsPositive(); | 2691 (right_range == NULL) || !right_range->IsPositive(); |
| 2707 if (right_may_be_negative) { | 2692 if (right_may_be_negative) { |
| 2708 ASSERT(shift_left->CanDeoptimize()); | 2693 ASSERT(shift_left->CanDeoptimize()); |
| 2709 __ bltz(right, deopt); | 2694 __ bltz(right, deopt); |
| 2710 } | 2695 } |
| 2711 Label done, is_not_zero; | 2696 Label done, is_not_zero; |
| 2712 | 2697 |
| 2713 __ sltiu(CMPRES1, | 2698 __ sltiu(CMPRES1, |
| (...skipping 27 matching lines...) Expand all Loading... |
| 2741 } | 2726 } |
| 2742 | 2727 |
| 2743 | 2728 |
| 2744 LocationSummary* BinarySmiOpInstr::MakeLocationSummary(Isolate* isolate, | 2729 LocationSummary* BinarySmiOpInstr::MakeLocationSummary(Isolate* isolate, |
| 2745 bool opt) const { | 2730 bool opt) const { |
| 2746 const intptr_t kNumInputs = 2; | 2731 const intptr_t kNumInputs = 2; |
| 2747 const intptr_t kNumTemps = | 2732 const intptr_t kNumTemps = |
| 2748 ((op_kind() == Token::kADD) || | 2733 ((op_kind() == Token::kADD) || |
| 2749 (op_kind() == Token::kMOD) || | 2734 (op_kind() == Token::kMOD) || |
| 2750 (op_kind() == Token::kTRUNCDIV) || | 2735 (op_kind() == Token::kTRUNCDIV) || |
| 2751 (((op_kind() == Token::kSHL) && !IsTruncating()) || | 2736 (((op_kind() == Token::kSHL) && can_overflow()) || |
| 2752 (op_kind() == Token::kSHR))) ? 1 : 0; | 2737 (op_kind() == Token::kSHR))) ? 1 : 0; |
| 2753 LocationSummary* summary = new(isolate) LocationSummary( | 2738 LocationSummary* summary = new(isolate) LocationSummary( |
| 2754 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2739 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2755 if (op_kind() == Token::kTRUNCDIV) { | 2740 if (op_kind() == Token::kTRUNCDIV) { |
| 2756 summary->set_in(0, Location::RequiresRegister()); | 2741 summary->set_in(0, Location::RequiresRegister()); |
| 2757 if (RightIsPowerOfTwoConstant()) { | 2742 if (RightIsPowerOfTwoConstant()) { |
| 2758 ConstantInstr* right_constant = right()->definition()->AsConstant(); | 2743 ConstantInstr* right_constant = right()->definition()->AsConstant(); |
| 2759 summary->set_in(1, Location::Constant(right_constant)); | 2744 summary->set_in(1, Location::Constant(right_constant)); |
| 2760 } else { | 2745 } else { |
| 2761 summary->set_in(1, Location::RequiresRegister()); | 2746 summary->set_in(1, Location::RequiresRegister()); |
| 2762 } | 2747 } |
| 2763 summary->set_temp(0, Location::RequiresRegister()); | 2748 summary->set_temp(0, Location::RequiresRegister()); |
| 2764 summary->set_out(0, Location::RequiresRegister()); | 2749 summary->set_out(0, Location::RequiresRegister()); |
| 2765 return summary; | 2750 return summary; |
| 2766 } | 2751 } |
| 2767 if (op_kind() == Token::kMOD) { | 2752 if (op_kind() == Token::kMOD) { |
| 2768 summary->set_in(0, Location::RequiresRegister()); | 2753 summary->set_in(0, Location::RequiresRegister()); |
| 2769 summary->set_in(1, Location::RequiresRegister()); | 2754 summary->set_in(1, Location::RequiresRegister()); |
| 2770 summary->set_temp(0, Location::RequiresRegister()); | 2755 summary->set_temp(0, Location::RequiresRegister()); |
| 2771 summary->set_out(0, Location::RequiresRegister()); | 2756 summary->set_out(0, Location::RequiresRegister()); |
| 2772 return summary; | 2757 return summary; |
| 2773 } | 2758 } |
| 2774 summary->set_in(0, Location::RequiresRegister()); | 2759 summary->set_in(0, Location::RequiresRegister()); |
| 2775 summary->set_in(1, Location::RegisterOrSmiConstant(right())); | 2760 summary->set_in(1, Location::RegisterOrSmiConstant(right())); |
| 2776 if (((op_kind() == Token::kSHL) && !IsTruncating()) || | 2761 if (((op_kind() == Token::kSHL) && can_overflow()) || |
| 2777 (op_kind() == Token::kSHR)) { | 2762 (op_kind() == Token::kSHR)) { |
| 2778 summary->set_temp(0, Location::RequiresRegister()); | 2763 summary->set_temp(0, Location::RequiresRegister()); |
| 2779 } else if (op_kind() == Token::kADD) { | 2764 } else if (op_kind() == Token::kADD) { |
| 2780 // Need an extra temp for the overflow detection code. | 2765 // Need an extra temp for the overflow detection code. |
| 2781 summary->set_temp(0, Location::RequiresRegister()); | 2766 summary->set_temp(0, Location::RequiresRegister()); |
| 2782 } | 2767 } |
| 2783 // We make use of 3-operand instructions by not requiring result register | 2768 // We make use of 3-operand instructions by not requiring result register |
| 2784 // to be identical to first input register as on Intel. | 2769 // to be identical to first input register as on Intel. |
| 2785 summary->set_out(0, Location::RequiresRegister()); | 2770 summary->set_out(0, Location::RequiresRegister()); |
| 2786 return summary; | 2771 return summary; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2822 __ AddImmediate(result, left, -imm); | 2807 __ AddImmediate(result, left, -imm); |
| 2823 } else { | 2808 } else { |
| 2824 __ SubImmediateDetectOverflow(result, left, imm, CMPRES1); | 2809 __ SubImmediateDetectOverflow(result, left, imm, CMPRES1); |
| 2825 __ bltz(CMPRES1, deopt); | 2810 __ bltz(CMPRES1, deopt); |
| 2826 } | 2811 } |
| 2827 break; | 2812 break; |
| 2828 } | 2813 } |
| 2829 case Token::kMUL: { | 2814 case Token::kMUL: { |
| 2830 // Keep left value tagged and untag right value. | 2815 // Keep left value tagged and untag right value. |
| 2831 const intptr_t value = Smi::Cast(constant).Value(); | 2816 const intptr_t value = Smi::Cast(constant).Value(); |
| 2832 if (deopt == NULL) { | 2817 __ LoadImmediate(TMP, value); |
| 2833 if (value == 2) { | 2818 __ mult(left, TMP); |
| 2834 __ sll(result, left, 1); | 2819 __ mflo(result); |
| 2835 } else { | 2820 if (deopt != NULL) { |
| 2836 __ LoadImmediate(TMP, value); | 2821 __ mfhi(CMPRES2); |
| 2837 __ mult(left, TMP); | |
| 2838 __ mflo(result); | |
| 2839 } | |
| 2840 } else { | |
| 2841 if (value == 2) { | |
| 2842 __ sra(CMPRES2, left, 31); // CMPRES2 = sign of left. | |
| 2843 __ sll(result, left, 1); | |
| 2844 } else { | |
| 2845 __ LoadImmediate(TMP, value); | |
| 2846 __ mult(left, TMP); | |
| 2847 __ mflo(result); | |
| 2848 __ mfhi(CMPRES2); | |
| 2849 } | |
| 2850 __ sra(CMPRES1, result, 31); | 2822 __ sra(CMPRES1, result, 31); |
| 2851 __ bne(CMPRES1, CMPRES2, deopt); | 2823 __ bne(CMPRES1, CMPRES2, deopt); |
| 2852 } | 2824 } |
| 2853 break; | 2825 break; |
| 2854 } | 2826 } |
| 2855 case Token::kTRUNCDIV: { | 2827 case Token::kTRUNCDIV: { |
| 2856 const intptr_t value = Smi::Cast(constant).Value(); | 2828 const intptr_t value = Smi::Cast(constant).Value(); |
| 2857 if (value == 1) { | |
| 2858 if (result != left) { | |
| 2859 __ mov(result, left); | |
| 2860 } | |
| 2861 break; | |
| 2862 } else if (value == -1) { | |
| 2863 // Check the corner case of dividing the 'MIN_SMI' with -1, in which | |
| 2864 // case we cannot negate the result. | |
| 2865 __ BranchEqual(left, 0x80000000, deopt); | |
| 2866 __ subu(result, ZR, left); | |
| 2867 break; | |
| 2868 } | |
| 2869 ASSERT(Utils::IsPowerOfTwo(Utils::Abs(value))); | 2829 ASSERT(Utils::IsPowerOfTwo(Utils::Abs(value))); |
| 2870 const intptr_t shift_count = | 2830 const intptr_t shift_count = |
| 2871 Utils::ShiftForPowerOfTwo(Utils::Abs(value)) + kSmiTagSize; | 2831 Utils::ShiftForPowerOfTwo(Utils::Abs(value)) + kSmiTagSize; |
| 2872 ASSERT(kSmiTagSize == 1); | 2832 ASSERT(kSmiTagSize == 1); |
| 2873 __ sra(TMP, left, 31); | 2833 __ sra(TMP, left, 31); |
| 2874 ASSERT(shift_count > 1); // 1, -1 case handled above. | 2834 ASSERT(shift_count > 1); // 1, -1 case handled above. |
| 2875 Register temp = locs()->temp(0).reg(); | 2835 Register temp = locs()->temp(0).reg(); |
| 2876 __ srl(TMP, TMP, 32 - shift_count); | 2836 __ srl(TMP, TMP, 32 - shift_count); |
| 2877 __ addu(temp, left, TMP); | 2837 __ addu(temp, left, TMP); |
| 2878 ASSERT(shift_count > 0); | 2838 ASSERT(shift_count > 0); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 2909 __ xori(result, left, Immediate(imm)); | 2869 __ xori(result, left, Immediate(imm)); |
| 2910 } else { | 2870 } else { |
| 2911 __ LoadImmediate(TMP, imm); | 2871 __ LoadImmediate(TMP, imm); |
| 2912 __ xor_(result, left, TMP); | 2872 __ xor_(result, left, TMP); |
| 2913 } | 2873 } |
| 2914 break; | 2874 break; |
| 2915 } | 2875 } |
| 2916 case Token::kSHR: { | 2876 case Token::kSHR: { |
| 2917 // sarl operation masks the count to 5 bits. | 2877 // sarl operation masks the count to 5 bits. |
| 2918 const intptr_t kCountLimit = 0x1F; | 2878 const intptr_t kCountLimit = 0x1F; |
| 2919 intptr_t value = Smi::Cast(constant).Value(); | 2879 const intptr_t value = Smi::Cast(constant).Value(); |
| 2920 | |
| 2921 __ TraceSimMsg("kSHR"); | 2880 __ TraceSimMsg("kSHR"); |
| 2922 | 2881 __ sra(result, left, Utils::Minimum(value + kSmiTagSize, kCountLimit)); |
| 2923 if (value == 0) { | |
| 2924 // TODO(vegorov): should be handled outside. | |
| 2925 if (result != left) { | |
| 2926 __ mov(result, left); | |
| 2927 } | |
| 2928 break; | |
| 2929 } else if (value < 0) { | |
| 2930 // TODO(vegorov): should be handled outside. | |
| 2931 __ b(deopt); | |
| 2932 break; | |
| 2933 } | |
| 2934 | |
| 2935 value = value + kSmiTagSize; | |
| 2936 if (value >= kCountLimit) { | |
| 2937 value = kCountLimit; | |
| 2938 } | |
| 2939 | |
| 2940 __ sra(result, left, value); | |
| 2941 __ SmiTag(result); | 2882 __ SmiTag(result); |
| 2942 break; | 2883 break; |
| 2943 } | 2884 } |
| 2944 | 2885 |
| 2945 default: | 2886 default: |
| 2946 UNREACHABLE(); | 2887 UNREACHABLE(); |
| 2947 break; | 2888 break; |
| 2948 } | 2889 } |
| 2949 return; | 2890 return; |
| 2950 } | 2891 } |
| (...skipping 2045 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4996 compiler->GenerateCall(token_pos(), &label, stub_kind_, locs()); | 4937 compiler->GenerateCall(token_pos(), &label, stub_kind_, locs()); |
| 4997 #if defined(DEBUG) | 4938 #if defined(DEBUG) |
| 4998 __ LoadImmediate(S4, kInvalidObjectPointer); | 4939 __ LoadImmediate(S4, kInvalidObjectPointer); |
| 4999 __ LoadImmediate(S5, kInvalidObjectPointer); | 4940 __ LoadImmediate(S5, kInvalidObjectPointer); |
| 5000 #endif | 4941 #endif |
| 5001 } | 4942 } |
| 5002 | 4943 |
| 5003 } // namespace dart | 4944 } // namespace dart |
| 5004 | 4945 |
| 5005 #endif // defined TARGET_ARCH_MIPS | 4946 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |