Chromium Code Reviews| 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_X64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. |
| 6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
| 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 2524 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2535 __ CompareImmediate(result, Immediate(-0x20000000000000LL), PP); | 2535 __ CompareImmediate(result, Immediate(-0x20000000000000LL), PP); |
| 2536 __ j(LESS, overflow); | 2536 __ j(LESS, overflow); |
| 2537 __ CompareImmediate(result, Immediate(0x20000000000000LL), PP); | 2537 __ CompareImmediate(result, Immediate(0x20000000000000LL), PP); |
| 2538 __ j(GREATER, overflow); | 2538 __ j(GREATER, overflow); |
| 2539 } | 2539 } |
| 2540 } | 2540 } |
| 2541 | 2541 |
| 2542 | 2542 |
| 2543 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, | 2543 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, |
| 2544 BinarySmiOpInstr* shift_left) { | 2544 BinarySmiOpInstr* shift_left) { |
| 2545 const bool is_truncating = shift_left->IsTruncating(); | |
| 2546 const LocationSummary& locs = *shift_left->locs(); | 2545 const LocationSummary& locs = *shift_left->locs(); |
| 2547 Register left = locs.in(0).reg(); | 2546 Register left = locs.in(0).reg(); |
| 2548 Register result = locs.out(0).reg(); | 2547 Register result = locs.out(0).reg(); |
| 2549 ASSERT(left == result); | 2548 ASSERT(left == result); |
| 2550 Label* deopt = shift_left->CanDeoptimize() ? | 2549 Label* deopt = shift_left->CanDeoptimize() ? |
| 2551 compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp) | 2550 compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp) |
| 2552 : NULL; | 2551 : NULL; |
| 2553 if (locs.in(1).IsConstant()) { | 2552 if (locs.in(1).IsConstant()) { |
| 2554 const Object& constant = locs.in(1).constant(); | 2553 const Object& constant = locs.in(1).constant(); |
| 2555 ASSERT(constant.IsSmi()); | 2554 ASSERT(constant.IsSmi()); |
| 2556 // shlq operation masks the count to 6 bits. | 2555 // shlq operation masks the count to 6 bits. |
| 2557 const intptr_t kCountLimit = 0x3F; | 2556 const intptr_t kCountLimit = 0x3F; |
| 2558 const intptr_t value = Smi::Cast(constant).Value(); | 2557 const intptr_t value = Smi::Cast(constant).Value(); |
| 2559 if (value == 0) { | 2558 ASSERT((0 < value) && (value < kCountLimit)); |
| 2560 // No code needed. | 2559 if (shift_left->can_overflow()) { |
| 2561 } else if ((value < 0) || (value >= kCountLimit)) { | 2560 // Check for overflow. |
| 2562 // This condition may not be known earlier in some cases because | 2561 Register temp = locs.temp(0).reg(); |
| 2563 // of constant propagation, inlining, etc. | 2562 __ movq(temp, left); |
| 2564 if ((value >= kCountLimit) && is_truncating) { | |
| 2565 __ xorq(result, result); | |
| 2566 } else { | |
| 2567 // Result is Mint or exception. | |
| 2568 __ jmp(deopt); | |
| 2569 } | |
| 2570 } else { | |
| 2571 if (!is_truncating) { | |
| 2572 // Check for overflow. | |
| 2573 Register temp = locs.temp(0).reg(); | |
| 2574 __ movq(temp, left); | |
| 2575 __ shlq(left, Immediate(value)); | |
| 2576 __ sarq(left, Immediate(value)); | |
| 2577 __ cmpq(left, temp); | |
| 2578 __ j(NOT_EQUAL, deopt); // Overflow. | |
| 2579 } | |
| 2580 // Shift for result now we know there is no overflow. | |
| 2581 __ shlq(left, Immediate(value)); | 2563 __ shlq(left, Immediate(value)); |
| 2564 __ sarq(left, Immediate(value)); | |
| 2565 __ cmpq(left, temp); | |
| 2566 __ j(NOT_EQUAL, deopt); // Overflow. | |
| 2582 } | 2567 } |
| 2568 // Shift for result now we know there is no overflow. | |
| 2569 __ shlq(left, Immediate(value)); | |
| 2583 if (FLAG_throw_on_javascript_int_overflow) { | 2570 if (FLAG_throw_on_javascript_int_overflow) { |
| 2584 EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result); | 2571 EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result); |
| 2585 } | 2572 } |
| 2586 return; | 2573 return; |
| 2587 } | 2574 } |
| 2588 | 2575 |
| 2589 // Right (locs.in(1)) is not constant. | 2576 // Right (locs.in(1)) is not constant. |
| 2590 Register right = locs.in(1).reg(); | 2577 Register right = locs.in(1).reg(); |
| 2591 Range* right_range = shift_left->right()->definition()->range(); | 2578 Range* right_range = shift_left->right()->definition()->range(); |
| 2592 if (shift_left->left()->BindsToConstant() && !is_truncating) { | 2579 if (shift_left->left()->BindsToConstant() && shift_left->can_overflow()) { |
| 2593 // TODO(srdjan): Implement code below for is_truncating(). | 2580 // TODO(srdjan): Implement code below for is_truncating(). |
| 2594 // If left is constant, we know the maximal allowed size for right. | 2581 // If left is constant, we know the maximal allowed size for right. |
| 2595 const Object& obj = shift_left->left()->BoundConstant(); | 2582 const Object& obj = shift_left->left()->BoundConstant(); |
| 2596 if (obj.IsSmi()) { | 2583 if (obj.IsSmi()) { |
| 2597 const intptr_t left_int = Smi::Cast(obj).Value(); | 2584 const intptr_t left_int = Smi::Cast(obj).Value(); |
| 2598 if (left_int == 0) { | 2585 if (left_int == 0) { |
| 2599 __ CompareImmediate(right, Immediate(0), PP); | 2586 __ CompareImmediate(right, Immediate(0), PP); |
| 2600 __ j(NEGATIVE, deopt); | 2587 __ j(NEGATIVE, deopt); |
| 2601 return; | 2588 return; |
| 2602 } | 2589 } |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 2613 } | 2600 } |
| 2614 if (FLAG_throw_on_javascript_int_overflow) { | 2601 if (FLAG_throw_on_javascript_int_overflow) { |
| 2615 EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result); | 2602 EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result); |
| 2616 } | 2603 } |
| 2617 return; | 2604 return; |
| 2618 } | 2605 } |
| 2619 | 2606 |
| 2620 const bool right_needs_check = | 2607 const bool right_needs_check = |
| 2621 !RangeUtils::IsWithin(right_range, 0, (Smi::kBits - 1)); | 2608 !RangeUtils::IsWithin(right_range, 0, (Smi::kBits - 1)); |
| 2622 ASSERT(right == RCX); // Count must be in RCX | 2609 ASSERT(right == RCX); // Count must be in RCX |
| 2623 if (is_truncating) { | 2610 if (!shift_left->can_overflow()) { |
| 2624 if (right_needs_check) { | 2611 if (right_needs_check) { |
| 2625 const bool right_may_be_negative = | 2612 const bool right_may_be_negative = |
| 2626 (right_range == NULL) || !right_range->IsPositive(); | 2613 (right_range == NULL) || !right_range->IsPositive(); |
| 2627 if (right_may_be_negative) { | 2614 if (right_may_be_negative) { |
| 2628 ASSERT(shift_left->CanDeoptimize()); | 2615 ASSERT(shift_left->CanDeoptimize()); |
| 2629 __ CompareImmediate(right, Immediate(0), PP); | 2616 __ CompareImmediate(right, Immediate(0), PP); |
| 2630 __ j(NEGATIVE, deopt); | 2617 __ j(NEGATIVE, deopt); |
| 2631 } | 2618 } |
| 2632 Label done, is_not_zero; | 2619 Label done, is_not_zero; |
| 2633 __ CompareImmediate(right, | 2620 __ CompareImmediate(right, |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2727 return summary; | 2714 return summary; |
| 2728 } else if (op_kind() == Token::kSHR) { | 2715 } else if (op_kind() == Token::kSHR) { |
| 2729 const intptr_t kNumTemps = 0; | 2716 const intptr_t kNumTemps = 0; |
| 2730 LocationSummary* summary = new(isolate) LocationSummary( | 2717 LocationSummary* summary = new(isolate) LocationSummary( |
| 2731 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2718 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2732 summary->set_in(0, Location::RequiresRegister()); | 2719 summary->set_in(0, Location::RequiresRegister()); |
| 2733 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), RCX)); | 2720 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), RCX)); |
| 2734 summary->set_out(0, Location::SameAsFirstInput()); | 2721 summary->set_out(0, Location::SameAsFirstInput()); |
| 2735 return summary; | 2722 return summary; |
| 2736 } else if (op_kind() == Token::kSHL) { | 2723 } else if (op_kind() == Token::kSHL) { |
| 2737 const intptr_t kNumTemps = !IsTruncating() ? 1 : 0; | 2724 const intptr_t kNumTemps = can_overflow() ? 1 : 0; |
| 2738 LocationSummary* summary = new(isolate) LocationSummary( | 2725 LocationSummary* summary = new(isolate) LocationSummary( |
| 2739 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2726 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2740 summary->set_in(0, Location::RequiresRegister()); | 2727 summary->set_in(0, Location::RequiresRegister()); |
| 2741 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), RCX)); | 2728 summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), RCX)); |
| 2742 if (!IsTruncating()) { | 2729 if (can_overflow()) { |
| 2743 summary->set_temp(0, Location::RequiresRegister()); | 2730 summary->set_temp(0, Location::RequiresRegister()); |
| 2744 } | 2731 } |
| 2745 summary->set_out(0, Location::SameAsFirstInput()); | 2732 summary->set_out(0, Location::SameAsFirstInput()); |
| 2746 return summary; | 2733 return summary; |
| 2747 } else { | 2734 } else { |
| 2748 const intptr_t kNumTemps = 0; | 2735 const intptr_t kNumTemps = 0; |
| 2749 LocationSummary* summary = new(isolate) LocationSummary( | 2736 LocationSummary* summary = new(isolate) LocationSummary( |
| 2750 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2737 isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2751 summary->set_in(0, Location::RequiresRegister()); | 2738 summary->set_in(0, Location::RequiresRegister()); |
| 2752 ConstantInstr* constant = right()->definition()->AsConstant(); | 2739 ConstantInstr* constant = right()->definition()->AsConstant(); |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 2773 if (CanDeoptimize()) { | 2760 if (CanDeoptimize()) { |
| 2774 deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinarySmiOp); | 2761 deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinarySmiOp); |
| 2775 } | 2762 } |
| 2776 | 2763 |
| 2777 if (locs()->in(1).IsConstant()) { | 2764 if (locs()->in(1).IsConstant()) { |
| 2778 const Object& constant = locs()->in(1).constant(); | 2765 const Object& constant = locs()->in(1).constant(); |
| 2779 ASSERT(constant.IsSmi()); | 2766 ASSERT(constant.IsSmi()); |
| 2780 const int64_t imm = reinterpret_cast<int64_t>(constant.raw()); | 2767 const int64_t imm = reinterpret_cast<int64_t>(constant.raw()); |
| 2781 switch (op_kind()) { | 2768 switch (op_kind()) { |
| 2782 case Token::kADD: { | 2769 case Token::kADD: { |
| 2783 if (imm != 0) { | 2770 __ AddImmediate(left, Immediate(imm), PP); |
| 2784 // Checking overflow without emitting an instruction would be wrong. | 2771 if (deopt != NULL) __ j(OVERFLOW, deopt); |
|
Cutch
2014/09/11 17:41:53
Please use curlies (here and elsewhere):
if (deop
| |
| 2785 __ AddImmediate(left, Immediate(imm), PP); | |
| 2786 if (deopt != NULL) __ j(OVERFLOW, deopt); | |
| 2787 } | |
| 2788 break; | 2772 break; |
| 2789 } | 2773 } |
| 2790 case Token::kSUB: { | 2774 case Token::kSUB: { |
| 2791 if (imm != 0) { | 2775 __ SubImmediate(left, Immediate(imm), PP); |
| 2792 // Checking overflow without emitting an instruction would be wrong. | 2776 if (deopt != NULL) __ j(OVERFLOW, deopt); |
| 2793 __ SubImmediate(left, Immediate(imm), PP); | |
| 2794 if (deopt != NULL) __ j(OVERFLOW, deopt); | |
| 2795 } | |
| 2796 break; | 2777 break; |
| 2797 } | 2778 } |
| 2798 case Token::kMUL: { | 2779 case Token::kMUL: { |
| 2799 // Keep left value tagged and untag right value. | 2780 // Keep left value tagged and untag right value. |
| 2800 const intptr_t value = Smi::Cast(constant).Value(); | 2781 const intptr_t value = Smi::Cast(constant).Value(); |
| 2801 if (value == 2) { | 2782 __ MulImmediate(left, Immediate(value), PP); |
| 2802 __ shlq(left, Immediate(1)); | |
| 2803 } else { | |
| 2804 __ MulImmediate(left, Immediate(value), PP); | |
| 2805 } | |
| 2806 if (deopt != NULL) __ j(OVERFLOW, deopt); | 2783 if (deopt != NULL) __ j(OVERFLOW, deopt); |
| 2807 break; | 2784 break; |
| 2808 } | 2785 } |
| 2809 case Token::kTRUNCDIV: { | 2786 case Token::kTRUNCDIV: { |
| 2810 const intptr_t value = Smi::Cast(constant).Value(); | 2787 const intptr_t value = Smi::Cast(constant).Value(); |
| 2811 if (value == 1) { | |
| 2812 // Do nothing. | |
| 2813 break; | |
| 2814 } else if (value == -1) { | |
| 2815 // Check the corner case of dividing the 'MIN_SMI' with -1, in which | |
| 2816 // case we cannot negate the result. | |
| 2817 __ CompareImmediate(left, Immediate(0x8000000000000000), PP); | |
| 2818 __ j(EQUAL, deopt); | |
| 2819 __ negq(left); | |
| 2820 break; | |
| 2821 } | |
| 2822 | |
| 2823 ASSERT(Utils::IsPowerOfTwo(Utils::Abs(value))); | 2788 ASSERT(Utils::IsPowerOfTwo(Utils::Abs(value))); |
| 2824 const intptr_t shift_count = | 2789 const intptr_t shift_count = |
| 2825 Utils::ShiftForPowerOfTwo(Utils::Abs(value)) + kSmiTagSize; | 2790 Utils::ShiftForPowerOfTwo(Utils::Abs(value)) + kSmiTagSize; |
| 2826 ASSERT(kSmiTagSize == 1); | 2791 ASSERT(kSmiTagSize == 1); |
| 2827 Register temp = locs()->temp(0).reg(); | 2792 Register temp = locs()->temp(0).reg(); |
| 2828 __ movq(temp, left); | 2793 __ movq(temp, left); |
| 2829 __ sarq(temp, Immediate(63)); | 2794 __ sarq(temp, Immediate(63)); |
| 2830 ASSERT(shift_count > 1); // 1, -1 case handled above. | 2795 ASSERT(shift_count > 1); // 1, -1 case handled above. |
| 2831 __ shrq(temp, Immediate(64 - shift_count)); | 2796 __ shrq(temp, Immediate(64 - shift_count)); |
| 2832 __ addq(left, temp); | 2797 __ addq(left, temp); |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 2850 } | 2815 } |
| 2851 case Token::kBIT_XOR: { | 2816 case Token::kBIT_XOR: { |
| 2852 // No overflow check. | 2817 // No overflow check. |
| 2853 __ XorImmediate(left, Immediate(imm), PP); | 2818 __ XorImmediate(left, Immediate(imm), PP); |
| 2854 break; | 2819 break; |
| 2855 } | 2820 } |
| 2856 | 2821 |
| 2857 case Token::kSHR: { | 2822 case Token::kSHR: { |
| 2858 // sarq operation masks the count to 6 bits. | 2823 // sarq operation masks the count to 6 bits. |
| 2859 const intptr_t kCountLimit = 0x3F; | 2824 const intptr_t kCountLimit = 0x3F; |
| 2860 intptr_t value = Smi::Cast(constant).Value(); | 2825 const intptr_t value = Smi::Cast(constant).Value(); |
| 2861 | 2826 __ sarq(left, Immediate( |
| 2862 if (value == 0) { | 2827 Utils::Minimum(value + kSmiTagSize, kCountLimit))); |
| 2863 // TODO(vegorov): should be handled outside. | |
| 2864 break; | |
| 2865 } else if (value < 0) { | |
| 2866 // TODO(vegorov): should be handled outside. | |
| 2867 __ jmp(deopt); | |
| 2868 break; | |
| 2869 } | |
| 2870 | |
| 2871 value = value + kSmiTagSize; | |
| 2872 if (value >= kCountLimit) value = kCountLimit; | |
| 2873 | |
| 2874 __ sarq(left, Immediate(value)); | |
| 2875 __ SmiTag(left); | 2828 __ SmiTag(left); |
| 2876 break; | 2829 break; |
| 2877 } | 2830 } |
| 2878 | 2831 |
| 2879 default: | 2832 default: |
| 2880 UNREACHABLE(); | 2833 UNREACHABLE(); |
| 2881 break; | 2834 break; |
| 2882 } | 2835 } |
| 2883 if (FLAG_throw_on_javascript_int_overflow) { | 2836 if (FLAG_throw_on_javascript_int_overflow) { |
| 2884 EmitJavascriptOverflowCheck(compiler, range(), deopt, result); | 2837 EmitJavascriptOverflowCheck(compiler, range(), deopt, result); |
| (...skipping 3093 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5978 __ movq(R10, Immediate(kInvalidObjectPointer)); | 5931 __ movq(R10, Immediate(kInvalidObjectPointer)); |
| 5979 __ movq(RBX, Immediate(kInvalidObjectPointer)); | 5932 __ movq(RBX, Immediate(kInvalidObjectPointer)); |
| 5980 #endif | 5933 #endif |
| 5981 } | 5934 } |
| 5982 | 5935 |
| 5983 } // namespace dart | 5936 } // namespace dart |
| 5984 | 5937 |
| 5985 #undef __ | 5938 #undef __ |
| 5986 | 5939 |
| 5987 #endif // defined TARGET_ARCH_X64 | 5940 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |