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

Side by Side Diff: src/a64/lithium-codegen-a64.cc

Issue 175143002: Consistenly handle power-of-2 divisors in division-like operations (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Rebased Created 6 years, 9 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
« no previous file with comments | « src/a64/lithium-a64.cc ('k') | src/arm/lithium-arm.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 the V8 project authors. All rights reserved. 1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 2546 matching lines...) Expand 10 before | Expand all | Expand 10 after
2557 // the special case below. 2557 // the special case below.
2558 if (info()->IsStub() && (type == Deoptimizer::EAGER)) { 2558 if (info()->IsStub() && (type == Deoptimizer::EAGER)) {
2559 type = Deoptimizer::LAZY; 2559 type = Deoptimizer::LAZY;
2560 } 2560 }
2561 2561
2562 Comment(";;; deoptimize: %s", instr->hydrogen()->reason()); 2562 Comment(";;; deoptimize: %s", instr->hydrogen()->reason());
2563 Deoptimize(instr->environment(), &type); 2563 Deoptimize(instr->environment(), &type);
2564 } 2564 }
2565 2565
2566 2566
2567 void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) {
2568 Register dividend = ToRegister32(instr->dividend());
2569 int32_t divisor = instr->divisor();
2570 Register result = ToRegister32(instr->result());
2571 ASSERT(divisor == kMinInt || (divisor != 0 && IsPowerOf2(Abs(divisor))));
2572 ASSERT(!result.is(dividend));
2573
2574 // Check for (0 / -x) that will produce negative zero.
2575 HDiv* hdiv = instr->hydrogen();
2576 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) &&
2577 hdiv->left()->RangeCanInclude(0) && divisor < 0) {
2578 __ Cmp(dividend, 0);
2579 DeoptimizeIf(eq, instr->environment());
2580 }
2581 // Check for (kMinInt / -1).
2582 if (hdiv->CheckFlag(HValue::kCanOverflow) &&
2583 hdiv->left()->RangeCanInclude(kMinInt) && divisor == -1) {
2584 __ Cmp(dividend, kMinInt);
2585 DeoptimizeIf(eq, instr->environment());
2586 }
2587 // Deoptimize if remainder will not be 0.
2588 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
2589 divisor != 1 && divisor != -1) {
2590 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
2591 __ Tst(dividend, mask);
2592 DeoptimizeIf(ne, instr->environment());
2593 }
2594
2595 if (divisor == -1) { // Nice shortcut, not needed for correctness.
2596 __ Neg(result, dividend);
2597 return;
2598 }
2599 int32_t shift = WhichPowerOf2Abs(divisor);
2600 if (shift == 0) {
2601 __ Mov(result, dividend);
2602 } else if (shift == 1) {
2603 __ Add(result, dividend, Operand(dividend, LSR, 31));
2604 } else {
2605 __ Mov(result, Operand(dividend, ASR, 31));
2606 __ Add(result, dividend, Operand(result, LSR, 32 - shift));
2607 }
2608 if (shift > 0) __ Mov(result, Operand(result, ASR, shift));
2609 if (divisor < 0) __ Neg(result, result);
2610 }
2611
2612
2567 void LCodeGen::DoDivI(LDivI* instr) { 2613 void LCodeGen::DoDivI(LDivI* instr) {
2568 if (!instr->is_flooring() && instr->hydrogen()->RightIsPowerOf2()) {
2569 HDiv* hdiv = instr->hydrogen();
2570 Register dividend = ToRegister32(instr->left());
2571 int32_t divisor = hdiv->right()->GetInteger32Constant();
2572 Register result = ToRegister32(instr->result());
2573 ASSERT(!result.is(dividend));
2574
2575 // Check for (0 / -x) that will produce negative zero.
2576 if (hdiv->left()->RangeCanInclude(0) && divisor < 0 &&
2577 hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
2578 __ Cmp(dividend, 0);
2579 DeoptimizeIf(eq, instr->environment());
2580 }
2581 // Check for (kMinInt / -1).
2582 if (hdiv->left()->RangeCanInclude(kMinInt) && divisor == -1 &&
2583 hdiv->CheckFlag(HValue::kCanOverflow)) {
2584 __ Cmp(dividend, kMinInt);
2585 DeoptimizeIf(eq, instr->environment());
2586 }
2587 // Deoptimize if remainder will not be 0.
2588 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
2589 Abs(divisor) != 1) {
2590 __ Tst(dividend, Abs(divisor) - 1);
2591 DeoptimizeIf(ne, instr->environment());
2592 }
2593 if (divisor == -1) { // Nice shortcut, not needed for correctness.
2594 __ Neg(result, dividend);
2595 return;
2596 }
2597 int32_t shift = WhichPowerOf2(Abs(divisor));
2598 if (shift == 0) {
2599 __ Mov(result, dividend);
2600 } else if (shift == 1) {
2601 __ Add(result, dividend, Operand(dividend, LSR, 31));
2602 } else {
2603 __ Mov(result, Operand(dividend, ASR, 31));
2604 __ Add(result, dividend, Operand(result, LSR, 32 - shift));
2605 }
2606 if (shift > 0) __ Mov(result, Operand(result, ASR, shift));
2607 if (divisor < 0) __ Neg(result, result);
2608 return;
2609 }
2610
2611 Register dividend = ToRegister32(instr->left()); 2614 Register dividend = ToRegister32(instr->left());
2612 Register divisor = ToRegister32(instr->right()); 2615 Register divisor = ToRegister32(instr->right());
2613 Register result = ToRegister32(instr->result()); 2616 Register result = ToRegister32(instr->result());
2614 HValue* hdiv = instr->hydrogen_value(); 2617 HValue* hdiv = instr->hydrogen_value();
2615 2618
2616 // Issue the division first, and then check for any deopt cases whilst the 2619 // Issue the division first, and then check for any deopt cases whilst the
2617 // result is computed. 2620 // result is computed.
2618 __ Sdiv(result, dividend, divisor); 2621 __ Sdiv(result, dividend, divisor);
2619 2622
2620 if (hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) { 2623 if (hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
(...skipping 1152 matching lines...) Expand 10 before | Expand all | Expand 10 after
3773 __ Fccmp(input, input, NoFlag, eq); 3776 __ Fccmp(input, input, NoFlag, eq);
3774 __ B(&done, eq); 3777 __ B(&done, eq);
3775 3778
3776 __ Bind(&deopt); 3779 __ Bind(&deopt);
3777 Deoptimize(instr->environment()); 3780 Deoptimize(instr->environment());
3778 3781
3779 __ Bind(&done); 3782 __ Bind(&done);
3780 } 3783 }
3781 3784
3782 3785
3783 void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) { 3786 void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
3787 Register dividend = ToRegister32(instr->dividend());
3788 int32_t divisor = instr->divisor();
3789 ASSERT(dividend.is(ToRegister32(instr->result())));
3790
3791 // If the divisor is positive, things are easy: There can be no deopts and we
3792 // can simply do an arithmetic right shift.
3793 if (divisor == 1) return;
3794 int32_t shift = WhichPowerOf2Abs(divisor);
3795 if (divisor > 1) {
3796 __ Mov(dividend, Operand(dividend, ASR, shift));
3797 return;
3798 }
3799
3800 // If the divisor is negative, we have to negate and handle edge cases.
3801 Label not_kmin_int, done;
3802 __ Negs(dividend, dividend);
3803 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3804 DeoptimizeIf(eq, instr->environment());
3805 }
3806 if (instr->hydrogen()->left()->RangeCanInclude(kMinInt)) {
3807 // Note that we could emit branch-free code, but that would need one more
3808 // register.
3809 __ B(vc, &not_kmin_int);
3810 if (divisor == -1) {
3811 Deoptimize(instr->environment());
3812 } else {
3813 __ Mov(dividend, kMinInt / divisor);
3814 __ B(&done);
3815 }
3816 }
3817 __ bind(&not_kmin_int);
3818 __ Mov(dividend, Operand(dividend, ASR, shift));
3819 __ bind(&done);
3820 }
3821
3822
3823 void LCodeGen::DoFlooringDivI(LFlooringDivI* instr) {
3824 Register dividend = ToRegister32(instr->dividend());
3825 Register divisor = ToRegister32(instr->divisor());
3826 Register remainder = ToRegister32(instr->temp());
3784 Register result = ToRegister32(instr->result()); 3827 Register result = ToRegister32(instr->result());
3785 Register left = ToRegister32(instr->left());
3786 Register right = ToRegister32(instr->right());
3787 Register remainder = ToRegister32(instr->temp());
3788 3828
3789 // This can't cause an exception on ARM, so we can speculatively 3829 // This can't cause an exception on ARM, so we can speculatively
3790 // execute it already now. 3830 // execute it already now.
3791 __ Sdiv(result, left, right); 3831 __ Sdiv(result, dividend, divisor);
3792 3832
3793 // Check for x / 0. 3833 // Check for x / 0.
3794 DeoptimizeIfZero(right, instr->environment()); 3834 DeoptimizeIfZero(divisor, instr->environment());
3795 3835
3796 // Check for (kMinInt / -1). 3836 // Check for (kMinInt / -1).
3797 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { 3837 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
3798 // The V flag will be set iff left == kMinInt. 3838 // The V flag will be set iff dividend == kMinInt.
3799 __ Cmp(left, 1); 3839 __ Cmp(dividend, 1);
3800 __ Ccmp(right, -1, NoFlag, vs); 3840 __ Ccmp(divisor, -1, NoFlag, vs);
3801 DeoptimizeIf(eq, instr->environment()); 3841 DeoptimizeIf(eq, instr->environment());
3802 } 3842 }
3803 3843
3804 // Check for (0 / -x) that will produce negative zero. 3844 // Check for (0 / -x) that will produce negative zero.
3805 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 3845 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3806 __ Cmp(right, 0); 3846 __ Cmp(divisor, 0);
3807 __ Ccmp(left, 0, ZFlag, mi); 3847 __ Ccmp(dividend, 0, ZFlag, mi);
3808 // "right" can't be null because the code would have already been 3848 // "divisor" can't be null because the code would have already been
3809 // deoptimized. The Z flag is set only if (right < 0) and (left == 0). 3849 // deoptimized. The Z flag is set only if (divisor < 0) and (dividend == 0).
3810 // In this case we need to deoptimize to produce a -0. 3850 // In this case we need to deoptimize to produce a -0.
3811 DeoptimizeIf(eq, instr->environment()); 3851 DeoptimizeIf(eq, instr->environment());
3812 } 3852 }
3813 3853
3814 Label done; 3854 Label done;
3815 // If both operands have the same sign then we are done. 3855 // If both operands have the same sign then we are done.
3816 __ Eor(remainder, left, right); 3856 __ Eor(remainder, dividend, divisor);
3817 __ Tbz(remainder, kWSignBit, &done); 3857 __ Tbz(remainder, kWSignBit, &done);
3818 3858
3819 // Check if the result needs to be corrected. 3859 // Check if the result needs to be corrected.
3820 __ Msub(remainder, result, right, left); 3860 __ Msub(remainder, result, divisor, dividend);
3821 __ Cbz(remainder, &done); 3861 __ Cbz(remainder, &done);
3822 __ Sub(result, result, 1); 3862 __ Sub(result, result, 1);
3823 3863
3824 __ Bind(&done); 3864 __ Bind(&done);
3825 } 3865 }
3826 3866
3827 3867
3828 void LCodeGen::DoMathLog(LMathLog* instr) { 3868 void LCodeGen::DoMathLog(LMathLog* instr) {
3829 ASSERT(instr->IsMarkedAsCall()); 3869 ASSERT(instr->IsMarkedAsCall());
3830 ASSERT(ToDoubleRegister(instr->value()).is(d0)); 3870 ASSERT(ToDoubleRegister(instr->value()).is(d0));
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after
3999 if (op == HMathMinMax::kMathMax) { 4039 if (op == HMathMinMax::kMathMax) {
4000 __ Fmax(result, left, right); 4040 __ Fmax(result, left, right);
4001 } else { 4041 } else {
4002 ASSERT(op == HMathMinMax::kMathMin); 4042 ASSERT(op == HMathMinMax::kMathMin);
4003 __ Fmin(result, left, right); 4043 __ Fmin(result, left, right);
4004 } 4044 }
4005 } 4045 }
4006 } 4046 }
4007 4047
4008 4048
4049 void LCodeGen::DoModByPowerOf2I(LModByPowerOf2I* instr) {
4050 Register dividend = ToRegister32(instr->dividend());
4051 int32_t divisor = instr->divisor();
4052 ASSERT(dividend.is(ToRegister32(instr->result())));
4053
4054 // Theoretically, a variation of the branch-free code for integer division by
4055 // a power of 2 (calculating the remainder via an additional multiplication
4056 // (which gets simplified to an 'and') and subtraction) should be faster, and
4057 // this is exactly what GCC and clang emit. Nevertheless, benchmarks seem to
4058 // indicate that positive dividends are heavily favored, so the branching
4059 // version performs better.
4060 HMod* hmod = instr->hydrogen();
4061 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
4062 Label dividend_is_not_negative, done;
4063 if (hmod->left()->CanBeNegative()) {
4064 __ Cmp(dividend, 0);
4065 __ B(pl, &dividend_is_not_negative);
4066 // Note that this is correct even for kMinInt operands.
4067 __ Neg(dividend, dividend);
4068 __ And(dividend, dividend, Operand(mask));
4069 __ Neg(dividend, dividend);
4070 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
4071 DeoptimizeIf(eq, instr->environment());
4072 }
4073 __ B(&done);
4074 }
4075
4076 __ bind(&dividend_is_not_negative);
4077 __ And(dividend, dividend, Operand(mask));
4078 __ bind(&done);
4079 }
4080
4081
4009 void LCodeGen::DoModI(LModI* instr) { 4082 void LCodeGen::DoModI(LModI* instr) {
4010 HMod* hmod = instr->hydrogen(); 4083 Register dividend = ToRegister32(instr->left());
4011 HValue* hleft = hmod->left(); 4084 Register divisor = ToRegister32(instr->right());
4012 HValue* hright = hmod->right(); 4085 Register result = ToRegister32(instr->result());
4013 4086
4014 Label done; 4087 Label deopt, done;
4015 Register result = ToRegister32(instr->result()); 4088 // modulo = dividend - quotient * divisor
4016 Register dividend = ToRegister32(instr->left()); 4089 __ Sdiv(result, dividend, divisor);
4017 4090 if (instr->hydrogen()->right()->CanBeZero()) {
4018 bool need_minus_zero_check = (hmod->CheckFlag(HValue::kBailoutOnMinusZero) && 4091 // Combine the deoptimization sites.
4019 hleft->CanBeNegative() && hmod->CanBeZero()); 4092 Label ok;
4020 4093 __ Cbnz(divisor, &ok);
4021 if (hmod->RightIsPowerOf2()) { 4094 __ Bind(&deopt);
4022 // Note: The code below even works when right contains kMinInt. 4095 Deoptimize(instr->environment());
4023 int32_t divisor = Abs(hright->GetInteger32Constant()); 4096 __ Bind(&ok);
4024 4097 }
4025 if (hleft->CanBeNegative()) { 4098 __ Msub(result, result, divisor, dividend);
4026 __ Cmp(dividend, 0); 4099 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero) &&
4027 __ Cneg(result, dividend, mi); 4100 instr->hydrogen()->left()->CanBeNegative() &&
4028 __ And(result, result, divisor - 1); 4101 instr->hydrogen()->CanBeZero()) {
4029 __ Cneg(result, result, mi); 4102 __ Cbnz(result, &done);
4030 if (need_minus_zero_check) { 4103 if (deopt.is_bound()) { // TODO(all) This is a hack, remove this...
4031 __ Cbnz(result, &done); 4104 __ Tbnz(dividend, kWSignBit, &deopt);
4032 // The result is 0. Deoptimize if the dividend was negative.
4033 DeoptimizeIf(mi, instr->environment());
4034 }
4035 } else { 4105 } else {
4036 __ And(result, dividend, divisor - 1); 4106 DeoptimizeIfNegative(dividend, instr->environment());
4037 }
4038
4039 } else {
4040 Label deopt;
4041 Register divisor = ToRegister32(instr->right());
4042 // Compute:
4043 // modulo = dividend - quotient * divisor
4044 __ Sdiv(result, dividend, divisor);
4045 if (hright->CanBeZero()) {
4046 // Combine the deoptimization sites.
4047 Label ok;
4048 __ Cbnz(divisor, &ok);
4049 __ Bind(&deopt);
4050 Deoptimize(instr->environment());
4051 __ Bind(&ok);
4052 }
4053 __ Msub(result, result, divisor, dividend);
4054 if (need_minus_zero_check) {
4055 __ Cbnz(result, &done);
4056 if (deopt.is_bound()) {
4057 __ Tbnz(dividend, kWSignBit, &deopt);
4058 } else {
4059 DeoptimizeIfNegative(dividend, instr->environment());
4060 }
4061 } 4107 }
4062 } 4108 }
4063 __ Bind(&done); 4109 __ Bind(&done);
4064 } 4110 }
4065 4111
4066 4112
4067 void LCodeGen::DoMulConstIS(LMulConstIS* instr) { 4113 void LCodeGen::DoMulConstIS(LMulConstIS* instr) {
4068 ASSERT(instr->hydrogen()->representation().IsSmiOrInteger32()); 4114 ASSERT(instr->hydrogen()->representation().IsSmiOrInteger32());
4069 bool is_smi = instr->hydrogen()->representation().IsSmi(); 4115 bool is_smi = instr->hydrogen()->representation().IsSmi();
4070 Register result = 4116 Register result =
(...skipping 1595 matching lines...) Expand 10 before | Expand all | Expand 10 after
5666 __ Bind(&out_of_object); 5712 __ Bind(&out_of_object);
5667 __ Ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset)); 5713 __ Ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
5668 // Index is equal to negated out of object property index plus 1. 5714 // Index is equal to negated out of object property index plus 1.
5669 __ Sub(result, result, Operand::UntagSmiAndScale(index, kPointerSizeLog2)); 5715 __ Sub(result, result, Operand::UntagSmiAndScale(index, kPointerSizeLog2));
5670 __ Ldr(result, FieldMemOperand(result, 5716 __ Ldr(result, FieldMemOperand(result,
5671 FixedArray::kHeaderSize - kPointerSize)); 5717 FixedArray::kHeaderSize - kPointerSize));
5672 __ Bind(&done); 5718 __ Bind(&done);
5673 } 5719 }
5674 5720
5675 } } // namespace v8::internal 5721 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/a64/lithium-a64.cc ('k') | src/arm/lithium-arm.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698