| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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_ARM64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. |
| 6 #if defined(TARGET_ARCH_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
| 7 | 7 |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 | 9 |
| 10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
| (...skipping 2777 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2788 __ cmp(left, Operand(TMP, ASR, value)); | 2788 __ cmp(left, Operand(TMP, ASR, value)); |
| 2789 __ b(deopt, NE); // Overflow. | 2789 __ b(deopt, NE); // Overflow. |
| 2790 } | 2790 } |
| 2791 // Shift for result now we know there is no overflow. | 2791 // Shift for result now we know there is no overflow. |
| 2792 __ LslImmediate(result, left, value); | 2792 __ LslImmediate(result, left, value); |
| 2793 return; | 2793 return; |
| 2794 } | 2794 } |
| 2795 | 2795 |
| 2796 // Right (locs.in(1)) is not constant. | 2796 // Right (locs.in(1)) is not constant. |
| 2797 const Register right = locs.in(1).reg(); | 2797 const Register right = locs.in(1).reg(); |
| 2798 Range* right_range = shift_left->right()->definition()->range(); | 2798 Range* right_range = shift_left->right_range(); |
| 2799 if (shift_left->left()->BindsToConstant() && shift_left->can_overflow()) { | 2799 if (shift_left->left()->BindsToConstant() && shift_left->can_overflow()) { |
| 2800 // TODO(srdjan): Implement code below for is_truncating(). | 2800 // TODO(srdjan): Implement code below for is_truncating(). |
| 2801 // If left is constant, we know the maximal allowed size for right. | 2801 // If left is constant, we know the maximal allowed size for right. |
| 2802 const Object& obj = shift_left->left()->BoundConstant(); | 2802 const Object& obj = shift_left->left()->BoundConstant(); |
| 2803 if (obj.IsSmi()) { | 2803 if (obj.IsSmi()) { |
| 2804 const intptr_t left_int = Smi::Cast(obj).Value(); | 2804 const intptr_t left_int = Smi::Cast(obj).Value(); |
| 2805 if (left_int == 0) { | 2805 if (left_int == 0) { |
| 2806 __ CompareRegisters(right, ZR); | 2806 __ CompareRegisters(right, ZR); |
| 2807 __ b(deopt, MI); | 2807 __ b(deopt, MI); |
| 2808 __ mov(result, ZR); | 2808 __ mov(result, ZR); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2819 __ SmiUntag(TMP, right); | 2819 __ SmiUntag(TMP, right); |
| 2820 __ lslv(result, left, TMP); | 2820 __ lslv(result, left, TMP); |
| 2821 } | 2821 } |
| 2822 return; | 2822 return; |
| 2823 } | 2823 } |
| 2824 | 2824 |
| 2825 const bool right_needs_check = | 2825 const bool right_needs_check = |
| 2826 !RangeUtils::IsWithin(right_range, 0, (Smi::kBits - 1)); | 2826 !RangeUtils::IsWithin(right_range, 0, (Smi::kBits - 1)); |
| 2827 if (!shift_left->can_overflow()) { | 2827 if (!shift_left->can_overflow()) { |
| 2828 if (right_needs_check) { | 2828 if (right_needs_check) { |
| 2829 const bool right_may_be_negative = | 2829 if (!RangeUtils::IsPositive(right_range)) { |
| 2830 (right_range == NULL) || !right_range->IsPositive(); | |
| 2831 if (right_may_be_negative) { | |
| 2832 ASSERT(shift_left->CanDeoptimize()); | 2830 ASSERT(shift_left->CanDeoptimize()); |
| 2833 __ CompareRegisters(right, ZR); | 2831 __ CompareRegisters(right, ZR); |
| 2834 __ b(deopt, MI); | 2832 __ b(deopt, MI); |
| 2835 } | 2833 } |
| 2836 | 2834 |
| 2837 __ CompareImmediate(right, | 2835 __ CompareImmediate(right, |
| 2838 reinterpret_cast<int64_t>(Smi::New(Smi::kBits))); | 2836 reinterpret_cast<int64_t>(Smi::New(Smi::kBits))); |
| 2839 __ csel(result, ZR, result, CS); | 2837 __ csel(result, ZR, result, CS); |
| 2840 __ SmiUntag(TMP, right); | 2838 __ SmiUntag(TMP, right); |
| 2841 __ lslv(TMP, left, TMP); | 2839 __ lslv(TMP, left, TMP); |
| (...skipping 429 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3271 break; | 3269 break; |
| 3272 } | 3270 } |
| 3273 default: | 3271 default: |
| 3274 UNREACHABLE(); | 3272 UNREACHABLE(); |
| 3275 break; | 3273 break; |
| 3276 } | 3274 } |
| 3277 return; | 3275 return; |
| 3278 } | 3276 } |
| 3279 | 3277 |
| 3280 const Register right = locs()->in(1).reg(); | 3278 const Register right = locs()->in(1).reg(); |
| 3281 Range* right_range = this->right()->definition()->range(); | |
| 3282 switch (op_kind()) { | 3279 switch (op_kind()) { |
| 3283 case Token::kADD: { | 3280 case Token::kADD: { |
| 3284 if (deopt == NULL) { | 3281 if (deopt == NULL) { |
| 3285 __ add(result, left, Operand(right)); | 3282 __ add(result, left, Operand(right)); |
| 3286 } else { | 3283 } else { |
| 3287 __ adds(result, left, Operand(right)); | 3284 __ adds(result, left, Operand(right)); |
| 3288 __ b(deopt, VS); | 3285 __ b(deopt, VS); |
| 3289 } | 3286 } |
| 3290 break; | 3287 break; |
| 3291 } | 3288 } |
| (...skipping 28 matching lines...) Expand all Loading... |
| 3320 // No overflow check. | 3317 // No overflow check. |
| 3321 __ orr(result, left, Operand(right)); | 3318 __ orr(result, left, Operand(right)); |
| 3322 break; | 3319 break; |
| 3323 } | 3320 } |
| 3324 case Token::kBIT_XOR: { | 3321 case Token::kBIT_XOR: { |
| 3325 // No overflow check. | 3322 // No overflow check. |
| 3326 __ eor(result, left, Operand(right)); | 3323 __ eor(result, left, Operand(right)); |
| 3327 break; | 3324 break; |
| 3328 } | 3325 } |
| 3329 case Token::kTRUNCDIV: { | 3326 case Token::kTRUNCDIV: { |
| 3330 if ((right_range == NULL) || right_range->Overlaps(0, 0)) { | 3327 if (RangeUtils::CanBeZero(right_range())) { |
| 3331 // Handle divide by zero in runtime. | 3328 // Handle divide by zero in runtime. |
| 3332 __ CompareRegisters(right, ZR); | 3329 __ CompareRegisters(right, ZR); |
| 3333 __ b(deopt, EQ); | 3330 __ b(deopt, EQ); |
| 3334 } | 3331 } |
| 3335 const Register temp = TMP2; | 3332 const Register temp = TMP2; |
| 3336 __ SmiUntag(temp, left); | 3333 __ SmiUntag(temp, left); |
| 3337 __ SmiUntag(TMP, right); | 3334 __ SmiUntag(TMP, right); |
| 3338 | 3335 |
| 3339 __ sdiv(result, temp, TMP); | 3336 __ sdiv(result, temp, TMP); |
| 3340 | 3337 |
| 3341 // Check the corner case of dividing the 'MIN_SMI' with -1, in which | 3338 // Check the corner case of dividing the 'MIN_SMI' with -1, in which |
| 3342 // case we cannot tag the result. | 3339 // case we cannot tag the result. |
| 3343 __ CompareImmediate(result, 0x4000000000000000LL); | 3340 __ CompareImmediate(result, 0x4000000000000000LL); |
| 3344 __ b(deopt, EQ); | 3341 __ b(deopt, EQ); |
| 3345 __ SmiTag(result); | 3342 __ SmiTag(result); |
| 3346 break; | 3343 break; |
| 3347 } | 3344 } |
| 3348 case Token::kMOD: { | 3345 case Token::kMOD: { |
| 3349 if ((right_range == NULL) || right_range->Overlaps(0, 0)) { | 3346 if (RangeUtils::CanBeZero(right_range())) { |
| 3350 // Handle divide by zero in runtime. | 3347 // Handle divide by zero in runtime. |
| 3351 __ CompareRegisters(right, ZR); | 3348 __ CompareRegisters(right, ZR); |
| 3352 __ b(deopt, EQ); | 3349 __ b(deopt, EQ); |
| 3353 } | 3350 } |
| 3354 const Register temp = TMP2; | 3351 const Register temp = TMP2; |
| 3355 __ SmiUntag(temp, left); | 3352 __ SmiUntag(temp, left); |
| 3356 __ SmiUntag(TMP, right); | 3353 __ SmiUntag(TMP, right); |
| 3357 | 3354 |
| 3358 __ sdiv(result, temp, TMP); | 3355 __ sdiv(result, temp, TMP); |
| 3359 | 3356 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 3380 break; | 3377 break; |
| 3381 } | 3378 } |
| 3382 case Token::kSHR: { | 3379 case Token::kSHR: { |
| 3383 if (CanDeoptimize()) { | 3380 if (CanDeoptimize()) { |
| 3384 __ CompareRegisters(right, ZR); | 3381 __ CompareRegisters(right, ZR); |
| 3385 __ b(deopt, LT); | 3382 __ b(deopt, LT); |
| 3386 } | 3383 } |
| 3387 __ SmiUntag(TMP, right); | 3384 __ SmiUntag(TMP, right); |
| 3388 // sarl operation masks the count to 6 bits. | 3385 // sarl operation masks the count to 6 bits. |
| 3389 const intptr_t kCountLimit = 0x3F; | 3386 const intptr_t kCountLimit = 0x3F; |
| 3390 if ((right_range == NULL) || | 3387 if (!RangeUtils::OnlyLessThanOrEqualTo(right_range(), kCountLimit)) { |
| 3391 !right_range->OnlyLessThanOrEqualTo(kCountLimit)) { | |
| 3392 __ LoadImmediate(TMP2, kCountLimit); | 3388 __ LoadImmediate(TMP2, kCountLimit); |
| 3393 __ CompareRegisters(TMP, TMP2); | 3389 __ CompareRegisters(TMP, TMP2); |
| 3394 __ csel(TMP, TMP2, TMP, GT); | 3390 __ csel(TMP, TMP2, TMP, GT); |
| 3395 } | 3391 } |
| 3396 const Register temp = locs()->temp(0).reg(); | 3392 const Register temp = locs()->temp(0).reg(); |
| 3397 __ SmiUntag(temp, left); | 3393 __ SmiUntag(temp, left); |
| 3398 __ asrv(result, temp, TMP); | 3394 __ asrv(result, temp, TMP); |
| 3399 __ SmiTag(result); | 3395 __ SmiTag(result); |
| 3400 break; | 3396 break; |
| 3401 } | 3397 } |
| (...skipping 1973 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5375 __ fmovdd(out, in); | 5371 __ fmovdd(out, in); |
| 5376 } else { | 5372 } else { |
| 5377 ASSERT(representation() == kTagged); | 5373 ASSERT(representation() == kTagged); |
| 5378 const Register out = locs()->out(0).reg(); | 5374 const Register out = locs()->out(0).reg(); |
| 5379 const Register in = in_loc.reg(); | 5375 const Register in = in_loc.reg(); |
| 5380 __ mov(out, in); | 5376 __ mov(out, in); |
| 5381 } | 5377 } |
| 5382 } | 5378 } |
| 5383 | 5379 |
| 5384 | 5380 |
| 5385 LocationSummary* MergedMathInstr::MakeLocationSummary(Zone* zone, | 5381 LocationSummary* TruncDivModInstr::MakeLocationSummary(Zone* zone, |
| 5386 bool opt) const { | 5382 bool opt) const { |
| 5387 if (kind() == MergedMathInstr::kTruncDivMod) { | 5383 const intptr_t kNumInputs = 2; |
| 5388 const intptr_t kNumInputs = 2; | 5384 const intptr_t kNumTemps = 0; |
| 5389 const intptr_t kNumTemps = 0; | 5385 LocationSummary* summary = new (zone) |
| 5390 LocationSummary* summary = new (zone) | 5386 LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 5391 LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); | 5387 summary->set_in(0, Location::RequiresRegister()); |
| 5392 summary->set_in(0, Location::RequiresRegister()); | 5388 summary->set_in(1, Location::RequiresRegister()); |
| 5393 summary->set_in(1, Location::RequiresRegister()); | 5389 // Output is a pair of registers. |
| 5394 // Output is a pair of registers. | 5390 summary->set_out(0, Location::Pair(Location::RequiresRegister(), |
| 5395 summary->set_out(0, Location::Pair(Location::RequiresRegister(), | 5391 Location::RequiresRegister())); |
| 5396 Location::RequiresRegister())); | 5392 return summary; |
| 5397 return summary; | |
| 5398 } | |
| 5399 UNIMPLEMENTED(); | |
| 5400 return NULL; | |
| 5401 } | 5393 } |
| 5402 | 5394 |
| 5403 | 5395 |
| 5404 void MergedMathInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 5396 void TruncDivModInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 5405 Label* deopt = NULL; | 5397 ASSERT(CanDeoptimize()); |
| 5406 if (CanDeoptimize()) { | 5398 Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinarySmiOp); |
| 5407 deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinarySmiOp); | 5399 const Register left = locs()->in(0).reg(); |
| 5400 const Register right = locs()->in(1).reg(); |
| 5401 ASSERT(locs()->out(0).IsPairLocation()); |
| 5402 const PairLocation* pair = locs()->out(0).AsPairLocation(); |
| 5403 const Register result_div = pair->At(0).reg(); |
| 5404 const Register result_mod = pair->At(1).reg(); |
| 5405 if (RangeUtils::CanBeZero(divisor_range())) { |
| 5406 // Handle divide by zero in runtime. |
| 5407 __ CompareRegisters(right, ZR); |
| 5408 __ b(deopt, EQ); |
| 5408 } | 5409 } |
| 5409 if (kind() == MergedMathInstr::kTruncDivMod) { | |
| 5410 const Register left = locs()->in(0).reg(); | |
| 5411 const Register right = locs()->in(1).reg(); | |
| 5412 ASSERT(locs()->out(0).IsPairLocation()); | |
| 5413 const PairLocation* pair = locs()->out(0).AsPairLocation(); | |
| 5414 const Register result_div = pair->At(0).reg(); | |
| 5415 const Register result_mod = pair->At(1).reg(); | |
| 5416 const Range* right_range = InputAt(1)->definition()->range(); | |
| 5417 if ((right_range == NULL) || right_range->Overlaps(0, 0)) { | |
| 5418 // Handle divide by zero in runtime. | |
| 5419 __ CompareRegisters(right, ZR); | |
| 5420 __ b(deopt, EQ); | |
| 5421 } | |
| 5422 | 5410 |
| 5423 __ SmiUntag(result_mod, left); | 5411 __ SmiUntag(result_mod, left); |
| 5424 __ SmiUntag(TMP, right); | 5412 __ SmiUntag(TMP, right); |
| 5425 | 5413 |
| 5426 __ sdiv(result_div, result_mod, TMP); | 5414 __ sdiv(result_div, result_mod, TMP); |
| 5427 | 5415 |
| 5428 // Check the corner case of dividing the 'MIN_SMI' with -1, in which | 5416 // Check the corner case of dividing the 'MIN_SMI' with -1, in which |
| 5429 // case we cannot tag the result. | 5417 // case we cannot tag the result. |
| 5430 __ CompareImmediate(result_div, 0x4000000000000000); | 5418 __ CompareImmediate(result_div, 0x4000000000000000); |
| 5431 __ b(deopt, EQ); | 5419 __ b(deopt, EQ); |
| 5432 // result_mod <- left - right * result_div. | 5420 // result_mod <- left - right * result_div. |
| 5433 __ msub(result_mod, TMP, result_div, result_mod); | 5421 __ msub(result_mod, TMP, result_div, result_mod); |
| 5434 __ SmiTag(result_div); | 5422 __ SmiTag(result_div); |
| 5435 __ SmiTag(result_mod); | 5423 __ SmiTag(result_mod); |
| 5436 // Correct MOD result: | 5424 // Correct MOD result: |
| 5437 // res = left % right; | 5425 // res = left % right; |
| 5438 // if (res < 0) { | 5426 // if (res < 0) { |
| 5439 // if (right < 0) { | 5427 // if (right < 0) { |
| 5440 // res = res - right; | 5428 // res = res - right; |
| 5441 // } else { | 5429 // } else { |
| 5442 // res = res + right; | 5430 // res = res + right; |
| 5443 // } | 5431 // } |
| 5444 // } | 5432 // } |
| 5445 Label done; | 5433 Label done; |
| 5446 __ CompareRegisters(result_mod, ZR); | 5434 __ CompareRegisters(result_mod, ZR); |
| 5447 __ b(&done, GE); | 5435 __ b(&done, GE); |
| 5448 // Result is negative, adjust it. | 5436 // Result is negative, adjust it. |
| 5449 __ CompareRegisters(right, ZR); | 5437 __ CompareRegisters(right, ZR); |
| 5450 __ sub(TMP2, result_mod, Operand(right)); | 5438 __ sub(TMP2, result_mod, Operand(right)); |
| 5451 __ add(TMP, result_mod, Operand(right)); | 5439 __ add(TMP, result_mod, Operand(right)); |
| 5452 __ csel(result_mod, TMP, TMP2, GE); | 5440 __ csel(result_mod, TMP, TMP2, GE); |
| 5453 __ Bind(&done); | 5441 __ Bind(&done); |
| 5454 return; | |
| 5455 } | |
| 5456 UNIMPLEMENTED(); | |
| 5457 } | 5442 } |
| 5458 | 5443 |
| 5459 | 5444 |
| 5460 LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary( | 5445 LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary( |
| 5461 Zone* zone, | 5446 Zone* zone, |
| 5462 bool opt) const { | 5447 bool opt) const { |
| 5463 return MakeCallSummary(zone); | 5448 return MakeCallSummary(zone); |
| 5464 } | 5449 } |
| 5465 | 5450 |
| 5466 | 5451 |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5725 UNIMPLEMENTED(); | 5710 UNIMPLEMENTED(); |
| 5726 return NULL; | 5711 return NULL; |
| 5727 } | 5712 } |
| 5728 | 5713 |
| 5729 | 5714 |
| 5730 void BinaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 5715 void BinaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 5731 UNIMPLEMENTED(); | 5716 UNIMPLEMENTED(); |
| 5732 } | 5717 } |
| 5733 | 5718 |
| 5734 | 5719 |
| 5735 bool ShiftMintOpInstr::has_shift_count_check() const { | |
| 5736 UNREACHABLE(); | |
| 5737 return false; | |
| 5738 } | |
| 5739 | |
| 5740 | |
| 5741 LocationSummary* ShiftMintOpInstr::MakeLocationSummary(Zone* zone, | 5720 LocationSummary* ShiftMintOpInstr::MakeLocationSummary(Zone* zone, |
| 5742 bool opt) const { | 5721 bool opt) const { |
| 5743 UNIMPLEMENTED(); | 5722 UNIMPLEMENTED(); |
| 5744 return NULL; | 5723 return NULL; |
| 5745 } | 5724 } |
| 5746 | 5725 |
| 5747 | 5726 |
| 5748 void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 5727 void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 5749 UNIMPLEMENTED(); | 5728 UNIMPLEMENTED(); |
| 5750 } | 5729 } |
| (...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6090 compiler->GenerateRuntimeCall(TokenPosition::kNoSource, deopt_id(), | 6069 compiler->GenerateRuntimeCall(TokenPosition::kNoSource, deopt_id(), |
| 6091 kGrowRegExpStackRuntimeEntry, 1, locs()); | 6070 kGrowRegExpStackRuntimeEntry, 1, locs()); |
| 6092 __ Drop(1); | 6071 __ Drop(1); |
| 6093 __ Pop(result); | 6072 __ Pop(result); |
| 6094 } | 6073 } |
| 6095 | 6074 |
| 6096 | 6075 |
| 6097 } // namespace dart | 6076 } // namespace dart |
| 6098 | 6077 |
| 6099 #endif // defined TARGET_ARCH_ARM64 | 6078 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |