Chromium Code Reviews| 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_IA32. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
| 6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
| 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 2645 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2656 // TODO(turnidge): Implement stack overflow count in assembly to | 2656 // TODO(turnidge): Implement stack overflow count in assembly to |
| 2657 // make --stacktrace-every and --deoptimize-every faster. | 2657 // make --stacktrace-every and --deoptimize-every faster. |
| 2658 __ jmp(slow_path->entry_label()); | 2658 __ jmp(slow_path->entry_label()); |
| 2659 } | 2659 } |
| 2660 __ Bind(slow_path->exit_label()); | 2660 __ Bind(slow_path->exit_label()); |
| 2661 } | 2661 } |
| 2662 | 2662 |
| 2663 | 2663 |
| 2664 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, | 2664 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, |
| 2665 BinarySmiOpInstr* shift_left) { | 2665 BinarySmiOpInstr* shift_left) { |
| 2666 const bool is_truncating = shift_left->IsTruncating(); | |
| 2667 const LocationSummary& locs = *shift_left->locs(); | 2666 const LocationSummary& locs = *shift_left->locs(); |
| 2668 Register left = locs.in(0).reg(); | 2667 Register left = locs.in(0).reg(); |
| 2669 Register result = locs.out(0).reg(); | 2668 Register result = locs.out(0).reg(); |
| 2670 ASSERT(left == result); | 2669 ASSERT(left == result); |
| 2671 Label* deopt = shift_left->CanDeoptimize() ? | 2670 Label* deopt = shift_left->CanDeoptimize() ? |
| 2672 compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp) | 2671 compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp) |
| 2673 : NULL; | 2672 : NULL; |
| 2674 if (locs.in(1).IsConstant()) { | 2673 if (locs.in(1).IsConstant()) { |
| 2675 const Object& constant = locs.in(1).constant(); | 2674 const Object& constant = locs.in(1).constant(); |
| 2676 ASSERT(constant.IsSmi()); | 2675 ASSERT(constant.IsSmi()); |
| 2677 // shll operation masks the count to 5 bits. | 2676 // shll operation masks the count to 5 bits. |
| 2678 const intptr_t kCountLimit = 0x1F; | 2677 const intptr_t kCountLimit = 0x1F; |
| 2679 const intptr_t value = Smi::Cast(constant).Value(); | 2678 const intptr_t value = Smi::Cast(constant).Value(); |
| 2680 if (value == 0) { | 2679 ASSERT((0 < value) && (value < kCountLimit)); |
| 2681 // No code needed. | 2680 if (shift_left->can_overflow()) { |
| 2682 } else if ((value < 0) || (value >= kCountLimit)) { | 2681 // Check for overflow. |
| 2683 // This condition may not be known earlier in some cases because | 2682 Register temp = locs.temp(0).reg(); |
| 2684 // of constant propagation, inlining, etc. | 2683 __ movl(temp, left); |
| 2685 if ((value >= kCountLimit) && is_truncating) { | |
| 2686 __ xorl(result, result); | |
| 2687 } else { | |
| 2688 // Result is Mint or exception. | |
| 2689 __ jmp(deopt); | |
| 2690 } | |
| 2691 } else { | |
| 2692 if (!is_truncating) { | |
| 2693 // Check for overflow. | |
| 2694 Register temp = locs.temp(0).reg(); | |
| 2695 __ movl(temp, left); | |
| 2696 __ shll(left, Immediate(value)); | |
| 2697 __ sarl(left, Immediate(value)); | |
| 2698 __ cmpl(left, temp); | |
| 2699 __ j(NOT_EQUAL, deopt); // Overflow. | |
| 2700 } | |
| 2701 // Shift for result now we know there is no overflow. | |
| 2702 __ shll(left, Immediate(value)); | 2684 __ shll(left, Immediate(value)); |
| 2685 __ sarl(left, Immediate(value)); | |
| 2686 __ cmpl(left, temp); | |
| 2687 __ j(NOT_EQUAL, deopt); // Overflow. | |
| 2703 } | 2688 } |
| 2689 // Shift for result now we know there is no overflow. | |
| 2690 __ shll(left, Immediate(value)); | |
| 2704 return; | 2691 return; |
| 2705 } | 2692 } |
| 2706 | 2693 |
| 2707 // Right (locs.in(1)) is not constant. | 2694 // Right (locs.in(1)) is not constant. |
| 2708 Register right = locs.in(1).reg(); | 2695 Register right = locs.in(1).reg(); |
| 2709 Range* right_range = shift_left->right()->definition()->range(); | 2696 Range* right_range = shift_left->right()->definition()->range(); |
| 2710 if (shift_left->left()->BindsToConstant() && !is_truncating) { | 2697 if (shift_left->left()->BindsToConstant() && shift_left->can_overflow()) { |
| 2711 // TODO(srdjan): Implement code below for is_truncating(). | 2698 // TODO(srdjan): Implement code below for can_overflow(). |
| 2712 // If left is constant, we know the maximal allowed size for right. | 2699 // If left is constant, we know the maximal allowed size for right. |
| 2713 const Object& obj = shift_left->left()->BoundConstant(); | 2700 const Object& obj = shift_left->left()->BoundConstant(); |
| 2714 if (obj.IsSmi()) { | 2701 if (obj.IsSmi()) { |
| 2715 const intptr_t left_int = Smi::Cast(obj).Value(); | 2702 const intptr_t left_int = Smi::Cast(obj).Value(); |
| 2716 if (left_int == 0) { | 2703 if (left_int == 0) { |
| 2717 __ cmpl(right, Immediate(0)); | 2704 __ cmpl(right, Immediate(0)); |
| 2718 __ j(NEGATIVE, deopt); | 2705 __ j(NEGATIVE, deopt); |
| 2719 return; | 2706 return; |
| 2720 } | 2707 } |
| 2721 const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int); | 2708 const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int); |
| 2722 const bool right_needs_check = | 2709 const bool right_needs_check = |
| 2723 !RangeUtils::IsWithin(right_range, 0, max_right - 1); | 2710 !RangeUtils::IsWithin(right_range, 0, max_right - 1); |
| 2724 if (right_needs_check) { | 2711 if (right_needs_check) { |
| 2725 __ cmpl(right, | 2712 __ cmpl(right, |
| 2726 Immediate(reinterpret_cast<int32_t>(Smi::New(max_right)))); | 2713 Immediate(reinterpret_cast<int32_t>(Smi::New(max_right)))); |
| 2727 __ j(ABOVE_EQUAL, deopt); | 2714 __ j(ABOVE_EQUAL, deopt); |
| 2728 } | 2715 } |
| 2729 __ SmiUntag(right); | 2716 __ SmiUntag(right); |
| 2730 __ shll(left, right); | 2717 __ shll(left, right); |
| 2731 } | 2718 } |
| 2732 return; | 2719 return; |
| 2733 } | 2720 } |
| 2734 | 2721 |
| 2735 const bool right_needs_check = | 2722 const bool right_needs_check = |
| 2736 !RangeUtils::IsWithin(right_range, 0, (Smi::kBits - 1)); | 2723 !RangeUtils::IsWithin(right_range, 0, (Smi::kBits - 1)); |
| 2737 ASSERT(right == ECX); // Count must be in ECX | 2724 ASSERT(right == ECX); // Count must be in ECX |
| 2738 if (is_truncating) { | 2725 if (!shift_left->can_overflow()) { |
| 2739 if (right_needs_check) { | 2726 if (right_needs_check) { |
| 2740 const bool right_may_be_negative = | 2727 const bool right_may_be_negative = |
| 2741 (right_range == NULL) || !right_range->IsPositive(); | 2728 (right_range == NULL) || !right_range->IsPositive(); |
| 2742 if (right_may_be_negative) { | 2729 if (right_may_be_negative) { |
| 2743 ASSERT(shift_left->CanDeoptimize()); | 2730 ASSERT(shift_left->CanDeoptimize()); |
| 2744 __ cmpl(right, Immediate(0)); | 2731 __ cmpl(right, Immediate(0)); |
| 2745 __ j(NEGATIVE, deopt); | 2732 __ j(NEGATIVE, deopt); |
| 2746 } | 2733 } |
| 2747 Label done, is_not_zero; | 2734 Label done, is_not_zero; |
| 2748 __ cmpl(right, | 2735 __ cmpl(right, |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2817 return summary; | 2804 return summary; |
| 2818 } else if (op_kind() == Token::kSHR) { | 2805 } else if (op_kind() == Token::kSHR) { |
| 2819 const intptr_t kNumTemps = 0; | 2806 const intptr_t kNumTemps = 0; |
| 2820 LocationSummary* summary = new(isolate) LocationSummary( | 2807 LocationSummary* summary = new(isolate) LocationSummary( |
| 2821 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2808 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2822 summary->set_in(0, Location::RequiresRegister()); | 2809 summary->set_in(0, Location::RequiresRegister()); |
| 2823 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX)); | 2810 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX)); |
| 2824 summary->set_out(0, Location::SameAsFirstInput()); | 2811 summary->set_out(0, Location::SameAsFirstInput()); |
| 2825 return summary; | 2812 return summary; |
| 2826 } else if (op_kind() == Token::kSHL) { | 2813 } else if (op_kind() == Token::kSHL) { |
| 2827 const intptr_t kNumTemps = !IsTruncating() ? 1 : 0; | 2814 const intptr_t kNumTemps = can_overflow() ? 1 : 0; |
| 2828 LocationSummary* summary = new(isolate) LocationSummary( | 2815 LocationSummary* summary = new(isolate) LocationSummary( |
| 2829 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2816 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2830 summary->set_in(0, Location::RequiresRegister()); | 2817 summary->set_in(0, Location::RequiresRegister()); |
| 2831 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX)); | 2818 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX)); |
| 2832 if (!IsTruncating()) { | 2819 if (can_overflow()) { |
| 2833 summary->set_temp(0, Location::RequiresRegister()); | 2820 summary->set_temp(0, Location::RequiresRegister()); |
| 2834 } | 2821 } |
| 2835 summary->set_out(0, Location::SameAsFirstInput()); | 2822 summary->set_out(0, Location::SameAsFirstInput()); |
| 2836 return summary; | 2823 return summary; |
| 2837 } else { | 2824 } else { |
| 2838 const intptr_t kNumTemps = 0; | 2825 const intptr_t kNumTemps = 0; |
| 2839 LocationSummary* summary = new(isolate) LocationSummary( | 2826 LocationSummary* summary = new(isolate) LocationSummary( |
| 2840 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2827 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2841 summary->set_in(0, Location::RequiresRegister()); | 2828 summary->set_in(0, Location::RequiresRegister()); |
| 2842 ConstantInstr* constant = right()->definition()->AsConstant(); | 2829 ConstantInstr* constant = right()->definition()->AsConstant(); |
| 2843 if (constant != NULL) { | 2830 if (constant != NULL) { |
| 2844 summary->set_in(1, Location::RegisterOrSmiConstant(right())); | 2831 summary->set_in(1, Location::RegisterOrSmiConstant(right())); |
| 2845 } else { | 2832 } else { |
| 2846 summary->set_in(1, Location::PrefersRegister()); | 2833 summary->set_in(1, Location::PrefersRegister()); |
| 2847 } | 2834 } |
| 2848 summary->set_out(0, Location::SameAsFirstInput()); | 2835 summary->set_out(0, Location::SameAsFirstInput()); |
| 2849 return summary; | 2836 return summary; |
| 2850 } | 2837 } |
| 2851 } | 2838 } |
| 2852 | 2839 |
| 2853 | 2840 |
| 2841 template<typename OperandType> | |
| 2842 static void EmitIntegerArithmetic(FlowGraphCompiler* compiler, | |
| 2843 Token::Kind op_kind, | |
| 2844 Register left, | |
| 2845 const OperandType& right, | |
| 2846 Label* deopt) { | |
| 2847 switch (op_kind) { | |
| 2848 case Token::kADD: | |
| 2849 __ addl(left, right); | |
| 2850 break; | |
| 2851 case Token::kSUB: | |
| 2852 __ subl(left, right); | |
| 2853 break; | |
| 2854 case Token::kBIT_AND: | |
| 2855 __ andl(left, right); | |
| 2856 break; | |
| 2857 case Token::kBIT_OR: | |
| 2858 __ orl(left, right); | |
| 2859 break; | |
| 2860 case Token::kBIT_XOR: | |
| 2861 __ xorl(left, right); | |
| 2862 break; | |
| 2863 case Token::kMUL: | |
| 2864 __ imull(left, right); | |
| 2865 break; | |
| 2866 default: | |
| 2867 UNREACHABLE(); | |
| 2868 } | |
| 2869 if (deopt != NULL) __ j(OVERFLOW, deopt); | |
| 2870 } | |
| 2871 | |
| 2872 | |
| 2854 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2873 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2855 if (op_kind() == Token::kSHL) { | 2874 if (op_kind() == Token::kSHL) { |
| 2856 EmitSmiShiftLeft(compiler, this); | 2875 EmitSmiShiftLeft(compiler, this); |
| 2857 return; | 2876 return; |
| 2858 } | 2877 } |
| 2859 | 2878 |
| 2860 Register left = locs()->in(0).reg(); | 2879 Register left = locs()->in(0).reg(); |
| 2861 Register result = locs()->out(0).reg(); | 2880 Register result = locs()->out(0).reg(); |
| 2862 ASSERT(left == result); | 2881 ASSERT(left == result); |
| 2863 Label* deopt = NULL; | 2882 Label* deopt = NULL; |
| 2864 if (CanDeoptimize()) { | 2883 if (CanDeoptimize()) { |
| 2865 deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinarySmiOp); | 2884 deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinarySmiOp); |
| 2866 } | 2885 } |
| 2867 | 2886 |
| 2868 if (locs()->in(1).IsConstant()) { | 2887 if (locs()->in(1).IsConstant()) { |
| 2869 const Object& constant = locs()->in(1).constant(); | 2888 const Object& constant = locs()->in(1).constant(); |
| 2870 ASSERT(constant.IsSmi()); | 2889 ASSERT(constant.IsSmi()); |
| 2871 const int32_t imm = reinterpret_cast<int32_t>(constant.raw()); | 2890 // const int32_t imm = reinterpret_cast<int32_t>(constant.raw()); |
|
Cutch
2014/09/11 17:41:53
kill
| |
| 2891 const intptr_t value = Smi::Cast(constant).Value(); | |
| 2872 switch (op_kind()) { | 2892 switch (op_kind()) { |
| 2873 case Token::kADD: | 2893 case Token::kADD: |
| 2874 if (imm != 0) { | 2894 case Token::kSUB: |
| 2875 // Checking overflow without emitting an instruction would be wrong. | 2895 case Token::kBIT_AND: |
| 2876 __ addl(left, Immediate(imm)); | 2896 case Token::kBIT_OR: |
| 2877 if (deopt != NULL) __ j(OVERFLOW, deopt); | 2897 case Token::kBIT_XOR: |
| 2878 } | 2898 case Token::kMUL: { |
| 2879 break; | 2899 const intptr_t imm = (op_kind() == Token::kMUL) ? value |
| 2880 case Token::kSUB: { | 2900 : Smi::RawValue(value); |
| 2881 if (imm != 0) { | 2901 EmitIntegerArithmetic(compiler, |
| 2882 // Checking overflow without emitting an instruction would be wrong. | 2902 op_kind(), |
| 2883 __ subl(left, Immediate(imm)); | 2903 left, |
| 2884 if (deopt != NULL) __ j(OVERFLOW, deopt); | 2904 Immediate(imm), |
| 2885 } | 2905 deopt); |
| 2886 break; | 2906 break; |
| 2887 } | 2907 } |
| 2888 case Token::kMUL: { | 2908 |
| 2889 // Keep left value tagged and untag right value. | |
| 2890 const intptr_t value = Smi::Cast(constant).Value(); | |
| 2891 if (value == 2) { | |
| 2892 __ shll(left, Immediate(1)); | |
| 2893 } else { | |
| 2894 __ imull(left, Immediate(value)); | |
| 2895 } | |
| 2896 if (deopt != NULL) __ j(OVERFLOW, deopt); | |
| 2897 break; | |
| 2898 } | |
| 2899 case Token::kTRUNCDIV: { | 2909 case Token::kTRUNCDIV: { |
| 2900 const intptr_t value = Smi::Cast(constant).Value(); | |
| 2901 if (value == 1) { | |
| 2902 // Do nothing. | |
| 2903 break; | |
| 2904 } else if (value == -1) { | |
| 2905 // Check the corner case of dividing the 'MIN_SMI' with -1, in which | |
| 2906 // case we cannot negate the result. | |
| 2907 __ cmpl(left, Immediate(0x80000000)); | |
| 2908 __ j(EQUAL, deopt); | |
| 2909 __ negl(left); | |
| 2910 break; | |
| 2911 } | |
| 2912 ASSERT(Utils::IsPowerOfTwo(Utils::Abs(value))); | 2910 ASSERT(Utils::IsPowerOfTwo(Utils::Abs(value))); |
| 2913 const intptr_t shift_count = | 2911 const intptr_t shift_count = |
| 2914 Utils::ShiftForPowerOfTwo(Utils::Abs(value)) + kSmiTagSize; | 2912 Utils::ShiftForPowerOfTwo(Utils::Abs(value)) + kSmiTagSize; |
| 2915 ASSERT(kSmiTagSize == 1); | 2913 ASSERT(kSmiTagSize == 1); |
| 2916 Register temp = locs()->temp(0).reg(); | 2914 Register temp = locs()->temp(0).reg(); |
| 2917 __ movl(temp, left); | 2915 __ movl(temp, left); |
| 2918 __ sarl(temp, Immediate(31)); | 2916 __ sarl(temp, Immediate(31)); |
| 2919 ASSERT(shift_count > 1); // 1, -1 case handled above. | 2917 ASSERT(shift_count > 1); // 1, -1 case handled above. |
| 2920 __ shrl(temp, Immediate(32 - shift_count)); | 2918 __ shrl(temp, Immediate(32 - shift_count)); |
| 2921 __ addl(left, temp); | 2919 __ addl(left, temp); |
| 2922 ASSERT(shift_count > 0); | 2920 ASSERT(shift_count > 0); |
| 2923 __ sarl(left, Immediate(shift_count)); | 2921 __ sarl(left, Immediate(shift_count)); |
| 2924 if (value < 0) { | 2922 if (value < 0) { |
| 2925 __ negl(left); | 2923 __ negl(left); |
| 2926 } | 2924 } |
| 2927 __ SmiTag(left); | 2925 __ SmiTag(left); |
| 2928 break; | 2926 break; |
| 2929 } | 2927 } |
| 2930 case Token::kBIT_AND: { | 2928 |
| 2931 // No overflow check. | |
| 2932 __ andl(left, Immediate(imm)); | |
| 2933 break; | |
| 2934 } | |
| 2935 case Token::kBIT_OR: { | |
| 2936 // No overflow check. | |
| 2937 __ orl(left, Immediate(imm)); | |
| 2938 break; | |
| 2939 } | |
| 2940 case Token::kBIT_XOR: { | |
| 2941 // No overflow check. | |
| 2942 __ xorl(left, Immediate(imm)); | |
| 2943 break; | |
| 2944 } | |
| 2945 case Token::kSHR: { | 2929 case Token::kSHR: { |
| 2946 // sarl operation masks the count to 5 bits. | 2930 // sarl operation masks the count to 5 bits. |
| 2947 const intptr_t kCountLimit = 0x1F; | 2931 const intptr_t kCountLimit = 0x1F; |
| 2948 intptr_t value = Smi::Cast(constant).Value(); | 2932 __ sarl(left, Immediate( |
| 2949 | 2933 Utils::Minimum(value + kSmiTagSize, kCountLimit))); |
| 2950 if (value == 0) { | |
| 2951 // TODO(vegorov): should be handled outside. | |
| 2952 break; | |
| 2953 } else if (value < 0) { | |
| 2954 // TODO(vegorov): should be handled outside. | |
| 2955 __ jmp(deopt); | |
| 2956 break; | |
| 2957 } | |
| 2958 | |
| 2959 value = value + kSmiTagSize; | |
| 2960 if (value >= kCountLimit) value = kCountLimit; | |
| 2961 | |
| 2962 __ sarl(left, Immediate(value)); | |
| 2963 __ SmiTag(left); | 2934 __ SmiTag(left); |
| 2964 break; | 2935 break; |
| 2965 } | 2936 } |
| 2966 | 2937 |
| 2967 default: | 2938 default: |
| 2968 UNREACHABLE(); | 2939 UNREACHABLE(); |
| 2969 break; | 2940 break; |
| 2970 } | 2941 } |
| 2971 return; | 2942 return; |
| 2972 } // if locs()->in(1).IsConstant() | 2943 } // if locs()->in(1).IsConstant() |
| 2973 | 2944 |
| 2974 if (locs()->in(1).IsStackSlot()) { | 2945 if (locs()->in(1).IsStackSlot()) { |
| 2975 const Address& right = locs()->in(1).ToStackSlotAddress(); | 2946 const Address& right = locs()->in(1).ToStackSlotAddress(); |
| 2976 switch (op_kind()) { | 2947 if (op_kind() == Token::kMUL) { |
| 2977 case Token::kADD: { | 2948 __ SmiUntag(left); |
| 2978 __ addl(left, right); | |
| 2979 if (deopt != NULL) __ j(OVERFLOW, deopt); | |
| 2980 break; | |
| 2981 } | |
| 2982 case Token::kSUB: { | |
| 2983 __ subl(left, right); | |
| 2984 if (deopt != NULL) __ j(OVERFLOW, deopt); | |
| 2985 break; | |
| 2986 } | |
| 2987 case Token::kMUL: { | |
| 2988 __ SmiUntag(left); | |
| 2989 __ imull(left, right); | |
| 2990 if (deopt != NULL) __ j(OVERFLOW, deopt); | |
| 2991 break; | |
| 2992 } | |
| 2993 case Token::kBIT_AND: { | |
| 2994 // No overflow check. | |
| 2995 __ andl(left, right); | |
| 2996 break; | |
| 2997 } | |
| 2998 case Token::kBIT_OR: { | |
| 2999 // No overflow check. | |
| 3000 __ orl(left, right); | |
| 3001 break; | |
| 3002 } | |
| 3003 case Token::kBIT_XOR: { | |
| 3004 // No overflow check. | |
| 3005 __ xorl(left, right); | |
| 3006 break; | |
| 3007 } | |
| 3008 default: | |
| 3009 UNREACHABLE(); | |
| 3010 } | 2949 } |
| 2950 EmitIntegerArithmetic(compiler, op_kind(), left, right, deopt); | |
| 3011 return; | 2951 return; |
| 3012 } // if locs()->in(1).IsStackSlot. | 2952 } |
| 3013 | 2953 |
| 3014 // if locs()->in(1).IsRegister. | 2954 // if locs()->in(1).IsRegister. |
| 3015 Register right = locs()->in(1).reg(); | 2955 Register right = locs()->in(1).reg(); |
| 3016 Range* right_range = this->right()->definition()->range(); | 2956 Range* right_range = this->right()->definition()->range(); |
| 3017 switch (op_kind()) { | 2957 switch (op_kind()) { |
| 3018 case Token::kADD: { | 2958 case Token::kADD: |
| 3019 __ addl(left, right); | 2959 case Token::kSUB: |
| 3020 if (deopt != NULL) __ j(OVERFLOW, deopt); | 2960 case Token::kBIT_AND: |
| 2961 case Token::kBIT_OR: | |
| 2962 case Token::kBIT_XOR: | |
| 2963 case Token::kMUL: | |
| 2964 if (op_kind() == Token::kMUL) { | |
| 2965 __ SmiUntag(left); | |
| 2966 } | |
| 2967 EmitIntegerArithmetic(compiler, op_kind(), left, right, deopt); | |
| 3021 break; | 2968 break; |
| 3022 } | 2969 |
| 3023 case Token::kSUB: { | 2970 |
| 3024 __ subl(left, right); | |
| 3025 if (deopt != NULL) __ j(OVERFLOW, deopt); | |
| 3026 break; | |
| 3027 } | |
| 3028 case Token::kMUL: { | |
| 3029 __ SmiUntag(left); | |
| 3030 __ imull(left, right); | |
| 3031 if (deopt != NULL) __ j(OVERFLOW, deopt); | |
| 3032 break; | |
| 3033 } | |
| 3034 case Token::kBIT_AND: { | |
| 3035 // No overflow check. | |
| 3036 __ andl(left, right); | |
| 3037 break; | |
| 3038 } | |
| 3039 case Token::kBIT_OR: { | |
| 3040 // No overflow check. | |
| 3041 __ orl(left, right); | |
| 3042 break; | |
| 3043 } | |
| 3044 case Token::kBIT_XOR: { | |
| 3045 // No overflow check. | |
| 3046 __ xorl(left, right); | |
| 3047 break; | |
| 3048 } | |
| 3049 case Token::kTRUNCDIV: { | 2971 case Token::kTRUNCDIV: { |
| 3050 if ((right_range == NULL) || right_range->Overlaps(0, 0)) { | 2972 if ((right_range == NULL) || right_range->Overlaps(0, 0)) { |
| 3051 // Handle divide by zero in runtime. | 2973 // Handle divide by zero in runtime. |
| 3052 __ testl(right, right); | 2974 __ testl(right, right); |
| 3053 __ j(ZERO, deopt); | 2975 __ j(ZERO, deopt); |
| 3054 } | 2976 } |
| 3055 ASSERT(left == EAX); | 2977 ASSERT(left == EAX); |
| 3056 ASSERT((right != EDX) && (right != EAX)); | 2978 ASSERT((right != EDX) && (right != EAX)); |
| 3057 ASSERT(locs()->temp(0).reg() == EDX); | 2979 ASSERT(locs()->temp(0).reg() == EDX); |
| 3058 ASSERT(result == EAX); | 2980 ASSERT(result == EAX); |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3167 return NULL; | 3089 return NULL; |
| 3168 } else if (op_kind() == Token::kSHR) { | 3090 } else if (op_kind() == Token::kSHR) { |
| 3169 const intptr_t kNumTemps = 0; | 3091 const intptr_t kNumTemps = 0; |
| 3170 LocationSummary* summary = new(isolate) LocationSummary( | 3092 LocationSummary* summary = new(isolate) LocationSummary( |
| 3171 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); | 3093 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 3172 summary->set_in(0, Location::RequiresRegister()); | 3094 summary->set_in(0, Location::RequiresRegister()); |
| 3173 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX)); | 3095 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX)); |
| 3174 summary->set_out(0, Location::SameAsFirstInput()); | 3096 summary->set_out(0, Location::SameAsFirstInput()); |
| 3175 return summary; | 3097 return summary; |
| 3176 } else if (op_kind() == Token::kSHL) { | 3098 } else if (op_kind() == Token::kSHL) { |
| 3177 const intptr_t kNumTemps = !IsTruncating() ? 1 : 0; | 3099 const intptr_t kNumTemps = can_overflow() ? 1 : 0; |
| 3178 LocationSummary* summary = new(isolate) LocationSummary( | 3100 LocationSummary* summary = new(isolate) LocationSummary( |
| 3179 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); | 3101 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 3180 summary->set_in(0, Location::RequiresRegister()); | 3102 summary->set_in(0, Location::RequiresRegister()); |
| 3181 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX)); | 3103 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX)); |
| 3182 if (!IsTruncating()) { | 3104 if (can_overflow()) { |
| 3183 summary->set_temp(0, Location::RequiresRegister()); | 3105 summary->set_temp(0, Location::RequiresRegister()); |
| 3184 } | 3106 } |
| 3185 summary->set_out(0, Location::SameAsFirstInput()); | 3107 summary->set_out(0, Location::SameAsFirstInput()); |
| 3186 return summary; | 3108 return summary; |
| 3187 } else { | 3109 } else { |
| 3188 const intptr_t kNumTemps = 0; | 3110 const intptr_t kNumTemps = 0; |
| 3189 LocationSummary* summary = new(isolate) LocationSummary( | 3111 LocationSummary* summary = new(isolate) LocationSummary( |
| 3190 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); | 3112 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 3191 summary->set_in(0, Location::RequiresRegister()); | 3113 summary->set_in(0, Location::RequiresRegister()); |
| 3192 ConstantInstr* constant = right()->definition()->AsConstant(); | 3114 ConstantInstr* constant = right()->definition()->AsConstant(); |
| 3193 if (constant != NULL) { | 3115 if (constant != NULL) { |
| 3194 summary->set_in(1, Location::RegisterOrSmiConstant(right())); | 3116 summary->set_in(1, Location::RegisterOrSmiConstant(right())); |
| 3195 } else { | 3117 } else { |
| 3196 summary->set_in(1, Location::PrefersRegister()); | 3118 summary->set_in(1, Location::PrefersRegister()); |
| 3197 } | 3119 } |
| 3198 summary->set_out(0, Location::SameAsFirstInput()); | 3120 summary->set_out(0, Location::SameAsFirstInput()); |
| 3199 return summary; | 3121 return summary; |
| 3200 } | 3122 } |
| 3201 } | 3123 } |
| 3202 | 3124 |
| 3203 | 3125 |
| 3204 static void EmitInt32ShiftLeft(FlowGraphCompiler* compiler, | 3126 static void EmitInt32ShiftLeft(FlowGraphCompiler* compiler, |
| 3205 BinaryInt32OpInstr* shift_left) { | 3127 BinaryInt32OpInstr* shift_left) { |
| 3206 const bool is_truncating = shift_left->IsTruncating(); | |
| 3207 const LocationSummary& locs = *shift_left->locs(); | 3128 const LocationSummary& locs = *shift_left->locs(); |
| 3208 Register left = locs.in(0).reg(); | 3129 Register left = locs.in(0).reg(); |
| 3209 Register result = locs.out(0).reg(); | 3130 Register result = locs.out(0).reg(); |
| 3210 ASSERT(left == result); | 3131 ASSERT(left == result); |
| 3211 Label* deopt = shift_left->CanDeoptimize() ? | 3132 Label* deopt = shift_left->CanDeoptimize() ? |
| 3212 compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp) | 3133 compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp) |
| 3213 : NULL; | 3134 : NULL; |
| 3214 ASSERT(locs.in(1).IsConstant()); | 3135 ASSERT(locs.in(1).IsConstant()); |
| 3215 | 3136 |
| 3216 const Object& constant = locs.in(1).constant(); | 3137 const Object& constant = locs.in(1).constant(); |
| 3217 ASSERT(constant.IsSmi()); | 3138 ASSERT(constant.IsSmi()); |
| 3218 // shll operation masks the count to 5 bits. | 3139 // shll operation masks the count to 5 bits. |
| 3219 const intptr_t kCountLimit = 0x1F; | 3140 const intptr_t kCountLimit = 0x1F; |
| 3220 const intptr_t value = Smi::Cast(constant).Value(); | 3141 const intptr_t value = Smi::Cast(constant).Value(); |
| 3221 if (value == 0) { | 3142 ASSERT((0 < value) && (value < kCountLimit)); |
| 3222 // No code needed. | 3143 if (shift_left->can_overflow()) { |
| 3223 } else if ((value < 0) || (value >= kCountLimit)) { | 3144 // Check for overflow. |
| 3224 // This condition may not be known earlier in some cases because | 3145 Register temp = locs.temp(0).reg(); |
| 3225 // of constant propagation, inlining, etc. | 3146 __ movl(temp, left); |
| 3226 if ((value >= kCountLimit) && is_truncating) { | |
| 3227 __ xorl(result, result); | |
| 3228 } else { | |
| 3229 // Result is Mint or exception. | |
| 3230 __ jmp(deopt); | |
| 3231 } | |
| 3232 } else { | |
| 3233 if (!is_truncating) { | |
| 3234 // Check for overflow. | |
| 3235 Register temp = locs.temp(0).reg(); | |
| 3236 __ movl(temp, left); | |
| 3237 __ shll(left, Immediate(value)); | |
| 3238 __ sarl(left, Immediate(value)); | |
| 3239 __ cmpl(left, temp); | |
| 3240 __ j(NOT_EQUAL, deopt); // Overflow. | |
| 3241 } | |
| 3242 // Shift for result now we know there is no overflow. | |
| 3243 __ shll(left, Immediate(value)); | 3147 __ shll(left, Immediate(value)); |
| 3148 __ sarl(left, Immediate(value)); | |
| 3149 __ cmpl(left, temp); | |
| 3150 __ j(NOT_EQUAL, deopt); // Overflow. | |
| 3244 } | 3151 } |
| 3152 // Shift for result now we know there is no overflow. | |
| 3153 __ shll(left, Immediate(value)); | |
| 3245 } | 3154 } |
| 3246 | 3155 |
| 3247 | 3156 |
| 3248 void BinaryInt32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3157 void BinaryInt32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 3249 if (op_kind() == Token::kSHL) { | 3158 if (op_kind() == Token::kSHL) { |
| 3250 EmitInt32ShiftLeft(compiler, this); | 3159 EmitInt32ShiftLeft(compiler, this); |
| 3251 return; | 3160 return; |
| 3252 } | 3161 } |
| 3253 | 3162 |
| 3254 Register left = locs()->in(0).reg(); | 3163 Register left = locs()->in(0).reg(); |
| 3255 Register result = locs()->out(0).reg(); | 3164 Register result = locs()->out(0).reg(); |
| 3256 ASSERT(left == result); | 3165 ASSERT(left == result); |
| 3257 Label* deopt = NULL; | 3166 Label* deopt = NULL; |
| 3258 if (CanDeoptimize()) { | 3167 if (CanDeoptimize()) { |
| 3259 deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinarySmiOp); | 3168 deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinarySmiOp); |
| 3260 } | 3169 } |
| 3261 | 3170 |
| 3262 if (locs()->in(1).IsConstant()) { | 3171 if (locs()->in(1).IsConstant()) { |
| 3263 const Object& constant = locs()->in(1).constant(); | 3172 const Object& constant = locs()->in(1).constant(); |
| 3264 ASSERT(constant.IsSmi()); | 3173 ASSERT(constant.IsSmi()); |
| 3265 const intptr_t value = Smi::Cast(constant).Value(); | 3174 const intptr_t value = Smi::Cast(constant).Value(); |
| 3266 switch (op_kind()) { | 3175 switch (op_kind()) { |
| 3267 case Token::kADD: | 3176 case Token::kADD: |
| 3268 if (value != 0) { | 3177 case Token::kSUB: |
| 3269 // Checking overflow without emitting an instruction would be wrong. | 3178 case Token::kMUL: |
| 3270 __ addl(left, Immediate(value)); | 3179 case Token::kBIT_AND: |
| 3271 if (deopt != NULL) __ j(OVERFLOW, deopt); | 3180 case Token::kBIT_OR: |
| 3272 } | 3181 case Token::kBIT_XOR: |
| 3182 EmitIntegerArithmetic(compiler, | |
| 3183 op_kind(), | |
| 3184 left, | |
| 3185 Immediate(value), | |
| 3186 deopt); | |
| 3273 break; | 3187 break; |
| 3274 case Token::kSUB: { | 3188 |
| 3275 if (value != 0) { | 3189 |
| 3276 // Checking overflow without emitting an instruction would be wrong. | 3190 |
| 3277 __ subl(left, Immediate(value)); | |
| 3278 if (deopt != NULL) __ j(OVERFLOW, deopt); | |
| 3279 } | |
| 3280 break; | |
| 3281 } | |
| 3282 case Token::kMUL: { | |
| 3283 if (value == 2) { | |
| 3284 __ shll(left, Immediate(1)); | |
| 3285 } else { | |
| 3286 __ imull(left, Immediate(value)); | |
| 3287 } | |
| 3288 if (deopt != NULL) __ j(OVERFLOW, deopt); | |
| 3289 break; | |
| 3290 } | |
| 3291 case Token::kTRUNCDIV: { | 3191 case Token::kTRUNCDIV: { |
| 3292 UNREACHABLE(); | 3192 UNREACHABLE(); |
| 3293 break; | 3193 break; |
| 3294 } | 3194 } |
| 3295 case Token::kBIT_AND: { | 3195 |
| 3296 // No overflow check. | |
| 3297 __ andl(left, Immediate(value)); | |
| 3298 break; | |
| 3299 } | |
| 3300 case Token::kBIT_OR: { | |
| 3301 // No overflow check. | |
| 3302 __ orl(left, Immediate(value)); | |
| 3303 break; | |
| 3304 } | |
| 3305 case Token::kBIT_XOR: { | |
| 3306 // No overflow check. | |
| 3307 __ xorl(left, Immediate(value)); | |
| 3308 break; | |
| 3309 } | |
| 3310 case Token::kSHR: { | 3196 case Token::kSHR: { |
| 3311 // sarl operation masks the count to 5 bits. | 3197 // sarl operation masks the count to 5 bits. |
| 3312 const intptr_t kCountLimit = 0x1F; | 3198 const intptr_t kCountLimit = 0x1F; |
| 3313 if (value == 0) { | 3199 __ sarl(left, Immediate(Utils::Minimum(value, kCountLimit))); |
| 3314 // TODO(vegorov): should be handled outside. | |
| 3315 break; | |
| 3316 } else if (value < 0) { | |
| 3317 // TODO(vegorov): should be handled outside. | |
| 3318 __ jmp(deopt); | |
| 3319 break; | |
| 3320 } | |
| 3321 | |
| 3322 if (value >= kCountLimit) { | |
| 3323 __ sarl(left, Immediate(kCountLimit)); | |
| 3324 } else { | |
| 3325 __ sarl(left, Immediate(value)); | |
| 3326 } | |
| 3327 | |
| 3328 break; | 3200 break; |
| 3329 } | 3201 } |
| 3330 | 3202 |
| 3331 default: | 3203 default: |
| 3332 UNREACHABLE(); | 3204 UNREACHABLE(); |
| 3333 break; | 3205 break; |
| 3334 } | 3206 } |
| 3335 return; | 3207 return; |
| 3336 } // if locs()->in(1).IsConstant() | 3208 } // if locs()->in(1).IsConstant() |
| 3337 | 3209 |
| 3338 if (locs()->in(1).IsStackSlot()) { | 3210 if (locs()->in(1).IsStackSlot()) { |
| 3339 const Address& right = locs()->in(1).ToStackSlotAddress(); | 3211 const Address& right = locs()->in(1).ToStackSlotAddress(); |
| 3340 switch (op_kind()) { | 3212 EmitIntegerArithmetic(compiler, |
| 3341 case Token::kADD: { | 3213 op_kind(), |
| 3342 __ addl(left, right); | 3214 left, |
| 3343 if (deopt != NULL) __ j(OVERFLOW, deopt); | 3215 right, |
| 3344 break; | 3216 deopt); |
| 3345 } | |
| 3346 case Token::kSUB: { | |
| 3347 __ subl(left, right); | |
| 3348 if (deopt != NULL) __ j(OVERFLOW, deopt); | |
| 3349 break; | |
| 3350 } | |
| 3351 case Token::kMUL: { | |
| 3352 __ imull(left, right); | |
| 3353 if (deopt != NULL) __ j(OVERFLOW, deopt); | |
| 3354 break; | |
| 3355 } | |
| 3356 case Token::kBIT_AND: { | |
| 3357 // No overflow check. | |
| 3358 __ andl(left, right); | |
| 3359 break; | |
| 3360 } | |
| 3361 case Token::kBIT_OR: { | |
| 3362 // No overflow check. | |
| 3363 __ orl(left, right); | |
| 3364 break; | |
| 3365 } | |
| 3366 case Token::kBIT_XOR: { | |
| 3367 // No overflow check. | |
| 3368 __ xorl(left, right); | |
| 3369 break; | |
| 3370 } | |
| 3371 default: | |
| 3372 UNREACHABLE(); | |
| 3373 } | |
| 3374 return; | 3217 return; |
| 3375 } // if locs()->in(1).IsStackSlot. | 3218 } // if locs()->in(1).IsStackSlot. |
| 3376 | 3219 |
| 3377 // if locs()->in(1).IsRegister. | 3220 // if locs()->in(1).IsRegister. |
| 3378 Register right = locs()->in(1).reg(); | 3221 Register right = locs()->in(1).reg(); |
| 3379 switch (op_kind()) { | 3222 switch (op_kind()) { |
| 3380 case Token::kADD: { | 3223 case Token::kADD: |
| 3381 __ addl(left, right); | 3224 case Token::kSUB: |
| 3382 if (deopt != NULL) __ j(OVERFLOW, deopt); | 3225 case Token::kMUL: |
| 3226 case Token::kBIT_AND: | |
| 3227 case Token::kBIT_OR: | |
| 3228 case Token::kBIT_XOR: | |
| 3229 EmitIntegerArithmetic(compiler, | |
| 3230 op_kind(), | |
| 3231 left, | |
| 3232 right, | |
| 3233 deopt); | |
| 3383 break; | 3234 break; |
| 3384 } | 3235 |
| 3385 case Token::kSUB: { | |
| 3386 __ subl(left, right); | |
| 3387 if (deopt != NULL) __ j(OVERFLOW, deopt); | |
| 3388 break; | |
| 3389 } | |
| 3390 case Token::kMUL: { | |
| 3391 __ imull(left, right); | |
| 3392 if (deopt != NULL) __ j(OVERFLOW, deopt); | |
| 3393 break; | |
| 3394 } | |
| 3395 case Token::kBIT_AND: { | |
| 3396 // No overflow check. | |
| 3397 __ andl(left, right); | |
| 3398 break; | |
| 3399 } | |
| 3400 case Token::kBIT_OR: { | |
| 3401 // No overflow check. | |
| 3402 __ orl(left, right); | |
| 3403 break; | |
| 3404 } | |
| 3405 case Token::kBIT_XOR: { | |
| 3406 // No overflow check. | |
| 3407 __ xorl(left, right); | |
| 3408 break; | |
| 3409 } | |
| 3410 case Token::kTRUNCDIV: { | |
| 3411 UNREACHABLE(); | |
| 3412 break; | |
| 3413 } | |
| 3414 case Token::kMOD: { | |
| 3415 UNREACHABLE(); | |
| 3416 break; | |
| 3417 } | |
| 3418 case Token::kSHR: { | |
| 3419 UNREACHABLE(); | |
| 3420 break; | |
| 3421 } | |
| 3422 case Token::kDIV: { | |
| 3423 // Dispatches to 'Double./'. | |
| 3424 // TODO(srdjan): Implement as conversion to double and double division. | |
| 3425 UNREACHABLE(); | |
| 3426 break; | |
| 3427 } | |
| 3428 case Token::kOR: | |
| 3429 case Token::kAND: { | |
| 3430 // Flow graph builder has dissected this operation to guarantee correct | |
| 3431 // behavior (short-circuit evaluation). | |
| 3432 UNREACHABLE(); | |
| 3433 break; | |
| 3434 } | |
| 3435 default: | 3236 default: |
| 3436 UNREACHABLE(); | 3237 UNREACHABLE(); |
| 3437 break; | 3238 break; |
| 3438 } | 3239 } |
| 3439 } | 3240 } |
| 3440 | 3241 |
| 3242 | |
| 3243 LocationSummary* BinaryUint32OpInstr::MakeLocationSummary(Isolate* isolate, | |
| 3244 bool opt) const { | |
| 3245 const intptr_t kNumInputs = 2; | |
| 3246 const intptr_t kNumTemps = (op_kind() == Token::kMUL) ? 1 : 0; | |
| 3247 LocationSummary* summary = new(isolate) LocationSummary( | |
| 3248 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); | |
| 3249 if (op_kind() == Token::kMUL) { | |
| 3250 summary->set_in(0, Location::RegisterLocation(EAX)); | |
| 3251 summary->set_temp(0, Location::RegisterLocation(EDX)); | |
| 3252 } else { | |
| 3253 summary->set_in(0, Location::RequiresRegister()); | |
| 3254 } | |
| 3255 summary->set_in(1, Location::RequiresRegister()); | |
| 3256 summary->set_out(0, Location::SameAsFirstInput()); | |
| 3257 return summary; | |
| 3258 } | |
| 3259 | |
| 3260 | |
| 3261 void BinaryUint32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 3262 Register left = locs()->in(0).reg(); | |
| 3263 Register right = locs()->in(1).reg(); | |
| 3264 Register out = locs()->out(0).reg(); | |
| 3265 ASSERT(out == left); | |
| 3266 switch (op_kind()) { | |
| 3267 case Token::kBIT_AND: | |
| 3268 case Token::kBIT_OR: | |
| 3269 case Token::kBIT_XOR: | |
| 3270 case Token::kADD: | |
| 3271 case Token::kSUB: | |
| 3272 EmitIntegerArithmetic(compiler, op_kind(), left, right, NULL); | |
| 3273 return; | |
| 3274 | |
| 3275 case Token::kMUL: | |
| 3276 __ mull(right); // Result in EDX:EAX. | |
| 3277 ASSERT(out == EAX); | |
| 3278 ASSERT(locs()->temp(0).reg() == EDX); | |
| 3279 break; | |
| 3280 default: | |
| 3281 UNREACHABLE(); | |
| 3282 } | |
| 3283 } | |
| 3284 | |
| 3441 | 3285 |
| 3442 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary(Isolate* isolate, | 3286 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary(Isolate* isolate, |
| 3443 bool opt) const { | 3287 bool opt) const { |
| 3444 intptr_t left_cid = left()->Type()->ToCid(); | 3288 intptr_t left_cid = left()->Type()->ToCid(); |
| 3445 intptr_t right_cid = right()->Type()->ToCid(); | 3289 intptr_t right_cid = right()->Type()->ToCid(); |
| 3446 ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid)); | 3290 ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid)); |
| 3447 const intptr_t kNumInputs = 2; | 3291 const intptr_t kNumInputs = 2; |
| 3448 const bool need_temp = (left()->definition() != right()->definition()) | 3292 const bool need_temp = (left()->definition() != right()->definition()) |
| 3449 && (left_cid != kSmiCid) | 3293 && (left_cid != kSmiCid) |
| 3450 && (right_cid != kSmiCid); | 3294 && (right_cid != kSmiCid); |
| (...skipping 2771 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6222 CompileType ShiftUint32OpInstr::ComputeType() const { | 6066 CompileType ShiftUint32OpInstr::ComputeType() const { |
| 6223 return CompileType::Int(); | 6067 return CompileType::Int(); |
| 6224 } | 6068 } |
| 6225 | 6069 |
| 6226 | 6070 |
| 6227 CompileType UnaryUint32OpInstr::ComputeType() const { | 6071 CompileType UnaryUint32OpInstr::ComputeType() const { |
| 6228 return CompileType::Int(); | 6072 return CompileType::Int(); |
| 6229 } | 6073 } |
| 6230 | 6074 |
| 6231 | 6075 |
| 6232 LocationSummary* BinaryUint32OpInstr::MakeLocationSummary(Isolate* isolate, | |
| 6233 bool opt) const { | |
| 6234 const intptr_t kNumInputs = 2; | |
| 6235 const intptr_t kNumTemps = (op_kind() == Token::kMUL) ? 1 : 0; | |
| 6236 LocationSummary* summary = new(isolate) LocationSummary( | |
| 6237 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); | |
| 6238 if (op_kind() == Token::kMUL) { | |
| 6239 summary->set_in(0, Location::RegisterLocation(EAX)); | |
| 6240 summary->set_temp(0, Location::RegisterLocation(EDX)); | |
| 6241 } else { | |
| 6242 summary->set_in(0, Location::RequiresRegister()); | |
| 6243 } | |
| 6244 summary->set_in(1, Location::RequiresRegister()); | |
| 6245 summary->set_out(0, Location::SameAsFirstInput()); | |
| 6246 return summary; | |
| 6247 } | |
| 6248 | |
| 6249 | |
| 6250 void BinaryUint32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 6251 Register left = locs()->in(0).reg(); | |
| 6252 Register right = locs()->in(1).reg(); | |
| 6253 Register out = locs()->out(0).reg(); | |
| 6254 ASSERT(out == left); | |
| 6255 switch (op_kind()) { | |
| 6256 case Token::kBIT_AND: | |
| 6257 __ andl(out, right); | |
| 6258 break; | |
| 6259 case Token::kBIT_OR: | |
| 6260 __ orl(out, right); | |
| 6261 break; | |
| 6262 case Token::kBIT_XOR: | |
| 6263 __ xorl(out, right); | |
| 6264 break; | |
| 6265 case Token::kADD: | |
| 6266 __ addl(out, right); | |
| 6267 break; | |
| 6268 case Token::kSUB: | |
| 6269 __ subl(out, right); | |
| 6270 break; | |
| 6271 case Token::kMUL: | |
| 6272 __ mull(right); // Result in EDX:EAX. | |
| 6273 ASSERT(out == EAX); | |
| 6274 ASSERT(locs()->temp(0).reg() == EDX); | |
| 6275 break; | |
| 6276 default: | |
| 6277 UNREACHABLE(); | |
| 6278 } | |
| 6279 } | |
| 6280 | |
| 6281 | |
| 6282 LocationSummary* ShiftUint32OpInstr::MakeLocationSummary(Isolate* isolate, | 6076 LocationSummary* ShiftUint32OpInstr::MakeLocationSummary(Isolate* isolate, |
| 6283 bool opt) const { | 6077 bool opt) const { |
| 6284 const intptr_t kNumInputs = 2; | 6078 const intptr_t kNumInputs = 2; |
| 6285 const intptr_t kNumTemps = 0; | 6079 const intptr_t kNumTemps = 0; |
| 6286 LocationSummary* summary = new(isolate) LocationSummary( | 6080 LocationSummary* summary = new(isolate) LocationSummary( |
| 6287 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); | 6081 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 6288 summary->set_in(0, Location::RequiresRegister()); | 6082 summary->set_in(0, Location::RequiresRegister()); |
| 6289 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX)); | 6083 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX)); |
| 6290 summary->set_out(0, Location::SameAsFirstInput()); | 6084 summary->set_out(0, Location::SameAsFirstInput()); |
| 6291 return summary; | 6085 return summary; |
| (...skipping 683 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6975 __ movl(EDX, Immediate(kInvalidObjectPointer)); | 6769 __ movl(EDX, Immediate(kInvalidObjectPointer)); |
| 6976 __ movl(EDX, Immediate(kInvalidObjectPointer)); | 6770 __ movl(EDX, Immediate(kInvalidObjectPointer)); |
| 6977 #endif | 6771 #endif |
| 6978 } | 6772 } |
| 6979 | 6773 |
| 6980 } // namespace dart | 6774 } // namespace dart |
| 6981 | 6775 |
| 6982 #undef __ | 6776 #undef __ |
| 6983 | 6777 |
| 6984 #endif // defined TARGET_ARCH_IA32 | 6778 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |