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 3036 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3047 if (RightIsPowerOfTwoConstant()) { | 3047 if (RightIsPowerOfTwoConstant()) { |
3048 num_temps = 1; | 3048 num_temps = 1; |
3049 } else { | 3049 } else { |
3050 num_temps = 2; | 3050 num_temps = 2; |
3051 } | 3051 } |
3052 } else if (op_kind() == Token::kMOD) { | 3052 } else if (op_kind() == Token::kMOD) { |
3053 num_temps = 2; | 3053 num_temps = 2; |
3054 } else if (((op_kind() == Token::kSHL) && can_overflow()) || | 3054 } else if (((op_kind() == Token::kSHL) && can_overflow()) || |
3055 (op_kind() == Token::kSHR)) { | 3055 (op_kind() == Token::kSHR)) { |
3056 num_temps = 1; | 3056 num_temps = 1; |
3057 } else if ((op_kind() == Token::kMUL) && | |
3058 (TargetCPUFeatures::arm_version() != ARMv7)) { | |
3059 num_temps = 1; | |
3060 } | 3057 } |
3061 LocationSummary* summary = new(zone) LocationSummary( | 3058 LocationSummary* summary = new(zone) LocationSummary( |
3062 zone, kNumInputs, num_temps, LocationSummary::kNoCall); | 3059 zone, kNumInputs, num_temps, LocationSummary::kNoCall); |
3063 if (op_kind() == Token::kTRUNCDIV) { | 3060 if (op_kind() == Token::kTRUNCDIV) { |
3064 summary->set_in(0, Location::RequiresRegister()); | 3061 summary->set_in(0, Location::RequiresRegister()); |
3065 if (RightIsPowerOfTwoConstant()) { | 3062 if (RightIsPowerOfTwoConstant()) { |
3066 ConstantInstr* right_constant = right()->definition()->AsConstant(); | 3063 ConstantInstr* right_constant = right()->definition()->AsConstant(); |
3067 summary->set_in(1, Location::Constant(right_constant)); | 3064 summary->set_in(1, Location::Constant(right_constant)); |
3068 summary->set_temp(0, Location::RequiresRegister()); | 3065 summary->set_temp(0, Location::RequiresRegister()); |
3069 } else { | 3066 } else { |
(...skipping 11 matching lines...) Expand all Loading... |
3081 summary->set_temp(1, Location::RequiresFpuRegister()); | 3078 summary->set_temp(1, Location::RequiresFpuRegister()); |
3082 summary->set_out(0, Location::RequiresRegister()); | 3079 summary->set_out(0, Location::RequiresRegister()); |
3083 return summary; | 3080 return summary; |
3084 } | 3081 } |
3085 summary->set_in(0, Location::RequiresRegister()); | 3082 summary->set_in(0, Location::RequiresRegister()); |
3086 summary->set_in(1, Location::RegisterOrSmiConstant(right())); | 3083 summary->set_in(1, Location::RegisterOrSmiConstant(right())); |
3087 if (((op_kind() == Token::kSHL) && can_overflow()) || | 3084 if (((op_kind() == Token::kSHL) && can_overflow()) || |
3088 (op_kind() == Token::kSHR)) { | 3085 (op_kind() == Token::kSHR)) { |
3089 summary->set_temp(0, Location::RequiresRegister()); | 3086 summary->set_temp(0, Location::RequiresRegister()); |
3090 } | 3087 } |
3091 if (op_kind() == Token::kMUL) { | |
3092 if (TargetCPUFeatures::arm_version() != ARMv7) { | |
3093 summary->set_temp(0, Location::RequiresFpuRegister()); | |
3094 } | |
3095 } | |
3096 // We make use of 3-operand instructions by not requiring result register | 3088 // We make use of 3-operand instructions by not requiring result register |
3097 // to be identical to first input register as on Intel. | 3089 // to be identical to first input register as on Intel. |
3098 summary->set_out(0, Location::RequiresRegister()); | 3090 summary->set_out(0, Location::RequiresRegister()); |
3099 return summary; | 3091 return summary; |
3100 } | 3092 } |
3101 | 3093 |
3102 | 3094 |
3103 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3095 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3104 if (op_kind() == Token::kSHL) { | 3096 if (op_kind() == Token::kSHL) { |
3105 EmitSmiShiftLeft(compiler, this); | 3097 EmitSmiShiftLeft(compiler, this); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3138 } | 3130 } |
3139 break; | 3131 break; |
3140 } | 3132 } |
3141 case Token::kMUL: { | 3133 case Token::kMUL: { |
3142 // Keep left value tagged and untag right value. | 3134 // Keep left value tagged and untag right value. |
3143 const intptr_t value = Smi::Cast(constant).Value(); | 3135 const intptr_t value = Smi::Cast(constant).Value(); |
3144 if (deopt == NULL) { | 3136 if (deopt == NULL) { |
3145 __ LoadImmediate(IP, value); | 3137 __ LoadImmediate(IP, value); |
3146 __ mul(result, left, IP); | 3138 __ mul(result, left, IP); |
3147 } else { | 3139 } else { |
3148 if (TargetCPUFeatures::arm_version() == ARMv7) { | 3140 __ LoadImmediate(IP, value); |
3149 __ LoadImmediate(IP, value); | 3141 __ smull(result, IP, left, IP); |
3150 __ smull(result, IP, left, IP); | 3142 // IP: result bits 32..63. |
3151 // IP: result bits 32..63. | 3143 __ cmp(IP, Operand(result, ASR, 31)); |
3152 __ cmp(IP, Operand(result, ASR, 31)); | 3144 __ b(deopt, NE); |
3153 __ b(deopt, NE); | |
3154 } else if (TargetCPUFeatures::can_divide()) { | |
3155 const QRegister qtmp = locs()->temp(0).fpu_reg(); | |
3156 const DRegister dtmp0 = EvenDRegisterOf(qtmp); | |
3157 const DRegister dtmp1 = OddDRegisterOf(qtmp); | |
3158 __ LoadImmediate(IP, value); | |
3159 __ CheckMultSignedOverflow(left, IP, result, dtmp0, dtmp1, deopt); | |
3160 __ mul(result, left, IP); | |
3161 } else { | |
3162 // TODO(vegorov): never emit this instruction if hardware does not | |
3163 // support it! This will lead to deopt cycle penalizing the code. | |
3164 __ b(deopt); | |
3165 } | |
3166 } | 3145 } |
3167 break; | 3146 break; |
3168 } | 3147 } |
3169 case Token::kTRUNCDIV: { | 3148 case Token::kTRUNCDIV: { |
3170 const intptr_t value = Smi::Cast(constant).Value(); | 3149 const intptr_t value = Smi::Cast(constant).Value(); |
3171 ASSERT(Utils::IsPowerOfTwo(Utils::Abs(value))); | 3150 ASSERT(Utils::IsPowerOfTwo(Utils::Abs(value))); |
3172 const intptr_t shift_count = | 3151 const intptr_t shift_count = |
3173 Utils::ShiftForPowerOfTwo(Utils::Abs(value)) + kSmiTagSize; | 3152 Utils::ShiftForPowerOfTwo(Utils::Abs(value)) + kSmiTagSize; |
3174 ASSERT(kSmiTagSize == 1); | 3153 ASSERT(kSmiTagSize == 1); |
3175 __ mov(IP, Operand(left, ASR, 31)); | 3154 __ mov(IP, Operand(left, ASR, 31)); |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3255 __ subs(result, left, Operand(right)); | 3234 __ subs(result, left, Operand(right)); |
3256 __ b(deopt, VS); | 3235 __ b(deopt, VS); |
3257 } | 3236 } |
3258 break; | 3237 break; |
3259 } | 3238 } |
3260 case Token::kMUL: { | 3239 case Token::kMUL: { |
3261 __ SmiUntag(IP, left); | 3240 __ SmiUntag(IP, left); |
3262 if (deopt == NULL) { | 3241 if (deopt == NULL) { |
3263 __ mul(result, IP, right); | 3242 __ mul(result, IP, right); |
3264 } else { | 3243 } else { |
3265 if (TargetCPUFeatures::arm_version() == ARMv7) { | 3244 __ smull(result, IP, IP, right); |
3266 __ smull(result, IP, IP, right); | 3245 // IP: result bits 32..63. |
3267 // IP: result bits 32..63. | 3246 __ cmp(IP, Operand(result, ASR, 31)); |
3268 __ cmp(IP, Operand(result, ASR, 31)); | 3247 __ b(deopt, NE); |
3269 __ b(deopt, NE); | |
3270 } else if (TargetCPUFeatures::can_divide()) { | |
3271 const QRegister qtmp = locs()->temp(0).fpu_reg(); | |
3272 const DRegister dtmp0 = EvenDRegisterOf(qtmp); | |
3273 const DRegister dtmp1 = OddDRegisterOf(qtmp); | |
3274 __ CheckMultSignedOverflow(IP, right, result, dtmp0, dtmp1, deopt); | |
3275 __ mul(result, IP, right); | |
3276 } else { | |
3277 // TODO(vegorov): never emit this instruction if hardware does not | |
3278 // support it! This will lead to deopt cycle penalizing the code. | |
3279 __ b(deopt); | |
3280 } | |
3281 } | 3248 } |
3282 break; | 3249 break; |
3283 } | 3250 } |
3284 case Token::kBIT_AND: { | 3251 case Token::kBIT_AND: { |
3285 // No overflow check. | 3252 // No overflow check. |
3286 __ and_(result, left, Operand(right)); | 3253 __ and_(result, left, Operand(right)); |
3287 break; | 3254 break; |
3288 } | 3255 } |
3289 case Token::kBIT_OR: { | 3256 case Token::kBIT_OR: { |
3290 // No overflow check. | 3257 // No overflow check. |
3291 __ orr(result, left, Operand(right)); | 3258 __ orr(result, left, Operand(right)); |
3292 break; | 3259 break; |
3293 } | 3260 } |
3294 case Token::kBIT_XOR: { | 3261 case Token::kBIT_XOR: { |
3295 // No overflow check. | 3262 // No overflow check. |
3296 __ eor(result, left, Operand(right)); | 3263 __ eor(result, left, Operand(right)); |
3297 break; | 3264 break; |
3298 } | 3265 } |
3299 case Token::kTRUNCDIV: { | 3266 case Token::kTRUNCDIV: { |
| 3267 ASSERT(TargetCPUFeatures::can_divide()); |
3300 if ((right_range == NULL) || right_range->Overlaps(0, 0)) { | 3268 if ((right_range == NULL) || right_range->Overlaps(0, 0)) { |
3301 // Handle divide by zero in runtime. | 3269 // Handle divide by zero in runtime. |
3302 __ cmp(right, Operand(0)); | 3270 __ cmp(right, Operand(0)); |
3303 __ b(deopt, EQ); | 3271 __ b(deopt, EQ); |
3304 } | 3272 } |
3305 const Register temp = locs()->temp(0).reg(); | 3273 const Register temp = locs()->temp(0).reg(); |
3306 if (TargetCPUFeatures::can_divide()) { | 3274 const DRegister dtemp = EvenDRegisterOf(locs()->temp(1).fpu_reg()); |
3307 const DRegister dtemp = EvenDRegisterOf(locs()->temp(1).fpu_reg()); | 3275 __ SmiUntag(temp, left); |
3308 __ SmiUntag(temp, left); | 3276 __ SmiUntag(IP, right); |
3309 __ SmiUntag(IP, right); | 3277 __ IntegerDivide(result, temp, IP, dtemp, DTMP); |
3310 __ IntegerDivide(result, temp, IP, dtemp, DTMP); | |
3311 } else { | |
3312 // TODO(vegorov): never emit this instruction if hardware does not | |
3313 // support it! This will lead to deopt cycle penalizing the code. | |
3314 __ b(deopt); | |
3315 } | |
3316 | 3278 |
3317 // Check the corner case of dividing the 'MIN_SMI' with -1, in which | 3279 // Check the corner case of dividing the 'MIN_SMI' with -1, in which |
3318 // case we cannot tag the result. | 3280 // case we cannot tag the result. |
3319 __ CompareImmediate(result, 0x40000000); | 3281 __ CompareImmediate(result, 0x40000000); |
3320 __ b(deopt, EQ); | 3282 __ b(deopt, EQ); |
3321 __ SmiTag(result); | 3283 __ SmiTag(result); |
3322 break; | 3284 break; |
3323 } | 3285 } |
3324 case Token::kMOD: { | 3286 case Token::kMOD: { |
| 3287 ASSERT(TargetCPUFeatures::can_divide()); |
3325 if ((right_range == NULL) || right_range->Overlaps(0, 0)) { | 3288 if ((right_range == NULL) || right_range->Overlaps(0, 0)) { |
3326 // Handle divide by zero in runtime. | 3289 // Handle divide by zero in runtime. |
3327 __ cmp(right, Operand(0)); | 3290 __ cmp(right, Operand(0)); |
3328 __ b(deopt, EQ); | 3291 __ b(deopt, EQ); |
3329 } | 3292 } |
3330 const Register temp = locs()->temp(0).reg(); | 3293 const Register temp = locs()->temp(0).reg(); |
3331 if (TargetCPUFeatures::can_divide()) { | 3294 const DRegister dtemp = EvenDRegisterOf(locs()->temp(1).fpu_reg()); |
3332 const DRegister dtemp = EvenDRegisterOf(locs()->temp(1).fpu_reg()); | 3295 __ SmiUntag(temp, left); |
3333 __ SmiUntag(temp, left); | 3296 __ SmiUntag(IP, right); |
3334 __ SmiUntag(IP, right); | 3297 __ IntegerDivide(result, temp, IP, dtemp, DTMP); |
3335 __ IntegerDivide(result, temp, IP, dtemp, DTMP); | |
3336 } else { | |
3337 // TODO(vegorov): never emit this instruction if hardware does not | |
3338 // support it! This will lead to deopt cycle penalizing the code. | |
3339 __ b(deopt); | |
3340 } | |
3341 __ SmiUntag(IP, right); | 3298 __ SmiUntag(IP, right); |
3342 __ mls(result, IP, result, temp); // result <- left - right * result | 3299 __ mls(result, IP, result, temp); // result <- left - right * result |
3343 __ SmiTag(result); | 3300 __ SmiTag(result); |
3344 // res = left % right; | 3301 // res = left % right; |
3345 // if (res < 0) { | 3302 // if (res < 0) { |
3346 // if (right < 0) { | 3303 // if (right < 0) { |
3347 // res = res - right; | 3304 // res = res - right; |
3348 // } else { | 3305 // } else { |
3349 // res = res + right; | 3306 // res = res + right; |
3350 // } | 3307 // } |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3425 | 3382 |
3426 | 3383 |
3427 LocationSummary* BinaryInt32OpInstr::MakeLocationSummary(Zone* zone, | 3384 LocationSummary* BinaryInt32OpInstr::MakeLocationSummary(Zone* zone, |
3428 bool opt) const { | 3385 bool opt) const { |
3429 const intptr_t kNumInputs = 2; | 3386 const intptr_t kNumInputs = 2; |
3430 // Calculate number of temporaries. | 3387 // Calculate number of temporaries. |
3431 intptr_t num_temps = 0; | 3388 intptr_t num_temps = 0; |
3432 if (((op_kind() == Token::kSHL) && can_overflow()) || | 3389 if (((op_kind() == Token::kSHL) && can_overflow()) || |
3433 (op_kind() == Token::kSHR)) { | 3390 (op_kind() == Token::kSHR)) { |
3434 num_temps = 1; | 3391 num_temps = 1; |
3435 } else if ((op_kind() == Token::kMUL) && | |
3436 (TargetCPUFeatures::arm_version() != ARMv7)) { | |
3437 num_temps = 1; | |
3438 } | 3392 } |
3439 LocationSummary* summary = new(zone) LocationSummary( | 3393 LocationSummary* summary = new(zone) LocationSummary( |
3440 zone, kNumInputs, num_temps, LocationSummary::kNoCall); | 3394 zone, kNumInputs, num_temps, LocationSummary::kNoCall); |
3441 summary->set_in(0, Location::RequiresRegister()); | 3395 summary->set_in(0, Location::RequiresRegister()); |
3442 summary->set_in(1, Location::RegisterOrSmiConstant(right())); | 3396 summary->set_in(1, Location::RegisterOrSmiConstant(right())); |
3443 if (((op_kind() == Token::kSHL) && can_overflow()) || | 3397 if (((op_kind() == Token::kSHL) && can_overflow()) || |
3444 (op_kind() == Token::kSHR)) { | 3398 (op_kind() == Token::kSHR)) { |
3445 summary->set_temp(0, Location::RequiresRegister()); | 3399 summary->set_temp(0, Location::RequiresRegister()); |
3446 } | 3400 } |
3447 if (op_kind() == Token::kMUL) { | |
3448 if (TargetCPUFeatures::arm_version() != ARMv7) { | |
3449 summary->set_temp(0, Location::RequiresFpuRegister()); | |
3450 } | |
3451 } | |
3452 // We make use of 3-operand instructions by not requiring result register | 3401 // We make use of 3-operand instructions by not requiring result register |
3453 // to be identical to first input register as on Intel. | 3402 // to be identical to first input register as on Intel. |
3454 summary->set_out(0, Location::RequiresRegister()); | 3403 summary->set_out(0, Location::RequiresRegister()); |
3455 return summary; | 3404 return summary; |
3456 } | 3405 } |
3457 | 3406 |
3458 | 3407 |
3459 void BinaryInt32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3408 void BinaryInt32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3460 if (op_kind() == Token::kSHL) { | 3409 if (op_kind() == Token::kSHL) { |
3461 EmitInt32ShiftLeft(compiler, this); | 3410 EmitInt32ShiftLeft(compiler, this); |
(...skipping 30 matching lines...) Expand all Loading... |
3492 __ SubImmediateSetFlags(result, left, value); | 3441 __ SubImmediateSetFlags(result, left, value); |
3493 __ b(deopt, VS); | 3442 __ b(deopt, VS); |
3494 } | 3443 } |
3495 break; | 3444 break; |
3496 } | 3445 } |
3497 case Token::kMUL: { | 3446 case Token::kMUL: { |
3498 if (deopt == NULL) { | 3447 if (deopt == NULL) { |
3499 __ LoadImmediate(IP, value); | 3448 __ LoadImmediate(IP, value); |
3500 __ mul(result, left, IP); | 3449 __ mul(result, left, IP); |
3501 } else { | 3450 } else { |
3502 if (TargetCPUFeatures::arm_version() == ARMv7) { | 3451 __ LoadImmediate(IP, value); |
3503 __ LoadImmediate(IP, value); | 3452 __ smull(result, IP, left, IP); |
3504 __ smull(result, IP, left, IP); | 3453 // IP: result bits 32..63. |
3505 // IP: result bits 32..63. | 3454 __ cmp(IP, Operand(result, ASR, 31)); |
3506 __ cmp(IP, Operand(result, ASR, 31)); | 3455 __ b(deopt, NE); |
3507 __ b(deopt, NE); | |
3508 } else if (TargetCPUFeatures::can_divide()) { | |
3509 const QRegister qtmp = locs()->temp(0).fpu_reg(); | |
3510 const DRegister dtmp0 = EvenDRegisterOf(qtmp); | |
3511 const DRegister dtmp1 = OddDRegisterOf(qtmp); | |
3512 __ LoadImmediate(IP, value); | |
3513 __ CheckMultSignedOverflow(left, IP, result, dtmp0, dtmp1, deopt); | |
3514 __ mul(result, left, IP); | |
3515 } else { | |
3516 // TODO(vegorov): never emit this instruction if hardware does not | |
3517 // support it! This will lead to deopt cycle penalizing the code. | |
3518 __ b(deopt); | |
3519 } | |
3520 } | 3456 } |
3521 break; | 3457 break; |
3522 } | 3458 } |
3523 case Token::kBIT_AND: { | 3459 case Token::kBIT_AND: { |
3524 // No overflow check. | 3460 // No overflow check. |
3525 Operand o; | 3461 Operand o; |
3526 if (Operand::CanHold(value, &o)) { | 3462 if (Operand::CanHold(value, &o)) { |
3527 __ and_(result, left, o); | 3463 __ and_(result, left, o); |
3528 } else if (Operand::CanHold(~value, &o)) { | 3464 } else if (Operand::CanHold(~value, &o)) { |
3529 __ bic(result, left, o); | 3465 __ bic(result, left, o); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3586 } else { | 3522 } else { |
3587 __ subs(result, left, Operand(right)); | 3523 __ subs(result, left, Operand(right)); |
3588 __ b(deopt, VS); | 3524 __ b(deopt, VS); |
3589 } | 3525 } |
3590 break; | 3526 break; |
3591 } | 3527 } |
3592 case Token::kMUL: { | 3528 case Token::kMUL: { |
3593 if (deopt == NULL) { | 3529 if (deopt == NULL) { |
3594 __ mul(result, left, right); | 3530 __ mul(result, left, right); |
3595 } else { | 3531 } else { |
3596 if (TargetCPUFeatures::arm_version() == ARMv7) { | 3532 __ smull(result, IP, left, right); |
3597 __ smull(result, IP, left, right); | 3533 // IP: result bits 32..63. |
3598 // IP: result bits 32..63. | 3534 __ cmp(IP, Operand(result, ASR, 31)); |
3599 __ cmp(IP, Operand(result, ASR, 31)); | 3535 __ b(deopt, NE); |
3600 __ b(deopt, NE); | |
3601 } else if (TargetCPUFeatures::can_divide()) { | |
3602 const QRegister qtmp = locs()->temp(0).fpu_reg(); | |
3603 const DRegister dtmp0 = EvenDRegisterOf(qtmp); | |
3604 const DRegister dtmp1 = OddDRegisterOf(qtmp); | |
3605 __ CheckMultSignedOverflow(left, right, result, dtmp0, dtmp1, deopt); | |
3606 __ mul(result, left, right); | |
3607 } else { | |
3608 // TODO(vegorov): never emit this instruction if hardware does not | |
3609 // support it! This will lead to deopt cycle penalizing the code. | |
3610 __ b(deopt); | |
3611 } | |
3612 } | 3536 } |
3613 break; | 3537 break; |
3614 } | 3538 } |
3615 case Token::kBIT_AND: { | 3539 case Token::kBIT_AND: { |
3616 // No overflow check. | 3540 // No overflow check. |
3617 __ and_(result, left, Operand(right)); | 3541 __ and_(result, left, Operand(right)); |
3618 break; | 3542 break; |
3619 } | 3543 } |
3620 case Token::kBIT_OR: { | 3544 case Token::kBIT_OR: { |
3621 // No overflow check. | 3545 // No overflow check. |
(...skipping 2251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5873 return NULL; | 5797 return NULL; |
5874 } | 5798 } |
5875 | 5799 |
5876 | 5800 |
5877 void MergedMathInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 5801 void MergedMathInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
5878 Label* deopt = NULL; | 5802 Label* deopt = NULL; |
5879 if (CanDeoptimize()) { | 5803 if (CanDeoptimize()) { |
5880 deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinarySmiOp); | 5804 deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinarySmiOp); |
5881 } | 5805 } |
5882 if (kind() == MergedMathInstr::kTruncDivMod) { | 5806 if (kind() == MergedMathInstr::kTruncDivMod) { |
| 5807 ASSERT(TargetCPUFeatures::can_divide()); |
5883 const Register left = locs()->in(0).reg(); | 5808 const Register left = locs()->in(0).reg(); |
5884 const Register right = locs()->in(1).reg(); | 5809 const Register right = locs()->in(1).reg(); |
5885 ASSERT(locs()->out(0).IsPairLocation()); | 5810 ASSERT(locs()->out(0).IsPairLocation()); |
5886 PairLocation* pair = locs()->out(0).AsPairLocation(); | 5811 PairLocation* pair = locs()->out(0).AsPairLocation(); |
5887 const Register result_div = pair->At(0).reg(); | 5812 const Register result_div = pair->At(0).reg(); |
5888 const Register result_mod = pair->At(1).reg(); | 5813 const Register result_mod = pair->At(1).reg(); |
5889 Range* right_range = InputAt(1)->definition()->range(); | 5814 Range* right_range = InputAt(1)->definition()->range(); |
5890 if ((right_range == NULL) || right_range->Overlaps(0, 0)) { | 5815 if ((right_range == NULL) || right_range->Overlaps(0, 0)) { |
5891 // Handle divide by zero in runtime. | 5816 // Handle divide by zero in runtime. |
5892 __ cmp(right, Operand(0)); | 5817 __ cmp(right, Operand(0)); |
5893 __ b(deopt, EQ); | 5818 __ b(deopt, EQ); |
5894 } | 5819 } |
5895 const Register temp = locs()->temp(0).reg(); | 5820 const Register temp = locs()->temp(0).reg(); |
5896 if (TargetCPUFeatures::can_divide()) { | 5821 const DRegister dtemp = EvenDRegisterOf(locs()->temp(1).fpu_reg()); |
5897 const DRegister dtemp = EvenDRegisterOf(locs()->temp(1).fpu_reg()); | 5822 __ SmiUntag(temp, left); |
5898 __ SmiUntag(temp, left); | 5823 __ SmiUntag(IP, right); |
5899 __ SmiUntag(IP, right); | 5824 __ IntegerDivide(result_div, temp, IP, dtemp, DTMP); |
5900 __ IntegerDivide(result_div, temp, IP, dtemp, DTMP); | |
5901 } else { | |
5902 // TODO(vegorov): never emit this instruction if hardware does not | |
5903 // support it! This will lead to deopt cycle penalizing the code. | |
5904 __ b(deopt); | |
5905 } | |
5906 | 5825 |
5907 // Check the corner case of dividing the 'MIN_SMI' with -1, in which | 5826 // Check the corner case of dividing the 'MIN_SMI' with -1, in which |
5908 // case we cannot tag the result. | 5827 // case we cannot tag the result. |
5909 __ CompareImmediate(result_div, 0x40000000); | 5828 __ CompareImmediate(result_div, 0x40000000); |
5910 __ b(deopt, EQ); | 5829 __ b(deopt, EQ); |
5911 __ SmiUntag(IP, right); | 5830 __ SmiUntag(IP, right); |
5912 // result_mod <- left - right * result_div. | 5831 // result_mod <- left - right * result_div. |
5913 __ mls(result_mod, IP, result_div, temp); | 5832 __ mls(result_mod, IP, result_div, temp); |
5914 __ SmiTag(result_div); | 5833 __ SmiTag(result_div); |
5915 __ SmiTag(result_mod); | 5834 __ SmiTag(result_mod); |
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6254 // Deopt on overflow. | 6173 // Deopt on overflow. |
6255 __ b(deopt, VS); | 6174 __ b(deopt, VS); |
6256 } | 6175 } |
6257 break; | 6176 break; |
6258 } | 6177 } |
6259 case Token::kMUL: { | 6178 case Token::kMUL: { |
6260 // The product of two signed 32-bit integers fits in a signed 64-bit | 6179 // The product of two signed 32-bit integers fits in a signed 64-bit |
6261 // result without causing overflow. | 6180 // result without causing overflow. |
6262 // We deopt on larger inputs. | 6181 // We deopt on larger inputs. |
6263 // TODO(regis): Range analysis may eliminate the deopt check. | 6182 // TODO(regis): Range analysis may eliminate the deopt check. |
6264 if (TargetCPUFeatures::arm_version() == ARMv7) { | 6183 __ cmp(left_hi, Operand(left_lo, ASR, 31)); |
6265 __ cmp(left_hi, Operand(left_lo, ASR, 31)); | 6184 __ cmp(right_hi, Operand(right_lo, ASR, 31), EQ); |
6266 __ cmp(right_hi, Operand(right_lo, ASR, 31), EQ); | 6185 __ b(deopt, NE); |
6267 __ b(deopt, NE); | 6186 __ smull(out_lo, out_hi, left_lo, right_lo); |
6268 __ smull(out_lo, out_hi, left_lo, right_lo); | |
6269 } else { | |
6270 // TODO(vegorov): never emit this instruction if hardware does not | |
6271 // support it! This will lead to deopt cycle penalizing the code. | |
6272 __ b(deopt); | |
6273 } | |
6274 break; | 6187 break; |
6275 } | 6188 } |
6276 default: | 6189 default: |
6277 UNREACHABLE(); | 6190 UNREACHABLE(); |
6278 } | 6191 } |
6279 if (FLAG_throw_on_javascript_int_overflow) { | 6192 if (FLAG_throw_on_javascript_int_overflow) { |
6280 EmitJavascriptIntOverflowCheck(compiler, deopt, out_lo, out_hi); | 6193 EmitJavascriptIntOverflowCheck(compiler, deopt, out_lo, out_hi); |
6281 } | 6194 } |
6282 } | 6195 } |
6283 | 6196 |
(...skipping 681 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6965 1, | 6878 1, |
6966 locs()); | 6879 locs()); |
6967 __ Drop(1); | 6880 __ Drop(1); |
6968 __ Pop(result); | 6881 __ Pop(result); |
6969 } | 6882 } |
6970 | 6883 |
6971 | 6884 |
6972 } // namespace dart | 6885 } // namespace dart |
6973 | 6886 |
6974 #endif // defined TARGET_ARCH_ARM | 6887 #endif // defined TARGET_ARCH_ARM |
OLD | NEW |