| 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_ARM. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. |
| 6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 7 | 7 |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 | 9 |
| 10 #include "vm/cpu.h" | 10 #include "vm/cpu.h" |
| (...skipping 2827 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2838 } | 2838 } |
| 2839 if (compiler->ForceSlowPathForStackOverflow()) { | 2839 if (compiler->ForceSlowPathForStackOverflow()) { |
| 2840 __ b(slow_path->entry_label()); | 2840 __ b(slow_path->entry_label()); |
| 2841 } | 2841 } |
| 2842 __ Bind(slow_path->exit_label()); | 2842 __ Bind(slow_path->exit_label()); |
| 2843 } | 2843 } |
| 2844 | 2844 |
| 2845 | 2845 |
| 2846 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, | 2846 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, |
| 2847 BinarySmiOpInstr* shift_left) { | 2847 BinarySmiOpInstr* shift_left) { |
| 2848 const bool is_truncating = shift_left->IsTruncating(); | |
| 2849 const LocationSummary& locs = *shift_left->locs(); | 2848 const LocationSummary& locs = *shift_left->locs(); |
| 2850 const Register left = locs.in(0).reg(); | 2849 const Register left = locs.in(0).reg(); |
| 2851 const Register result = locs.out(0).reg(); | 2850 const Register result = locs.out(0).reg(); |
| 2852 Label* deopt = shift_left->CanDeoptimize() ? | 2851 Label* deopt = shift_left->CanDeoptimize() ? |
| 2853 compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp) | 2852 compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp) |
| 2854 : NULL; | 2853 : NULL; |
| 2855 if (locs.in(1).IsConstant()) { | 2854 if (locs.in(1).IsConstant()) { |
| 2856 const Object& constant = locs.in(1).constant(); | 2855 const Object& constant = locs.in(1).constant(); |
| 2857 ASSERT(constant.IsSmi()); | 2856 ASSERT(constant.IsSmi()); |
| 2858 // Immediate shift operation takes 5 bits for the count. | 2857 // Immediate shift operation takes 5 bits for the count. |
| 2859 const intptr_t kCountLimit = 0x1F; | 2858 const intptr_t kCountLimit = 0x1F; |
| 2860 const intptr_t value = Smi::Cast(constant).Value(); | 2859 const intptr_t value = Smi::Cast(constant).Value(); |
| 2861 if (value == 0) { | 2860 ASSERT((0 < value) && (value < kCountLimit)); |
| 2862 __ MoveRegister(result, left); | 2861 if (shift_left->can_overflow()) { |
| 2863 } else if ((value < 0) || (value >= kCountLimit)) { | 2862 // Check for overflow (preserve left). |
| 2864 // This condition may not be known earlier in some cases because | 2863 __ Lsl(IP, left, value); |
| 2865 // of constant propagation, inlining, etc. | 2864 __ cmp(left, Operand(IP, ASR, value)); |
| 2866 if ((value >= kCountLimit) && is_truncating) { | 2865 __ b(deopt, NE); // Overflow. |
| 2867 __ mov(result, Operand(0)); | |
| 2868 } else { | |
| 2869 // Result is Mint or exception. | |
| 2870 __ b(deopt); | |
| 2871 } | |
| 2872 } else { | |
| 2873 if (!is_truncating) { | |
| 2874 // Check for overflow (preserve left). | |
| 2875 __ Lsl(IP, left, value); | |
| 2876 __ cmp(left, Operand(IP, ASR, value)); | |
| 2877 __ b(deopt, NE); // Overflow. | |
| 2878 } | |
| 2879 // Shift for result now we know there is no overflow. | |
| 2880 __ Lsl(result, left, value); | |
| 2881 } | 2866 } |
| 2867 // Shift for result now we know there is no overflow. |
| 2868 __ Lsl(result, left, value); |
| 2882 return; | 2869 return; |
| 2883 } | 2870 } |
| 2884 | 2871 |
| 2885 // Right (locs.in(1)) is not constant. | 2872 // Right (locs.in(1)) is not constant. |
| 2886 const Register right = locs.in(1).reg(); | 2873 const Register right = locs.in(1).reg(); |
| 2887 Range* right_range = shift_left->right()->definition()->range(); | 2874 Range* right_range = shift_left->right()->definition()->range(); |
| 2888 if (shift_left->left()->BindsToConstant() && !is_truncating) { | 2875 if (shift_left->left()->BindsToConstant() && shift_left->can_overflow()) { |
| 2889 // TODO(srdjan): Implement code below for is_truncating(). | 2876 // TODO(srdjan): Implement code below for is_truncating(). |
| 2890 // If left is constant, we know the maximal allowed size for right. | 2877 // If left is constant, we know the maximal allowed size for right. |
| 2891 const Object& obj = shift_left->left()->BoundConstant(); | 2878 const Object& obj = shift_left->left()->BoundConstant(); |
| 2892 if (obj.IsSmi()) { | 2879 if (obj.IsSmi()) { |
| 2893 const intptr_t left_int = Smi::Cast(obj).Value(); | 2880 const intptr_t left_int = Smi::Cast(obj).Value(); |
| 2894 if (left_int == 0) { | 2881 if (left_int == 0) { |
| 2895 __ cmp(right, Operand(0)); | 2882 __ cmp(right, Operand(0)); |
| 2896 __ b(deopt, MI); | 2883 __ b(deopt, MI); |
| 2897 __ mov(result, Operand(0)); | 2884 __ mov(result, Operand(0)); |
| 2898 return; | 2885 return; |
| 2899 } | 2886 } |
| 2900 const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int); | 2887 const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int); |
| 2901 const bool right_needs_check = | 2888 const bool right_needs_check = |
| 2902 !RangeUtils::IsWithin(right_range, 0, max_right - 1); | 2889 !RangeUtils::IsWithin(right_range, 0, max_right - 1); |
| 2903 if (right_needs_check) { | 2890 if (right_needs_check) { |
| 2904 __ cmp(right, Operand(reinterpret_cast<int32_t>(Smi::New(max_right)))); | 2891 __ cmp(right, Operand(reinterpret_cast<int32_t>(Smi::New(max_right)))); |
| 2905 __ b(deopt, CS); | 2892 __ b(deopt, CS); |
| 2906 } | 2893 } |
| 2907 __ SmiUntag(IP, right); | 2894 __ SmiUntag(IP, right); |
| 2908 __ Lsl(result, left, IP); | 2895 __ Lsl(result, left, IP); |
| 2909 } | 2896 } |
| 2910 return; | 2897 return; |
| 2911 } | 2898 } |
| 2912 | 2899 |
| 2913 const bool right_needs_check = | 2900 const bool right_needs_check = |
| 2914 !RangeUtils::IsWithin(right_range, 0, (Smi::kBits - 1)); | 2901 !RangeUtils::IsWithin(right_range, 0, (Smi::kBits - 1)); |
| 2915 if (is_truncating) { | 2902 if (!shift_left->can_overflow()) { |
| 2916 if (right_needs_check) { | 2903 if (right_needs_check) { |
| 2917 const bool right_may_be_negative = | 2904 const bool right_may_be_negative = |
| 2918 (right_range == NULL) || !right_range->IsPositive(); | 2905 (right_range == NULL) || !right_range->IsPositive(); |
| 2919 if (right_may_be_negative) { | 2906 if (right_may_be_negative) { |
| 2920 ASSERT(shift_left->CanDeoptimize()); | 2907 ASSERT(shift_left->CanDeoptimize()); |
| 2921 __ cmp(right, Operand(0)); | 2908 __ cmp(right, Operand(0)); |
| 2922 __ b(deopt, MI); | 2909 __ b(deopt, MI); |
| 2923 } | 2910 } |
| 2924 | 2911 |
| 2925 __ cmp(right, Operand(reinterpret_cast<int32_t>(Smi::New(Smi::kBits)))); | 2912 __ cmp(right, Operand(reinterpret_cast<int32_t>(Smi::New(Smi::kBits)))); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 2956 // Calculate number of temporaries. | 2943 // Calculate number of temporaries. |
| 2957 intptr_t num_temps = 0; | 2944 intptr_t num_temps = 0; |
| 2958 if (op_kind() == Token::kTRUNCDIV) { | 2945 if (op_kind() == Token::kTRUNCDIV) { |
| 2959 if (RightIsPowerOfTwoConstant()) { | 2946 if (RightIsPowerOfTwoConstant()) { |
| 2960 num_temps = 1; | 2947 num_temps = 1; |
| 2961 } else { | 2948 } else { |
| 2962 num_temps = 2; | 2949 num_temps = 2; |
| 2963 } | 2950 } |
| 2964 } else if (op_kind() == Token::kMOD) { | 2951 } else if (op_kind() == Token::kMOD) { |
| 2965 num_temps = 2; | 2952 num_temps = 2; |
| 2966 } else if (((op_kind() == Token::kSHL) && !IsTruncating()) || | 2953 } else if (((op_kind() == Token::kSHL) && can_overflow()) || |
| 2967 (op_kind() == Token::kSHR)) { | 2954 (op_kind() == Token::kSHR)) { |
| 2968 num_temps = 1; | 2955 num_temps = 1; |
| 2969 } else if ((op_kind() == Token::kMUL) && | 2956 } else if ((op_kind() == Token::kMUL) && |
| 2970 (TargetCPUFeatures::arm_version() != ARMv7)) { | 2957 (TargetCPUFeatures::arm_version() != ARMv7)) { |
| 2971 num_temps = 1; | 2958 num_temps = 1; |
| 2972 } | 2959 } |
| 2973 LocationSummary* summary = new(isolate) LocationSummary( | 2960 LocationSummary* summary = new(isolate) LocationSummary( |
| 2974 isolate, kNumInputs, num_temps, LocationSummary::kNoCall); | 2961 isolate, kNumInputs, num_temps, LocationSummary::kNoCall); |
| 2975 if (op_kind() == Token::kTRUNCDIV) { | 2962 if (op_kind() == Token::kTRUNCDIV) { |
| 2976 summary->set_in(0, Location::RequiresRegister()); | 2963 summary->set_in(0, Location::RequiresRegister()); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 2989 if (op_kind() == Token::kMOD) { | 2976 if (op_kind() == Token::kMOD) { |
| 2990 summary->set_in(0, Location::RequiresRegister()); | 2977 summary->set_in(0, Location::RequiresRegister()); |
| 2991 summary->set_in(1, Location::RequiresRegister()); | 2978 summary->set_in(1, Location::RequiresRegister()); |
| 2992 summary->set_temp(0, Location::RequiresRegister()); | 2979 summary->set_temp(0, Location::RequiresRegister()); |
| 2993 summary->set_temp(1, Location::RequiresFpuRegister()); | 2980 summary->set_temp(1, Location::RequiresFpuRegister()); |
| 2994 summary->set_out(0, Location::RequiresRegister()); | 2981 summary->set_out(0, Location::RequiresRegister()); |
| 2995 return summary; | 2982 return summary; |
| 2996 } | 2983 } |
| 2997 summary->set_in(0, Location::RequiresRegister()); | 2984 summary->set_in(0, Location::RequiresRegister()); |
| 2998 summary->set_in(1, Location::RegisterOrSmiConstant(right())); | 2985 summary->set_in(1, Location::RegisterOrSmiConstant(right())); |
| 2999 if (((op_kind() == Token::kSHL) && !IsTruncating()) || | 2986 if (((op_kind() == Token::kSHL) && can_overflow()) || |
| 3000 (op_kind() == Token::kSHR)) { | 2987 (op_kind() == Token::kSHR)) { |
| 3001 summary->set_temp(0, Location::RequiresRegister()); | 2988 summary->set_temp(0, Location::RequiresRegister()); |
| 3002 } | 2989 } |
| 3003 if (op_kind() == Token::kMUL) { | 2990 if (op_kind() == Token::kMUL) { |
| 3004 if (TargetCPUFeatures::arm_version() != ARMv7) { | 2991 if (TargetCPUFeatures::arm_version() != ARMv7) { |
| 3005 summary->set_temp(0, Location::RequiresFpuRegister()); | 2992 summary->set_temp(0, Location::RequiresFpuRegister()); |
| 3006 } | 2993 } |
| 3007 } | 2994 } |
| 3008 // We make use of 3-operand instructions by not requiring result register | 2995 // We make use of 3-operand instructions by not requiring result register |
| 3009 // to be identical to first input register as on Intel. | 2996 // to be identical to first input register as on Intel. |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3047 // overflow when imm == kMinInt32. | 3034 // overflow when imm == kMinInt32. |
| 3048 __ SubImmediateSetFlags(result, left, imm); | 3035 __ SubImmediateSetFlags(result, left, imm); |
| 3049 __ b(deopt, VS); | 3036 __ b(deopt, VS); |
| 3050 } | 3037 } |
| 3051 break; | 3038 break; |
| 3052 } | 3039 } |
| 3053 case Token::kMUL: { | 3040 case Token::kMUL: { |
| 3054 // Keep left value tagged and untag right value. | 3041 // Keep left value tagged and untag right value. |
| 3055 const intptr_t value = Smi::Cast(constant).Value(); | 3042 const intptr_t value = Smi::Cast(constant).Value(); |
| 3056 if (deopt == NULL) { | 3043 if (deopt == NULL) { |
| 3057 if (value == 2) { | 3044 __ LoadImmediate(IP, value); |
| 3058 __ mov(result, Operand(left, LSL, 1)); | 3045 __ mul(result, left, IP); |
| 3059 } else { | 3046 } else { |
| 3047 if (TargetCPUFeatures::arm_version() == ARMv7) { |
| 3060 __ LoadImmediate(IP, value); | 3048 __ LoadImmediate(IP, value); |
| 3061 __ mul(result, left, IP); | 3049 __ smull(result, IP, left, IP); |
| 3062 } | |
| 3063 } else { | |
| 3064 if (value == 2) { | |
| 3065 __ mov(IP, Operand(left, ASR, 31)); // IP = sign of left. | |
| 3066 __ mov(result, Operand(left, LSL, 1)); | |
| 3067 // IP: result bits 32..63. | 3050 // IP: result bits 32..63. |
| 3068 __ cmp(IP, Operand(result, ASR, 31)); | 3051 __ cmp(IP, Operand(result, ASR, 31)); |
| 3069 __ b(deopt, NE); | 3052 __ b(deopt, NE); |
| 3053 } else if (TargetCPUFeatures::can_divide()) { |
| 3054 const QRegister qtmp = locs()->temp(0).fpu_reg(); |
| 3055 const DRegister dtmp0 = EvenDRegisterOf(qtmp); |
| 3056 const DRegister dtmp1 = OddDRegisterOf(qtmp); |
| 3057 __ LoadImmediate(IP, value); |
| 3058 __ CheckMultSignedOverflow(left, IP, result, dtmp0, dtmp1, deopt); |
| 3059 __ mul(result, left, IP); |
| 3070 } else { | 3060 } else { |
| 3071 if (TargetCPUFeatures::arm_version() == ARMv7) { | 3061 // TODO(vegorov): never emit this instruction if hardware does not |
| 3072 __ LoadImmediate(IP, value); | 3062 // support it! This will lead to deopt cycle penalizing the code. |
| 3073 __ smull(result, IP, left, IP); | 3063 __ b(deopt); |
| 3074 // IP: result bits 32..63. | |
| 3075 __ cmp(IP, Operand(result, ASR, 31)); | |
| 3076 __ b(deopt, NE); | |
| 3077 } else if (TargetCPUFeatures::can_divide()) { | |
| 3078 const QRegister qtmp = locs()->temp(0).fpu_reg(); | |
| 3079 const DRegister dtmp0 = EvenDRegisterOf(qtmp); | |
| 3080 const DRegister dtmp1 = OddDRegisterOf(qtmp); | |
| 3081 __ LoadImmediate(IP, value); | |
| 3082 __ CheckMultSignedOverflow(left, IP, result, dtmp0, dtmp1, deopt); | |
| 3083 __ mul(result, left, IP); | |
| 3084 } else { | |
| 3085 // TODO(vegorov): never emit this instruction if hardware does not | |
| 3086 // support it! This will lead to deopt cycle penalizing the code. | |
| 3087 __ b(deopt); | |
| 3088 } | |
| 3089 } | 3064 } |
| 3090 } | 3065 } |
| 3091 break; | 3066 break; |
| 3092 } | 3067 } |
| 3093 case Token::kTRUNCDIV: { | 3068 case Token::kTRUNCDIV: { |
| 3094 const intptr_t value = Smi::Cast(constant).Value(); | 3069 const intptr_t value = Smi::Cast(constant).Value(); |
| 3095 if (value == 1) { | |
| 3096 __ MoveRegister(result, left); | |
| 3097 break; | |
| 3098 } else if (value == -1) { | |
| 3099 // Check the corner case of dividing the 'MIN_SMI' with -1, in which | |
| 3100 // case we cannot negate the result. | |
| 3101 __ CompareImmediate(left, 0x80000000); | |
| 3102 __ b(deopt, EQ); | |
| 3103 __ rsb(result, left, Operand(0)); | |
| 3104 break; | |
| 3105 } | |
| 3106 ASSERT(Utils::IsPowerOfTwo(Utils::Abs(value))); | 3070 ASSERT(Utils::IsPowerOfTwo(Utils::Abs(value))); |
| 3107 const intptr_t shift_count = | 3071 const intptr_t shift_count = |
| 3108 Utils::ShiftForPowerOfTwo(Utils::Abs(value)) + kSmiTagSize; | 3072 Utils::ShiftForPowerOfTwo(Utils::Abs(value)) + kSmiTagSize; |
| 3109 ASSERT(kSmiTagSize == 1); | 3073 ASSERT(kSmiTagSize == 1); |
| 3110 __ mov(IP, Operand(left, ASR, 31)); | 3074 __ mov(IP, Operand(left, ASR, 31)); |
| 3111 ASSERT(shift_count > 1); // 1, -1 case handled above. | 3075 ASSERT(shift_count > 1); // 1, -1 case handled above. |
| 3112 const Register temp = locs()->temp(0).reg(); | 3076 const Register temp = locs()->temp(0).reg(); |
| 3113 __ add(temp, left, Operand(IP, LSR, 32 - shift_count)); | 3077 __ add(temp, left, Operand(IP, LSR, 32 - shift_count)); |
| 3114 ASSERT(shift_count > 0); | 3078 ASSERT(shift_count > 0); |
| 3115 __ mov(result, Operand(temp, ASR, shift_count)); | 3079 __ mov(result, Operand(temp, ASR, shift_count)); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3151 } else { | 3115 } else { |
| 3152 __ LoadImmediate(IP, imm); | 3116 __ LoadImmediate(IP, imm); |
| 3153 __ eor(result, left, Operand(IP)); | 3117 __ eor(result, left, Operand(IP)); |
| 3154 } | 3118 } |
| 3155 break; | 3119 break; |
| 3156 } | 3120 } |
| 3157 case Token::kSHR: { | 3121 case Token::kSHR: { |
| 3158 // sarl operation masks the count to 5 bits. | 3122 // sarl operation masks the count to 5 bits. |
| 3159 const intptr_t kCountLimit = 0x1F; | 3123 const intptr_t kCountLimit = 0x1F; |
| 3160 intptr_t value = Smi::Cast(constant).Value(); | 3124 intptr_t value = Smi::Cast(constant).Value(); |
| 3161 | 3125 __ Asr(result, left, Utils::Minimum(value + kSmiTagSize, kCountLimit)); |
| 3162 if (value == 0) { | |
| 3163 // TODO(vegorov): should be handled outside. | |
| 3164 __ MoveRegister(result, left); | |
| 3165 break; | |
| 3166 } else if (value < 0) { | |
| 3167 // TODO(vegorov): should be handled outside. | |
| 3168 __ b(deopt); | |
| 3169 break; | |
| 3170 } | |
| 3171 | |
| 3172 value = value + kSmiTagSize; | |
| 3173 if (value >= kCountLimit) { | |
| 3174 value = kCountLimit; | |
| 3175 } | |
| 3176 | |
| 3177 __ Asr(result, left, value); | |
| 3178 __ SmiTag(result); | 3126 __ SmiTag(result); |
| 3179 break; | 3127 break; |
| 3180 } | 3128 } |
| 3181 | 3129 |
| 3182 default: | 3130 default: |
| 3183 UNREACHABLE(); | 3131 UNREACHABLE(); |
| 3184 break; | 3132 break; |
| 3185 } | 3133 } |
| 3186 return; | 3134 return; |
| 3187 } | 3135 } |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3343 } | 3291 } |
| 3344 default: | 3292 default: |
| 3345 UNREACHABLE(); | 3293 UNREACHABLE(); |
| 3346 break; | 3294 break; |
| 3347 } | 3295 } |
| 3348 } | 3296 } |
| 3349 | 3297 |
| 3350 | 3298 |
| 3351 static void EmitInt32ShiftLeft(FlowGraphCompiler* compiler, | 3299 static void EmitInt32ShiftLeft(FlowGraphCompiler* compiler, |
| 3352 BinaryInt32OpInstr* shift_left) { | 3300 BinaryInt32OpInstr* shift_left) { |
| 3353 const bool is_truncating = shift_left->IsTruncating(); | |
| 3354 const LocationSummary& locs = *shift_left->locs(); | 3301 const LocationSummary& locs = *shift_left->locs(); |
| 3355 const Register left = locs.in(0).reg(); | 3302 const Register left = locs.in(0).reg(); |
| 3356 const Register result = locs.out(0).reg(); | 3303 const Register result = locs.out(0).reg(); |
| 3357 Label* deopt = shift_left->CanDeoptimize() ? | 3304 Label* deopt = shift_left->CanDeoptimize() ? |
| 3358 compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp) | 3305 compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp) |
| 3359 : NULL; | 3306 : NULL; |
| 3360 ASSERT(locs.in(1).IsConstant()); | 3307 ASSERT(locs.in(1).IsConstant()); |
| 3361 const Object& constant = locs.in(1).constant(); | 3308 const Object& constant = locs.in(1).constant(); |
| 3362 ASSERT(constant.IsSmi()); | 3309 ASSERT(constant.IsSmi()); |
| 3363 // Immediate shift operation takes 5 bits for the count. | 3310 // Immediate shift operation takes 5 bits for the count. |
| 3364 const intptr_t kCountLimit = 0x1F; | 3311 const intptr_t kCountLimit = 0x1F; |
| 3365 const intptr_t value = Smi::Cast(constant).Value(); | 3312 const intptr_t value = Smi::Cast(constant).Value(); |
| 3366 if (value == 0) { | 3313 ASSERT((0 < value) && (value < kCountLimit)); |
| 3367 __ MoveRegister(result, left); | 3314 if (shift_left->can_overflow()) { |
| 3368 } else if ((value < 0) || (value >= kCountLimit)) { | 3315 // Check for overflow (preserve left). |
| 3369 // This condition may not be known earlier in some cases because | 3316 __ Lsl(IP, left, value); |
| 3370 // of constant propagation, inlining, etc. | 3317 __ cmp(left, Operand(IP, ASR, value)); |
| 3371 if ((value >= kCountLimit) && is_truncating) { | 3318 __ b(deopt, NE); // Overflow. |
| 3372 __ mov(result, Operand(0)); | |
| 3373 } else { | |
| 3374 // Result is Mint or exception. | |
| 3375 __ b(deopt); | |
| 3376 } | |
| 3377 } else { | |
| 3378 if (!is_truncating) { | |
| 3379 // Check for overflow (preserve left). | |
| 3380 __ Lsl(IP, left, value); | |
| 3381 __ cmp(left, Operand(IP, ASR, value)); | |
| 3382 __ b(deopt, NE); // Overflow. | |
| 3383 } | |
| 3384 // Shift for result now we know there is no overflow. | |
| 3385 __ Lsl(result, left, value); | |
| 3386 } | 3319 } |
| 3320 // Shift for result now we know there is no overflow. |
| 3321 __ Lsl(result, left, value); |
| 3387 } | 3322 } |
| 3388 | 3323 |
| 3389 | 3324 |
| 3390 LocationSummary* BinaryInt32OpInstr::MakeLocationSummary(Isolate* isolate, | 3325 LocationSummary* BinaryInt32OpInstr::MakeLocationSummary(Isolate* isolate, |
| 3391 bool opt) const { | 3326 bool opt) const { |
| 3392 const intptr_t kNumInputs = 2; | 3327 const intptr_t kNumInputs = 2; |
| 3393 // Calculate number of temporaries. | 3328 // Calculate number of temporaries. |
| 3394 intptr_t num_temps = 0; | 3329 intptr_t num_temps = 0; |
| 3395 if (((op_kind() == Token::kSHL) && !IsTruncating()) || | 3330 if (((op_kind() == Token::kSHL) && can_overflow()) || |
| 3396 (op_kind() == Token::kSHR)) { | 3331 (op_kind() == Token::kSHR)) { |
| 3397 num_temps = 1; | 3332 num_temps = 1; |
| 3398 } else if ((op_kind() == Token::kMUL) && | 3333 } else if ((op_kind() == Token::kMUL) && |
| 3399 (TargetCPUFeatures::arm_version() != ARMv7)) { | 3334 (TargetCPUFeatures::arm_version() != ARMv7)) { |
| 3400 num_temps = 1; | 3335 num_temps = 1; |
| 3401 } | 3336 } |
| 3402 LocationSummary* summary = new(isolate) LocationSummary( | 3337 LocationSummary* summary = new(isolate) LocationSummary( |
| 3403 isolate, kNumInputs, num_temps, LocationSummary::kNoCall); | 3338 isolate, kNumInputs, num_temps, LocationSummary::kNoCall); |
| 3404 summary->set_in(0, Location::RequiresRegister()); | 3339 summary->set_in(0, Location::RequiresRegister()); |
| 3405 summary->set_in(1, Location::RegisterOrSmiConstant(right())); | 3340 summary->set_in(1, Location::RegisterOrSmiConstant(right())); |
| 3406 if (((op_kind() == Token::kSHL) && !IsTruncating()) || | 3341 if (((op_kind() == Token::kSHL) && can_overflow()) || |
| 3407 (op_kind() == Token::kSHR)) { | 3342 (op_kind() == Token::kSHR)) { |
| 3408 summary->set_temp(0, Location::RequiresRegister()); | 3343 summary->set_temp(0, Location::RequiresRegister()); |
| 3409 } | 3344 } |
| 3410 if (op_kind() == Token::kMUL) { | 3345 if (op_kind() == Token::kMUL) { |
| 3411 if (TargetCPUFeatures::arm_version() != ARMv7) { | 3346 if (TargetCPUFeatures::arm_version() != ARMv7) { |
| 3412 summary->set_temp(0, Location::RequiresFpuRegister()); | 3347 summary->set_temp(0, Location::RequiresFpuRegister()); |
| 3413 } | 3348 } |
| 3414 } | 3349 } |
| 3415 // We make use of 3-operand instructions by not requiring result register | 3350 // We make use of 3-operand instructions by not requiring result register |
| 3416 // to be identical to first input register as on Intel. | 3351 // to be identical to first input register as on Intel. |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3452 } else { | 3387 } else { |
| 3453 // Negating value and using AddImmediateSetFlags would not detect the | 3388 // Negating value and using AddImmediateSetFlags would not detect the |
| 3454 // overflow when value == kMinInt32. | 3389 // overflow when value == kMinInt32. |
| 3455 __ SubImmediateSetFlags(result, left, value); | 3390 __ SubImmediateSetFlags(result, left, value); |
| 3456 __ b(deopt, VS); | 3391 __ b(deopt, VS); |
| 3457 } | 3392 } |
| 3458 break; | 3393 break; |
| 3459 } | 3394 } |
| 3460 case Token::kMUL: { | 3395 case Token::kMUL: { |
| 3461 if (deopt == NULL) { | 3396 if (deopt == NULL) { |
| 3462 if (value == 2) { | 3397 __ LoadImmediate(IP, value); |
| 3463 __ mov(result, Operand(left, LSL, 1)); | 3398 __ mul(result, left, IP); |
| 3399 } else { |
| 3400 if (TargetCPUFeatures::arm_version() == ARMv7) { |
| 3401 __ LoadImmediate(IP, value); |
| 3402 __ smull(result, IP, left, IP); |
| 3403 // IP: result bits 32..63. |
| 3404 __ cmp(IP, Operand(result, ASR, 31)); |
| 3405 __ b(deopt, NE); |
| 3406 } else if (TargetCPUFeatures::can_divide()) { |
| 3407 const QRegister qtmp = locs()->temp(0).fpu_reg(); |
| 3408 const DRegister dtmp0 = EvenDRegisterOf(qtmp); |
| 3409 const DRegister dtmp1 = OddDRegisterOf(qtmp); |
| 3410 __ LoadImmediate(IP, value); |
| 3411 __ CheckMultSignedOverflow(left, IP, result, dtmp0, dtmp1, deopt); |
| 3412 __ mul(result, left, IP); |
| 3464 } else { | 3413 } else { |
| 3465 __ LoadImmediate(IP, value); | 3414 // TODO(vegorov): never emit this instruction if hardware does not |
| 3466 __ mul(result, left, IP); | 3415 // support it! This will lead to deopt cycle penalizing the code. |
| 3467 } | 3416 __ b(deopt); |
| 3468 } else { | |
| 3469 if (value == 2) { | |
| 3470 __ CompareImmediate(left, 0xC0000000); | |
| 3471 __ b(deopt, MI); | |
| 3472 __ mov(result, Operand(left, LSL, 1)); | |
| 3473 } else { | |
| 3474 if (TargetCPUFeatures::arm_version() == ARMv7) { | |
| 3475 __ LoadImmediate(IP, value); | |
| 3476 __ smull(result, IP, left, IP); | |
| 3477 // IP: result bits 32..63. | |
| 3478 __ cmp(IP, Operand(result, ASR, 31)); | |
| 3479 __ b(deopt, NE); | |
| 3480 } else if (TargetCPUFeatures::can_divide()) { | |
| 3481 const QRegister qtmp = locs()->temp(0).fpu_reg(); | |
| 3482 const DRegister dtmp0 = EvenDRegisterOf(qtmp); | |
| 3483 const DRegister dtmp1 = OddDRegisterOf(qtmp); | |
| 3484 __ LoadImmediate(IP, value); | |
| 3485 __ CheckMultSignedOverflow(left, IP, result, dtmp0, dtmp1, deopt); | |
| 3486 __ mul(result, left, IP); | |
| 3487 } else { | |
| 3488 // TODO(vegorov): never emit this instruction if hardware does not | |
| 3489 // support it! This will lead to deopt cycle penalizing the code. | |
| 3490 __ b(deopt); | |
| 3491 } | |
| 3492 } | 3417 } |
| 3493 } | 3418 } |
| 3494 break; | 3419 break; |
| 3495 } | 3420 } |
| 3496 case Token::kBIT_AND: { | 3421 case Token::kBIT_AND: { |
| 3497 // No overflow check. | 3422 // No overflow check. |
| 3498 Operand o; | 3423 Operand o; |
| 3499 if (Operand::CanHold(value, &o)) { | 3424 if (Operand::CanHold(value, &o)) { |
| 3500 __ and_(result, left, o); | 3425 __ and_(result, left, o); |
| 3501 } else if (Operand::CanHold(~value, &o)) { | 3426 } else if (Operand::CanHold(~value, &o)) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 3524 __ eor(result, left, o); | 3449 __ eor(result, left, o); |
| 3525 } else { | 3450 } else { |
| 3526 __ LoadImmediate(IP, value); | 3451 __ LoadImmediate(IP, value); |
| 3527 __ eor(result, left, Operand(IP)); | 3452 __ eor(result, left, Operand(IP)); |
| 3528 } | 3453 } |
| 3529 break; | 3454 break; |
| 3530 } | 3455 } |
| 3531 case Token::kSHR: { | 3456 case Token::kSHR: { |
| 3532 // sarl operation masks the count to 5 bits. | 3457 // sarl operation masks the count to 5 bits. |
| 3533 const intptr_t kCountLimit = 0x1F; | 3458 const intptr_t kCountLimit = 0x1F; |
| 3534 | 3459 __ Asr(result, left, Utils::Minimum(value, kCountLimit)); |
| 3535 if (value == 0) { | |
| 3536 // TODO(vegorov): should be handled outside. | |
| 3537 __ MoveRegister(result, left); | |
| 3538 break; | |
| 3539 } else if (value < 0) { | |
| 3540 // TODO(vegorov): should be handled outside. | |
| 3541 __ b(deopt); | |
| 3542 break; | |
| 3543 } | |
| 3544 | |
| 3545 if (value >= kCountLimit) { | |
| 3546 __ Asr(result, left, kCountLimit); | |
| 3547 } else { | |
| 3548 __ Asr(result, left, value); | |
| 3549 } | |
| 3550 break; | 3460 break; |
| 3551 } | 3461 } |
| 3552 | 3462 |
| 3553 default: | 3463 default: |
| 3554 UNREACHABLE(); | 3464 UNREACHABLE(); |
| 3555 break; | 3465 break; |
| 3556 } | 3466 } |
| 3557 return; | 3467 return; |
| 3558 } | 3468 } |
| 3559 | 3469 |
| (...skipping 3573 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7133 compiler->GenerateCall(token_pos(), &label, stub_kind_, locs()); | 7043 compiler->GenerateCall(token_pos(), &label, stub_kind_, locs()); |
| 7134 #if defined(DEBUG) | 7044 #if defined(DEBUG) |
| 7135 __ LoadImmediate(R4, kInvalidObjectPointer); | 7045 __ LoadImmediate(R4, kInvalidObjectPointer); |
| 7136 __ LoadImmediate(R5, kInvalidObjectPointer); | 7046 __ LoadImmediate(R5, kInvalidObjectPointer); |
| 7137 #endif | 7047 #endif |
| 7138 } | 7048 } |
| 7139 | 7049 |
| 7140 } // namespace dart | 7050 } // namespace dart |
| 7141 | 7051 |
| 7142 #endif // defined TARGET_ARCH_ARM | 7052 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |