Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(649)

Side by Side Diff: runtime/vm/intermediate_language_arm64.cc

Issue 564843002: Initial steps towards cleaning up integer arithmetic IR. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698