OLD | NEW |
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 Loading... |
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 Loading... |
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, ¬_kmin_int); |
| 3810 if (divisor == -1) { |
| 3811 Deoptimize(instr->environment()); |
| 3812 } else { |
| 3813 __ Mov(dividend, kMinInt / divisor); |
| 3814 __ B(&done); |
| 3815 } |
| 3816 } |
| 3817 __ bind(¬_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 Loading... |
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, ÷nd_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(÷nd_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 Loading... |
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 |
OLD | NEW |