| 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 2514 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2525 __ LoadImmediate(TMP, 0x20000000000000LL, PP); | 2525 __ LoadImmediate(TMP, 0x20000000000000LL, PP); |
| 2526 __ add(TMP2, result, Operand(TMP)); | 2526 __ add(TMP2, result, Operand(TMP)); |
| 2527 __ cmp(TMP2, Operand(TMP, LSL, 1)); | 2527 __ cmp(TMP2, Operand(TMP, LSL, 1)); |
| 2528 __ b(overflow, HI); | 2528 __ b(overflow, HI); |
| 2529 } | 2529 } |
| 2530 } | 2530 } |
| 2531 | 2531 |
| 2532 | 2532 |
| 2533 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, | 2533 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, |
| 2534 BinarySmiOpInstr* shift_left) { | 2534 BinarySmiOpInstr* shift_left) { |
| 2535 const bool is_truncating = shift_left->IsTruncating(); | |
| 2536 const LocationSummary& locs = *shift_left->locs(); | 2535 const LocationSummary& locs = *shift_left->locs(); |
| 2537 const Register left = locs.in(0).reg(); | 2536 const Register left = locs.in(0).reg(); |
| 2538 const Register result = locs.out(0).reg(); | 2537 const Register result = locs.out(0).reg(); |
| 2539 Label* deopt = shift_left->CanDeoptimize() ? | 2538 Label* deopt = shift_left->CanDeoptimize() ? |
| 2540 compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp) | 2539 compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp) |
| 2541 : NULL; | 2540 : NULL; |
| 2542 if (locs.in(1).IsConstant()) { | 2541 if (locs.in(1).IsConstant()) { |
| 2543 const Object& constant = locs.in(1).constant(); | 2542 const Object& constant = locs.in(1).constant(); |
| 2544 ASSERT(constant.IsSmi()); | 2543 ASSERT(constant.IsSmi()); |
| 2545 // Immediate shift operation takes 6 bits for the count. | 2544 // Immediate shift operation takes 6 bits for the count. |
| 2546 const intptr_t kCountLimit = 0x3F; | 2545 const intptr_t kCountLimit = 0x3F; |
| 2547 const intptr_t value = Smi::Cast(constant).Value(); | 2546 const intptr_t value = Smi::Cast(constant).Value(); |
| 2548 if (value == 0) { | 2547 ASSERT((0 < value) && (value < kCountLimit)); |
| 2549 __ mov(result, left); | 2548 if (shift_left->can_overflow()) { |
| 2550 } else if ((value < 0) || (value >= kCountLimit)) { | 2549 // Check for overflow (preserve left). |
| 2551 // This condition may not be known earlier in some cases because | 2550 __ Lsl(TMP, left, value); |
| 2552 // of constant propagation, inlining, etc. | 2551 __ cmp(left, Operand(TMP, ASR, value)); |
| 2553 if ((value >= kCountLimit) && is_truncating) { | 2552 __ b(deopt, NE); // Overflow. |
| 2554 __ mov(result, ZR); | |
| 2555 } else { | |
| 2556 // Result is Mint or exception. | |
| 2557 __ b(deopt); | |
| 2558 } | |
| 2559 } else { | |
| 2560 if (!is_truncating) { | |
| 2561 // Check for overflow (preserve left). | |
| 2562 __ Lsl(TMP, left, value); | |
| 2563 __ cmp(left, Operand(TMP, ASR, value)); | |
| 2564 __ b(deopt, NE); // Overflow. | |
| 2565 } | |
| 2566 // Shift for result now we know there is no overflow. | |
| 2567 __ Lsl(result, left, value); | |
| 2568 } | 2553 } |
| 2554 // Shift for result now we know there is no overflow. |
| 2555 __ Lsl(result, left, value); |
| 2569 if (FLAG_throw_on_javascript_int_overflow) { | 2556 if (FLAG_throw_on_javascript_int_overflow) { |
| 2570 EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result); | 2557 EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result); |
| 2571 } | 2558 } |
| 2572 return; | 2559 return; |
| 2573 } | 2560 } |
| 2574 | 2561 |
| 2575 // Right (locs.in(1)) is not constant. | 2562 // Right (locs.in(1)) is not constant. |
| 2576 const Register right = locs.in(1).reg(); | 2563 const Register right = locs.in(1).reg(); |
| 2577 Range* right_range = shift_left->right()->definition()->range(); | 2564 Range* right_range = shift_left->right()->definition()->range(); |
| 2578 if (shift_left->left()->BindsToConstant() && !is_truncating) { | 2565 if (shift_left->left()->BindsToConstant() && shift_left->can_overflow()) { |
| 2579 // TODO(srdjan): Implement code below for is_truncating(). | 2566 // TODO(srdjan): Implement code below for is_truncating(). |
| 2580 // If left is constant, we know the maximal allowed size for right. | 2567 // If left is constant, we know the maximal allowed size for right. |
| 2581 const Object& obj = shift_left->left()->BoundConstant(); | 2568 const Object& obj = shift_left->left()->BoundConstant(); |
| 2582 if (obj.IsSmi()) { | 2569 if (obj.IsSmi()) { |
| 2583 const intptr_t left_int = Smi::Cast(obj).Value(); | 2570 const intptr_t left_int = Smi::Cast(obj).Value(); |
| 2584 if (left_int == 0) { | 2571 if (left_int == 0) { |
| 2585 __ CompareRegisters(right, ZR); | 2572 __ CompareRegisters(right, ZR); |
| 2586 __ b(deopt, MI); | 2573 __ b(deopt, MI); |
| 2587 __ mov(result, ZR); | 2574 __ mov(result, ZR); |
| 2588 return; | 2575 return; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2599 __ lslv(result, left, TMP); | 2586 __ lslv(result, left, TMP); |
| 2600 } | 2587 } |
| 2601 if (FLAG_throw_on_javascript_int_overflow) { | 2588 if (FLAG_throw_on_javascript_int_overflow) { |
| 2602 EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result); | 2589 EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result); |
| 2603 } | 2590 } |
| 2604 return; | 2591 return; |
| 2605 } | 2592 } |
| 2606 | 2593 |
| 2607 const bool right_needs_check = | 2594 const bool right_needs_check = |
| 2608 !RangeUtils::IsWithin(right_range, 0, (Smi::kBits - 1)); | 2595 !RangeUtils::IsWithin(right_range, 0, (Smi::kBits - 1)); |
| 2609 if (is_truncating) { | 2596 if (!shift_left->can_overflow()) { |
| 2610 if (right_needs_check) { | 2597 if (right_needs_check) { |
| 2611 const bool right_may_be_negative = | 2598 const bool right_may_be_negative = |
| 2612 (right_range == NULL) || !right_range->IsPositive(); | 2599 (right_range == NULL) || !right_range->IsPositive(); |
| 2613 if (right_may_be_negative) { | 2600 if (right_may_be_negative) { |
| 2614 ASSERT(shift_left->CanDeoptimize()); | 2601 ASSERT(shift_left->CanDeoptimize()); |
| 2615 __ CompareRegisters(right, ZR); | 2602 __ CompareRegisters(right, ZR); |
| 2616 __ b(deopt, MI); | 2603 __ b(deopt, MI); |
| 2617 } | 2604 } |
| 2618 | 2605 |
| 2619 __ CompareImmediate( | 2606 __ CompareImmediate( |
| (...skipping 28 matching lines...) Expand all Loading... |
| 2648 if (FLAG_throw_on_javascript_int_overflow) { | 2635 if (FLAG_throw_on_javascript_int_overflow) { |
| 2649 EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result); | 2636 EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result); |
| 2650 } | 2637 } |
| 2651 } | 2638 } |
| 2652 | 2639 |
| 2653 | 2640 |
| 2654 LocationSummary* BinarySmiOpInstr::MakeLocationSummary(Isolate* isolate, | 2641 LocationSummary* BinarySmiOpInstr::MakeLocationSummary(Isolate* isolate, |
| 2655 bool opt) const { | 2642 bool opt) const { |
| 2656 const intptr_t kNumInputs = 2; | 2643 const intptr_t kNumInputs = 2; |
| 2657 const intptr_t kNumTemps = | 2644 const intptr_t kNumTemps = |
| 2658 (((op_kind() == Token::kSHL) && !IsTruncating()) || | 2645 (((op_kind() == Token::kSHL) && can_overflow()) || |
| 2659 (op_kind() == Token::kSHR)) ? 1 : 0; | 2646 (op_kind() == Token::kSHR)) ? 1 : 0; |
| 2660 LocationSummary* summary = new(isolate) LocationSummary( | 2647 LocationSummary* summary = new(isolate) LocationSummary( |
| 2661 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2648 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2662 if (op_kind() == Token::kTRUNCDIV) { | 2649 if (op_kind() == Token::kTRUNCDIV) { |
| 2663 summary->set_in(0, Location::RequiresRegister()); | 2650 summary->set_in(0, Location::RequiresRegister()); |
| 2664 if (RightIsPowerOfTwoConstant()) { | 2651 if (RightIsPowerOfTwoConstant()) { |
| 2665 ConstantInstr* right_constant = right()->definition()->AsConstant(); | 2652 ConstantInstr* right_constant = right()->definition()->AsConstant(); |
| 2666 summary->set_in(1, Location::Constant(right_constant)); | 2653 summary->set_in(1, Location::Constant(right_constant)); |
| 2667 } else { | 2654 } else { |
| 2668 summary->set_in(1, Location::RequiresRegister()); | 2655 summary->set_in(1, Location::RequiresRegister()); |
| 2669 } | 2656 } |
| 2670 summary->set_out(0, Location::RequiresRegister()); | 2657 summary->set_out(0, Location::RequiresRegister()); |
| 2671 return summary; | 2658 return summary; |
| 2672 } | 2659 } |
| 2673 if (op_kind() == Token::kMOD) { | 2660 if (op_kind() == Token::kMOD) { |
| 2674 summary->set_in(0, Location::RequiresRegister()); | 2661 summary->set_in(0, Location::RequiresRegister()); |
| 2675 summary->set_in(1, Location::RequiresRegister()); | 2662 summary->set_in(1, Location::RequiresRegister()); |
| 2676 summary->set_out(0, Location::RequiresRegister()); | 2663 summary->set_out(0, Location::RequiresRegister()); |
| 2677 return summary; | 2664 return summary; |
| 2678 } | 2665 } |
| 2679 summary->set_in(0, Location::RequiresRegister()); | 2666 summary->set_in(0, Location::RequiresRegister()); |
| 2680 summary->set_in(1, Location::RegisterOrSmiConstant(right())); | 2667 summary->set_in(1, Location::RegisterOrSmiConstant(right())); |
| 2681 if (((op_kind() == Token::kSHL) && !IsTruncating()) || | 2668 if (((op_kind() == Token::kSHL) && can_overflow()) || |
| 2682 (op_kind() == Token::kSHR)) { | 2669 (op_kind() == Token::kSHR)) { |
| 2683 summary->set_temp(0, Location::RequiresRegister()); | 2670 summary->set_temp(0, Location::RequiresRegister()); |
| 2684 } | 2671 } |
| 2685 // We make use of 3-operand instructions by not requiring result register | 2672 // We make use of 3-operand instructions by not requiring result register |
| 2686 // to be identical to first input register as on Intel. | 2673 // to be identical to first input register as on Intel. |
| 2687 summary->set_out(0, Location::RequiresRegister()); | 2674 summary->set_out(0, Location::RequiresRegister()); |
| 2688 return summary; | 2675 return summary; |
| 2689 } | 2676 } |
| 2690 | 2677 |
| 2691 | 2678 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2723 // Negating imm and using AddImmediateSetFlags would not detect the | 2710 // Negating imm and using AddImmediateSetFlags would not detect the |
| 2724 // overflow when imm == kMinInt64. | 2711 // overflow when imm == kMinInt64. |
| 2725 __ SubImmediateSetFlags(result, left, imm, PP); | 2712 __ SubImmediateSetFlags(result, left, imm, PP); |
| 2726 __ b(deopt, VS); | 2713 __ b(deopt, VS); |
| 2727 } | 2714 } |
| 2728 break; | 2715 break; |
| 2729 } | 2716 } |
| 2730 case Token::kMUL: { | 2717 case Token::kMUL: { |
| 2731 // Keep left value tagged and untag right value. | 2718 // Keep left value tagged and untag right value. |
| 2732 const intptr_t value = Smi::Cast(constant).Value(); | 2719 const intptr_t value = Smi::Cast(constant).Value(); |
| 2733 if (deopt == NULL) { | 2720 __ LoadImmediate(TMP, value, PP); |
| 2734 if (value == 2) { | 2721 __ mul(result, left, TMP); |
| 2735 __ Lsl(result, left, 1); | 2722 if (deopt != NULL) { |
| 2736 } else { | 2723 __ smulh(TMP, left, TMP); |
| 2737 __ LoadImmediate(TMP, value, PP); | 2724 // TMP: result bits 64..127. |
| 2738 __ mul(result, left, TMP); | 2725 __ cmp(TMP, Operand(result, ASR, 63)); |
| 2739 } | 2726 __ b(deopt, NE); |
| 2740 } else { | |
| 2741 if (value == 2) { | |
| 2742 __ Asr(TMP, left, 63); // TMP = sign of left. | |
| 2743 __ Lsl(result, left, 1); | |
| 2744 // TMP: result bits 32..63. | |
| 2745 __ cmp(TMP, Operand(result, ASR, 63)); | |
| 2746 __ b(deopt, NE); | |
| 2747 } else { | |
| 2748 __ LoadImmediate(TMP, value, PP); | |
| 2749 __ mul(result, left, TMP); | |
| 2750 __ smulh(TMP, left, TMP); | |
| 2751 // TMP: result bits 64..127. | |
| 2752 __ cmp(TMP, Operand(result, ASR, 63)); | |
| 2753 __ b(deopt, NE); | |
| 2754 } | |
| 2755 } | 2727 } |
| 2756 break; | 2728 break; |
| 2757 } | 2729 } |
| 2758 case Token::kTRUNCDIV: { | 2730 case Token::kTRUNCDIV: { |
| 2759 const intptr_t value = Smi::Cast(constant).Value(); | 2731 const intptr_t value = Smi::Cast(constant).Value(); |
| 2760 if (value == 1) { | |
| 2761 __ mov(result, left); | |
| 2762 break; | |
| 2763 } else if (value == -1) { | |
| 2764 // Check the corner case of dividing the 'MIN_SMI' with -1, in which | |
| 2765 // case we cannot negate the result. | |
| 2766 __ CompareImmediate(left, 0x8000000000000000LL, kNoPP); | |
| 2767 __ b(deopt, EQ); | |
| 2768 __ sub(result, ZR, Operand(left)); | |
| 2769 break; | |
| 2770 } | |
| 2771 ASSERT(Utils::IsPowerOfTwo(Utils::Abs(value))); | 2732 ASSERT(Utils::IsPowerOfTwo(Utils::Abs(value))); |
| 2772 const intptr_t shift_count = | 2733 const intptr_t shift_count = |
| 2773 Utils::ShiftForPowerOfTwo(Utils::Abs(value)) + kSmiTagSize; | 2734 Utils::ShiftForPowerOfTwo(Utils::Abs(value)) + kSmiTagSize; |
| 2774 ASSERT(kSmiTagSize == 1); | 2735 ASSERT(kSmiTagSize == 1); |
| 2775 __ Asr(TMP, left, 63); | 2736 __ Asr(TMP, left, 63); |
| 2776 ASSERT(shift_count > 1); // 1, -1 case handled above. | 2737 ASSERT(shift_count > 1); // 1, -1 case handled above. |
| 2777 const Register temp = TMP2; | 2738 const Register temp = TMP2; |
| 2778 __ add(temp, left, Operand(TMP, LSR, 64 - shift_count)); | 2739 __ add(temp, left, Operand(TMP, LSR, 64 - shift_count)); |
| 2779 ASSERT(shift_count > 0); | 2740 ASSERT(shift_count > 0); |
| 2780 __ Asr(result, temp, shift_count); | 2741 __ Asr(result, temp, shift_count); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 2793 __ OrImmediate(result, left, imm, PP); | 2754 __ OrImmediate(result, left, imm, PP); |
| 2794 break; | 2755 break; |
| 2795 case Token::kBIT_XOR: | 2756 case Token::kBIT_XOR: |
| 2796 // No overflow check. | 2757 // No overflow check. |
| 2797 __ XorImmediate(result, left, imm, PP); | 2758 __ XorImmediate(result, left, imm, PP); |
| 2798 break; | 2759 break; |
| 2799 case Token::kSHR: { | 2760 case Token::kSHR: { |
| 2800 // Asr operation masks the count to 6 bits. | 2761 // Asr operation masks the count to 6 bits. |
| 2801 const intptr_t kCountLimit = 0x3F; | 2762 const intptr_t kCountLimit = 0x3F; |
| 2802 intptr_t value = Smi::Cast(constant).Value(); | 2763 intptr_t value = Smi::Cast(constant).Value(); |
| 2803 | 2764 __ Asr(result, left, Utils::Minimum(value + kSmiTagSize, kCountLimit)); |
| 2804 if (value == 0) { | |
| 2805 // TODO(vegorov): should be handled outside. | |
| 2806 __ mov(result, left); | |
| 2807 break; | |
| 2808 } else if (value < 0) { | |
| 2809 // TODO(vegorov): should be handled outside. | |
| 2810 __ b(deopt); | |
| 2811 break; | |
| 2812 } | |
| 2813 | |
| 2814 value = value + kSmiTagSize; | |
| 2815 if (value >= kCountLimit) { | |
| 2816 value = kCountLimit; | |
| 2817 } | |
| 2818 | |
| 2819 __ Asr(result, left, value); | |
| 2820 __ SmiTag(result); | 2765 __ SmiTag(result); |
| 2821 break; | 2766 break; |
| 2822 } | 2767 } |
| 2823 default: | 2768 default: |
| 2824 UNREACHABLE(); | 2769 UNREACHABLE(); |
| 2825 break; | 2770 break; |
| 2826 } | 2771 } |
| 2827 if (FLAG_throw_on_javascript_int_overflow) { | 2772 if (FLAG_throw_on_javascript_int_overflow) { |
| 2828 EmitJavascriptOverflowCheck(compiler, range(), deopt, result); | 2773 EmitJavascriptOverflowCheck(compiler, range(), deopt, result); |
| 2829 } | 2774 } |
| (...skipping 2726 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5556 compiler->GenerateCall(token_pos(), &label, stub_kind_, locs()); | 5501 compiler->GenerateCall(token_pos(), &label, stub_kind_, locs()); |
| 5557 #if defined(DEBUG) | 5502 #if defined(DEBUG) |
| 5558 __ LoadImmediate(R4, kInvalidObjectPointer, kNoPP); | 5503 __ LoadImmediate(R4, kInvalidObjectPointer, kNoPP); |
| 5559 __ LoadImmediate(R5, kInvalidObjectPointer, kNoPP); | 5504 __ LoadImmediate(R5, kInvalidObjectPointer, kNoPP); |
| 5560 #endif | 5505 #endif |
| 5561 } | 5506 } |
| 5562 | 5507 |
| 5563 } // namespace dart | 5508 } // namespace dart |
| 5564 | 5509 |
| 5565 #endif // defined TARGET_ARCH_ARM64 | 5510 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |