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

Side by Side Diff: runtime/vm/intermediate_language_arm.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_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
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698