Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(164)

Side by Side Diff: runtime/vm/intermediate_language_ia32.cc

Issue 564843002: Initial steps towards cleaning up integer arithmetic IR. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698