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 |