| 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/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| (...skipping 2430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2441 __ CompareImmediate(temp, threshold, PP); | 2441 __ CompareImmediate(temp, threshold, PP); |
| 2442 __ b(slow_path->osr_entry_label(), GE); | 2442 __ b(slow_path->osr_entry_label(), GE); |
| 2443 } | 2443 } |
| 2444 if (compiler->ForceSlowPathForStackOverflow()) { | 2444 if (compiler->ForceSlowPathForStackOverflow()) { |
| 2445 __ b(slow_path->entry_label()); | 2445 __ b(slow_path->entry_label()); |
| 2446 } | 2446 } |
| 2447 __ Bind(slow_path->exit_label()); | 2447 __ Bind(slow_path->exit_label()); |
| 2448 } | 2448 } |
| 2449 | 2449 |
| 2450 | 2450 |
| 2451 static void EmitJavascriptOverflowCheck(FlowGraphCompiler* compiler, |
| 2452 Range* range, |
| 2453 Label* overflow, |
| 2454 Register result) { |
| 2455 if (!range->IsWithin(-0x20000000000000LL, 0x20000000000000LL)) { |
| 2456 ASSERT(overflow != NULL); |
| 2457 __ CompareImmediate(result, -0x20000000000000LL, PP); |
| 2458 __ b(overflow, LT); |
| 2459 __ CompareImmediate(result, 0x20000000000000LL, PP); |
| 2460 __ b(overflow, GT); |
| 2461 } |
| 2462 } |
| 2463 |
| 2464 |
| 2451 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, | 2465 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, |
| 2452 BinarySmiOpInstr* shift_left) { | 2466 BinarySmiOpInstr* shift_left) { |
| 2453 const bool is_truncating = shift_left->is_truncating(); | 2467 const bool is_truncating = shift_left->is_truncating(); |
| 2454 const LocationSummary& locs = *shift_left->locs(); | 2468 const LocationSummary& locs = *shift_left->locs(); |
| 2455 Register left = locs.in(0).reg(); | 2469 Register left = locs.in(0).reg(); |
| 2456 Register result = locs.out(0).reg(); | 2470 Register result = locs.out(0).reg(); |
| 2457 Label* deopt = shift_left->CanDeoptimize() ? | 2471 Label* deopt = shift_left->CanDeoptimize() ? |
| 2458 compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp) | 2472 compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp) |
| 2459 : NULL; | 2473 : NULL; |
| 2460 if (locs.in(1).IsConstant()) { | 2474 if (locs.in(1).IsConstant()) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2477 } else { | 2491 } else { |
| 2478 if (!is_truncating) { | 2492 if (!is_truncating) { |
| 2479 // Check for overflow (preserve left). | 2493 // Check for overflow (preserve left). |
| 2480 __ Lsl(TMP, left, value); | 2494 __ Lsl(TMP, left, value); |
| 2481 __ cmp(left, Operand(TMP, ASR, value)); | 2495 __ cmp(left, Operand(TMP, ASR, value)); |
| 2482 __ b(deopt, NE); // Overflow. | 2496 __ b(deopt, NE); // Overflow. |
| 2483 } | 2497 } |
| 2484 // Shift for result now we know there is no overflow. | 2498 // Shift for result now we know there is no overflow. |
| 2485 __ Lsl(result, left, value); | 2499 __ Lsl(result, left, value); |
| 2486 } | 2500 } |
| 2501 if (FLAG_throw_on_javascript_int_overflow) { |
| 2502 EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result); |
| 2503 } |
| 2487 return; | 2504 return; |
| 2488 } | 2505 } |
| 2489 | 2506 |
| 2490 // Right (locs.in(1)) is not constant. | 2507 // Right (locs.in(1)) is not constant. |
| 2491 Register right = locs.in(1).reg(); | 2508 Register right = locs.in(1).reg(); |
| 2492 Range* right_range = shift_left->right()->definition()->range(); | 2509 Range* right_range = shift_left->right()->definition()->range(); |
| 2493 if (shift_left->left()->BindsToConstant() && !is_truncating) { | 2510 if (shift_left->left()->BindsToConstant() && !is_truncating) { |
| 2494 // TODO(srdjan): Implement code below for is_truncating(). | 2511 // TODO(srdjan): Implement code below for is_truncating(). |
| 2495 // If left is constant, we know the maximal allowed size for right. | 2512 // If left is constant, we know the maximal allowed size for right. |
| 2496 const Object& obj = shift_left->left()->BoundConstant(); | 2513 const Object& obj = shift_left->left()->BoundConstant(); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2507 (right_range == NULL) || | 2524 (right_range == NULL) || |
| 2508 !right_range->IsWithin(0, max_right - 1); | 2525 !right_range->IsWithin(0, max_right - 1); |
| 2509 if (right_needs_check) { | 2526 if (right_needs_check) { |
| 2510 __ CompareImmediate(right, | 2527 __ CompareImmediate(right, |
| 2511 reinterpret_cast<int64_t>(Smi::New(max_right)), PP); | 2528 reinterpret_cast<int64_t>(Smi::New(max_right)), PP); |
| 2512 __ b(deopt, CS); | 2529 __ b(deopt, CS); |
| 2513 } | 2530 } |
| 2514 __ Asr(TMP, right, kSmiTagSize); // SmiUntag right into TMP. | 2531 __ Asr(TMP, right, kSmiTagSize); // SmiUntag right into TMP. |
| 2515 __ lslv(result, left, TMP); | 2532 __ lslv(result, left, TMP); |
| 2516 } | 2533 } |
| 2534 if (FLAG_throw_on_javascript_int_overflow) { |
| 2535 EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result); |
| 2536 } |
| 2517 return; | 2537 return; |
| 2518 } | 2538 } |
| 2519 | 2539 |
| 2520 const bool right_needs_check = | 2540 const bool right_needs_check = |
| 2521 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1)); | 2541 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1)); |
| 2522 if (is_truncating) { | 2542 if (is_truncating) { |
| 2523 if (right_needs_check) { | 2543 if (right_needs_check) { |
| 2524 const bool right_may_be_negative = | 2544 const bool right_may_be_negative = |
| 2525 (right_range == NULL) || | 2545 (right_range == NULL) || |
| 2526 !right_range->IsWithin(0, RangeBoundary::kPlusInfinity); | 2546 !right_range->IsWithin(0, RangeBoundary::kPlusInfinity); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 2552 __ Asr(TMP, right, kSmiTagSize); // SmiUntag right into IP. | 2572 __ Asr(TMP, right, kSmiTagSize); // SmiUntag right into IP. |
| 2553 // Overflow test (preserve left, right, and IP); | 2573 // Overflow test (preserve left, right, and IP); |
| 2554 Register temp = locs.temp(0).reg(); | 2574 Register temp = locs.temp(0).reg(); |
| 2555 __ lslv(temp, left, TMP); | 2575 __ lslv(temp, left, TMP); |
| 2556 __ asrv(TMP2, temp, TMP); | 2576 __ asrv(TMP2, temp, TMP); |
| 2557 __ CompareRegisters(left, TMP2); | 2577 __ CompareRegisters(left, TMP2); |
| 2558 __ b(deopt, NE); // Overflow. | 2578 __ b(deopt, NE); // Overflow. |
| 2559 // Shift for result now we know there is no overflow. | 2579 // Shift for result now we know there is no overflow. |
| 2560 __ lslv(result, left, TMP); | 2580 __ lslv(result, left, TMP); |
| 2561 } | 2581 } |
| 2582 if (FLAG_throw_on_javascript_int_overflow) { |
| 2583 EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result); |
| 2584 } |
| 2562 } | 2585 } |
| 2563 | 2586 |
| 2564 | 2587 |
| 2565 LocationSummary* BinarySmiOpInstr::MakeLocationSummary(bool opt) const { | 2588 LocationSummary* BinarySmiOpInstr::MakeLocationSummary(bool opt) const { |
| 2566 const intptr_t kNumInputs = 2; | 2589 const intptr_t kNumInputs = 2; |
| 2567 const intptr_t kNumTemps = 0; | 2590 const intptr_t kNumTemps = 0; |
| 2568 LocationSummary* summary = | 2591 LocationSummary* summary = |
| 2569 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2592 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2570 if (op_kind() == Token::kTRUNCDIV) { | 2593 if (op_kind() == Token::kTRUNCDIV) { |
| 2571 summary->set_in(0, Location::RequiresRegister()); | 2594 summary->set_in(0, Location::RequiresRegister()); |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2726 } | 2749 } |
| 2727 | 2750 |
| 2728 __ Asr(result, left, value); | 2751 __ Asr(result, left, value); |
| 2729 __ SmiTag(result); | 2752 __ SmiTag(result); |
| 2730 break; | 2753 break; |
| 2731 } | 2754 } |
| 2732 default: | 2755 default: |
| 2733 UNREACHABLE(); | 2756 UNREACHABLE(); |
| 2734 break; | 2757 break; |
| 2735 } | 2758 } |
| 2759 if (FLAG_throw_on_javascript_int_overflow) { |
| 2760 EmitJavascriptOverflowCheck(compiler, range(), deopt, result); |
| 2761 } |
| 2736 return; | 2762 return; |
| 2737 } | 2763 } |
| 2738 | 2764 |
| 2739 Register right = locs()->in(1).reg(); | 2765 Register right = locs()->in(1).reg(); |
| 2740 Range* right_range = this->right()->definition()->range(); | 2766 Range* right_range = this->right()->definition()->range(); |
| 2741 switch (op_kind()) { | 2767 switch (op_kind()) { |
| 2742 case Token::kADD: { | 2768 case Token::kADD: { |
| 2743 if (deopt == NULL) { | 2769 if (deopt == NULL) { |
| 2744 __ add(result, left, Operand(right)); | 2770 __ add(result, left, Operand(right)); |
| 2745 } else { | 2771 } else { |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2868 case Token::kAND: { | 2894 case Token::kAND: { |
| 2869 // Flow graph builder has dissected this operation to guarantee correct | 2895 // Flow graph builder has dissected this operation to guarantee correct |
| 2870 // behavior (short-circuit evaluation). | 2896 // behavior (short-circuit evaluation). |
| 2871 UNREACHABLE(); | 2897 UNREACHABLE(); |
| 2872 break; | 2898 break; |
| 2873 } | 2899 } |
| 2874 default: | 2900 default: |
| 2875 UNREACHABLE(); | 2901 UNREACHABLE(); |
| 2876 break; | 2902 break; |
| 2877 } | 2903 } |
| 2904 if (FLAG_throw_on_javascript_int_overflow) { |
| 2905 EmitJavascriptOverflowCheck(compiler, range(), deopt, result); |
| 2906 } |
| 2878 } | 2907 } |
| 2879 | 2908 |
| 2880 | 2909 |
| 2881 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary(bool opt) const { | 2910 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary(bool opt) const { |
| 2882 intptr_t left_cid = left()->Type()->ToCid(); | 2911 intptr_t left_cid = left()->Type()->ToCid(); |
| 2883 intptr_t right_cid = right()->Type()->ToCid(); | 2912 intptr_t right_cid = right()->Type()->ToCid(); |
| 2884 ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid)); | 2913 ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid)); |
| 2885 const intptr_t kNumInputs = 2; | 2914 const intptr_t kNumInputs = 2; |
| 2886 const intptr_t kNumTemps = 0; | 2915 const intptr_t kNumTemps = 0; |
| 2887 LocationSummary* summary = | 2916 LocationSummary* summary = |
| (...skipping 667 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3555 | 3584 |
| 3556 | 3585 |
| 3557 void UnarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3586 void UnarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 3558 Register value = locs()->in(0).reg(); | 3587 Register value = locs()->in(0).reg(); |
| 3559 Register result = locs()->out(0).reg(); | 3588 Register result = locs()->out(0).reg(); |
| 3560 switch (op_kind()) { | 3589 switch (op_kind()) { |
| 3561 case Token::kNEGATE: { | 3590 case Token::kNEGATE: { |
| 3562 Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnaryOp); | 3591 Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnaryOp); |
| 3563 __ subs(result, ZR, Operand(value)); | 3592 __ subs(result, ZR, Operand(value)); |
| 3564 __ b(deopt, VS); | 3593 __ b(deopt, VS); |
| 3594 if (FLAG_throw_on_javascript_int_overflow) { |
| 3595 EmitJavascriptOverflowCheck(compiler, range(), deopt, value); |
| 3596 } |
| 3565 break; | 3597 break; |
| 3566 } | 3598 } |
| 3567 case Token::kBIT_NOT: | 3599 case Token::kBIT_NOT: |
| 3568 __ mvn(result, value); | 3600 __ mvn(result, value); |
| 3569 // Remove inverted smi-tag. | 3601 // Remove inverted smi-tag. |
| 3570 __ andi(result, result, ~kSmiTagMask); | 3602 __ andi(result, result, ~kSmiTagMask); |
| 3571 break; | 3603 break; |
| 3572 default: | 3604 default: |
| 3573 UNREACHABLE(); | 3605 UNREACHABLE(); |
| 3574 } | 3606 } |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3636 __ fcmpd(VTMP, VTMP); | 3668 __ fcmpd(VTMP, VTMP); |
| 3637 __ b(&do_call, VS); | 3669 __ b(&do_call, VS); |
| 3638 | 3670 |
| 3639 __ fcvtzds(result, VTMP); | 3671 __ fcvtzds(result, VTMP); |
| 3640 // Overflow is signaled with minint. | 3672 // Overflow is signaled with minint. |
| 3641 | 3673 |
| 3642 // Check for overflow and that it fits into Smi. | 3674 // Check for overflow and that it fits into Smi. |
| 3643 __ CompareImmediate(result, 0xC000000000000000, PP); | 3675 __ CompareImmediate(result, 0xC000000000000000, PP); |
| 3644 __ b(&do_call, MI); | 3676 __ b(&do_call, MI); |
| 3645 __ SmiTag(result); | 3677 __ SmiTag(result); |
| 3678 if (FLAG_throw_on_javascript_int_overflow) { |
| 3679 EmitJavascriptOverflowCheck(compiler, range(), &do_call, result); |
| 3680 } |
| 3646 __ b(&done); | 3681 __ b(&done); |
| 3647 __ Bind(&do_call); | 3682 __ Bind(&do_call); |
| 3648 __ Push(value_obj); | 3683 __ Push(value_obj); |
| 3649 ASSERT(instance_call()->HasICData()); | 3684 ASSERT(instance_call()->HasICData()); |
| 3650 const ICData& ic_data = *instance_call()->ic_data(); | 3685 const ICData& ic_data = *instance_call()->ic_data(); |
| 3651 ASSERT((ic_data.NumberOfChecks() == 1)); | 3686 ASSERT((ic_data.NumberOfChecks() == 1)); |
| 3652 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); | 3687 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); |
| 3653 | 3688 |
| 3654 const intptr_t kNumberOfArguments = 1; | 3689 const intptr_t kNumberOfArguments = 1; |
| 3655 compiler->GenerateStaticCall(deopt_id(), | 3690 compiler->GenerateStaticCall(deopt_id(), |
| (...skipping 25 matching lines...) Expand all Loading... |
| 3681 // on ARM64 because fcvtzds gives 0 for NaN. | 3716 // on ARM64 because fcvtzds gives 0 for NaN. |
| 3682 // TODO(zra): Check spec that this is true. | 3717 // TODO(zra): Check spec that this is true. |
| 3683 __ fcmpd(value, value); | 3718 __ fcmpd(value, value); |
| 3684 __ b(deopt, VS); | 3719 __ b(deopt, VS); |
| 3685 | 3720 |
| 3686 __ fcvtzds(result, value); | 3721 __ fcvtzds(result, value); |
| 3687 // Check for overflow and that it fits into Smi. | 3722 // Check for overflow and that it fits into Smi. |
| 3688 __ CompareImmediate(result, 0xC000000000000000, PP); | 3723 __ CompareImmediate(result, 0xC000000000000000, PP); |
| 3689 __ b(deopt, MI); | 3724 __ b(deopt, MI); |
| 3690 __ SmiTag(result); | 3725 __ SmiTag(result); |
| 3726 if (FLAG_throw_on_javascript_int_overflow) { |
| 3727 EmitJavascriptOverflowCheck(compiler, range(), deopt, result); |
| 3728 } |
| 3691 } | 3729 } |
| 3692 | 3730 |
| 3693 | 3731 |
| 3694 LocationSummary* DoubleToDoubleInstr::MakeLocationSummary(bool opt) const { | 3732 LocationSummary* DoubleToDoubleInstr::MakeLocationSummary(bool opt) const { |
| 3695 UNIMPLEMENTED(); | 3733 UNIMPLEMENTED(); |
| 3696 return NULL; | 3734 return NULL; |
| 3697 } | 3735 } |
| 3698 | 3736 |
| 3699 | 3737 |
| 3700 void DoubleToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3738 void DoubleToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| (...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3987 // } | 4025 // } |
| 3988 Label done; | 4026 Label done; |
| 3989 __ CompareRegisters(result_mod, ZR);; | 4027 __ CompareRegisters(result_mod, ZR);; |
| 3990 __ b(&done, GE); | 4028 __ b(&done, GE); |
| 3991 // Result is negative, adjust it. | 4029 // Result is negative, adjust it. |
| 3992 __ CompareRegisters(right, ZR); | 4030 __ CompareRegisters(right, ZR); |
| 3993 __ sub(TMP2, result_mod, Operand(right)); | 4031 __ sub(TMP2, result_mod, Operand(right)); |
| 3994 __ add(TMP, result_mod, Operand(right)); | 4032 __ add(TMP, result_mod, Operand(right)); |
| 3995 __ csel(result_mod, TMP, TMP2, GE); | 4033 __ csel(result_mod, TMP, TMP2, GE); |
| 3996 __ Bind(&done); | 4034 __ Bind(&done); |
| 3997 | 4035 // FLAG_throw_on_javascript_int_overflow: not needed. |
| 4036 // Note that the result of an integer division/modulo of two |
| 4037 // in-range arguments, cannot create out-of-range result. |
| 3998 return; | 4038 return; |
| 3999 } | 4039 } |
| 4000 if (kind() == MergedMathInstr::kSinCos) { | 4040 if (kind() == MergedMathInstr::kSinCos) { |
| 4001 UNIMPLEMENTED(); | 4041 UNIMPLEMENTED(); |
| 4002 } | 4042 } |
| 4003 UNIMPLEMENTED(); | 4043 UNIMPLEMENTED(); |
| 4004 } | 4044 } |
| 4005 | 4045 |
| 4006 | 4046 |
| 4007 LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary( | 4047 LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary( |
| (...skipping 439 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4447 compiler->GenerateCall(token_pos(), | 4487 compiler->GenerateCall(token_pos(), |
| 4448 &label, | 4488 &label, |
| 4449 PcDescriptors::kOther, | 4489 PcDescriptors::kOther, |
| 4450 locs()); | 4490 locs()); |
| 4451 __ Drop(ArgumentCount()); // Discard arguments. | 4491 __ Drop(ArgumentCount()); // Discard arguments. |
| 4452 } | 4492 } |
| 4453 | 4493 |
| 4454 } // namespace dart | 4494 } // namespace dart |
| 4455 | 4495 |
| 4456 #endif // defined TARGET_ARCH_ARM64 | 4496 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |