| Index: src/a64/lithium-codegen-a64.cc
|
| diff --git a/src/a64/lithium-codegen-a64.cc b/src/a64/lithium-codegen-a64.cc
|
| index 40ef5c6f124501e42e5c4c05735718a84eaa2627..66edbcce6787665085006b5f45b696b9b2dbbf01 100644
|
| --- a/src/a64/lithium-codegen-a64.cc
|
| +++ b/src/a64/lithium-codegen-a64.cc
|
| @@ -1062,6 +1062,15 @@ void LCodeGen::DeoptimizeIfZero(Register rt, LEnvironment* environment) {
|
| }
|
|
|
|
|
| +void LCodeGen::DeoptimizeIfNotZero(Register rt, LEnvironment* environment) {
|
| + Label dont_deopt;
|
| + Deoptimizer::BailoutType bailout_type = DeoptimizeHeader(environment, NULL);
|
| + __ Cbz(rt, &dont_deopt);
|
| + Deoptimize(environment, bailout_type);
|
| + __ Bind(&dont_deopt);
|
| +}
|
| +
|
| +
|
| void LCodeGen::DeoptimizeIfNegative(Register rt, LEnvironment* environment) {
|
| Label dont_deopt;
|
| Deoptimizer::BailoutType bailout_type = DeoptimizeHeader(environment, NULL);
|
| @@ -2581,131 +2590,162 @@ void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
|
| }
|
|
|
|
|
| -void LCodeGen::DoDivI(LDivI* instr) {
|
| - Register dividend = ToRegister32(instr->left());
|
| - Register result = ToRegister32(instr->result());
|
| +void LCodeGen::DoDivConstI(LDivConstI* instr) {
|
| + ASSERT(instr->hydrogen()->RightIsPowerOf2());
|
|
|
| - bool has_power_of_2_divisor = instr->hydrogen()->RightIsPowerOf2();
|
| + HDiv* hinstr = instr->hydrogen();
|
| bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
|
| - bool bailout_on_minus_zero =
|
| - instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
|
| - bool can_be_div_by_zero =
|
| - instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero);
|
| + bool bailout_on_minus_zero = hinstr->CheckFlag(HValue::kBailoutOnMinusZero);
|
| bool all_uses_truncating_to_int32 =
|
| - instr->hydrogen()->CheckFlag(HInstruction::kAllUsesTruncatingToInt32);
|
| + hinstr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32);
|
| + bool is_smi = hinstr->representation().IsSmi();
|
| +
|
| + Register dividend = is_smi ?
|
| + ToRegister(instr->left()) : ToRegister32(instr->left());
|
| + Register result = is_smi ?
|
| + ToRegister(instr->result()) : ToRegister32(instr->result());
|
| + int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right()));
|
| + int32_t power;
|
| + int64_t power_mask;
|
| + Label done;
|
|
|
| - if (has_power_of_2_divisor) {
|
| - ASSERT(instr->temp() == NULL);
|
| - int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right()));
|
| - int32_t power;
|
| - int32_t power_mask;
|
| - Label deopt, done;
|
| -
|
| - ASSERT(divisor != 0);
|
| - if (divisor > 0) {
|
| - power = WhichPowerOf2(divisor);
|
| - power_mask = divisor - 1;
|
| - } else {
|
| - // Check for (0 / -x) as that will produce negative zero.
|
| - if (bailout_on_minus_zero) {
|
| - if (all_uses_truncating_to_int32) {
|
| - // If all uses truncate, and the dividend is zero, the truncated
|
| - // result is zero.
|
| - __ Mov(result, 0);
|
| - __ Cbz(dividend, &done);
|
| - } else {
|
| - __ Cbz(dividend, &deopt);
|
| - }
|
| - }
|
| - // Check for (kMinInt / -1).
|
| - if ((divisor == -1) && can_overflow && !all_uses_truncating_to_int32) {
|
| - // Check for kMinInt by subtracting one and checking for overflow.
|
| - __ Cmp(dividend, 1);
|
| - __ B(vs, &deopt);
|
| + ASSERT(divisor != 0);
|
| + if (divisor > 0) {
|
| + power = WhichPowerOf2(divisor);
|
| + power_mask = divisor - 1;
|
| + } else {
|
| + // Check for (0 / -x) as that will produce negative zero.
|
| + if (bailout_on_minus_zero) {
|
| + if (all_uses_truncating_to_int32) {
|
| + // If all uses truncate, and the dividend is zero, the truncated
|
| + // result is zero.
|
| + __ Mov(result, 0);
|
| + __ Cbz(dividend, &done);
|
| + } else {
|
| + DeoptimizeIfZero(dividend, instr->environment());
|
| }
|
| - power = WhichPowerOf2(-divisor);
|
| - power_mask = -divisor - 1;
|
| }
|
| + // Check for (kMinInt / -1).
|
| + if ((divisor == -1) && can_overflow && !all_uses_truncating_to_int32) {
|
| + // Check for kMinInt (or the smi equivalent) by subtracting one and
|
| + // checking for overflow.
|
| + __ Cmp(dividend, 1);
|
| + DeoptimizeIf(vs, instr->environment());
|
| + }
|
| + power = WhichPowerOf2(-divisor);
|
| + power_mask = -divisor - 1;
|
| + }
|
|
|
| - if (power_mask != 0) {
|
| - if (all_uses_truncating_to_int32) {
|
| - __ Cmp(dividend, 0);
|
| - __ Cneg(result, dividend, lt);
|
| - __ Asr(result, result, power);
|
| - if (divisor > 0) __ Cneg(result, result, lt);
|
| - if (divisor < 0) __ Cneg(result, result, gt);
|
| - return; // Don't fall through to negation below.
|
| - } else {
|
| - // Deoptimize if remainder is not 0. If the least-significant
|
| - // power bits aren't 0, it's not a multiple of 2^power, and
|
| - // therefore, there will be a remainder.
|
| - __ TestAndBranchIfAnySet(dividend, power_mask, &deopt);
|
| - __ Asr(result, dividend, power);
|
| - if (divisor < 0) __ Neg(result, result);
|
| + if (power_mask != 0) {
|
| + if (all_uses_truncating_to_int32) {
|
| + __ Cmp(dividend, 0);
|
| + __ Cneg(result, dividend, lt);
|
| + __ Lsr(result, result, power);
|
| + if (divisor > 0) __ Cneg(result, result, lt);
|
| + if (divisor < 0) __ Cneg(result, result, gt);
|
| + if (is_smi) {
|
| + // Clear the bits shifted into the smi tag.
|
| + __ Bic(result, result, kSmiShiftMask);
|
| }
|
| + return;
|
| } else {
|
| - ASSERT((divisor == 1) || (divisor == -1));
|
| - if (divisor < 0) {
|
| - __ Neg(result, dividend);
|
| - } else {
|
| - __ Mov(result, dividend);
|
| - }
|
| + if (is_smi) power_mask <<= kSmiShift;
|
| +
|
| + // Deoptimize if remainder is not 0. If the least-significant
|
| + // power bits aren't 0, it's not a multiple of 2^power, and
|
| + // therefore, there will be a remainder.
|
| + __ Tst(dividend, power_mask);
|
| + DeoptimizeIf(ne, instr->environment());
|
| + __ Asr(result, dividend, power);
|
| + if (divisor < 0) __ Neg(result, result);
|
| +
|
| + // If there's no remainder, there will be no set bits in the smi tag area
|
| + // after shifting, so the result is a valid smi.
|
| }
|
| - __ B(&done);
|
| - __ Bind(&deopt);
|
| - Deoptimize(instr->environment());
|
| - __ Bind(&done);
|
| } else {
|
| - Register divisor = ToRegister32(instr->right());
|
| + ASSERT((divisor == 1) || (divisor == -1));
|
| + if (divisor < 0) {
|
| + __ Neg(result, dividend);
|
| + } else {
|
| + __ Mov(result, dividend);
|
| + }
|
| + }
|
| + __ Bind(&done);
|
| +}
|
|
|
| - // Issue the division first, and then check for any deopt cases whilst the
|
| - // result is computed.
|
| - __ Sdiv(result, dividend, divisor);
|
|
|
| - if (!all_uses_truncating_to_int32) {
|
| - Label deopt;
|
| - // Check for x / 0.
|
| - if (can_be_div_by_zero) {
|
| - __ Cbz(divisor, &deopt);
|
| - }
|
| +void LCodeGen::DoDivI(LDivI* instr) {
|
| + HDiv* hinstr = instr->hydrogen();
|
| + bool can_overflow = hinstr->CheckFlag(HValue::kCanOverflow);
|
| + bool bailout_on_minus_zero = hinstr->CheckFlag(HValue::kBailoutOnMinusZero);
|
| + bool can_be_div_by_zero = hinstr->CheckFlag(HValue::kCanBeDivByZero);
|
| + bool all_uses_truncating_to_int32 =
|
| + hinstr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32);
|
| + bool is_smi = hinstr->representation().IsSmi();
|
|
|
| - // Check for (0 / -x) as that will produce negative zero.
|
| - if (bailout_on_minus_zero) {
|
| - __ Cmp(divisor, 0);
|
| + Register result = ToRegister32(instr->result());
|
| + Register dividend, divisor;
|
|
|
| - // If the divisor < 0 (mi), compare the dividend, and deopt if it is
|
| - // zero, ie. zero dividend with negative divisor deopts.
|
| - // If the divisor >= 0 (pl, the opposite of mi) set the flags to
|
| - // condition ne, so we don't deopt, ie. positive divisor doesn't deopt.
|
| - __ Ccmp(dividend, 0, NoFlag, mi);
|
| - __ B(eq, &deopt);
|
| - }
|
| + if (is_smi) {
|
| + dividend = ToRegister32(instr->temp2());
|
| + divisor = ToRegister32(instr->temp3());
|
| + __ SmiUntag(dividend, ToRegister(instr->left()));
|
| + __ SmiUntag(divisor, ToRegister(instr->right()));
|
| + } else {
|
| + // Additional temps are not required for the int32 case.
|
| + ASSERT((instr->temp2() == NULL) && (instr->temp3() == NULL));
|
| + dividend = ToRegister32(instr->left());
|
| + divisor = ToRegister32(instr->right());
|
| + }
|
|
|
| - // Check for (kMinInt / -1).
|
| - if (can_overflow) {
|
| - // Test dividend for kMinInt by subtracting one (cmp) and checking for
|
| - // overflow.
|
| - __ Cmp(dividend, 1);
|
| - // If overflow is set, ie. dividend = kMinInt, compare the divisor with
|
| - // -1. If overflow is clear, set the flags for condition ne, as the
|
| - // dividend isn't -1, and thus we shouldn't deopt.
|
| - __ Ccmp(divisor, -1, NoFlag, vs);
|
| - __ B(eq, &deopt);
|
| - }
|
| + // Issue the division first, and then check for any deopt cases whilst the
|
| + // result is computed.
|
| + __ Sdiv(result, dividend, divisor);
|
|
|
| - // Compute remainder and deopt if it's not zero.
|
| - Register remainder = ToRegister32(instr->temp());
|
| - __ Msub(remainder, result, divisor, dividend);
|
| - __ Cbnz(remainder, &deopt);
|
| + if (all_uses_truncating_to_int32) {
|
| + // Equivalent to integer division, so no special handling required.
|
| + // Sdiv gives the correct answer for truncated infinite or minus zero
|
| + // results.
|
| + ASSERT(instr->temp1() == NULL);
|
| + } else {
|
| + // Check for x / 0.
|
| + if (can_be_div_by_zero) {
|
| + // A non-truncated zero divisor has a floating point result, so deopt.
|
| + DeoptimizeIfZero(divisor, instr->environment());
|
| + }
|
|
|
| - Label div_ok;
|
| - __ B(&div_ok);
|
| - __ Bind(&deopt);
|
| - Deoptimize(instr->environment());
|
| - __ Bind(&div_ok);
|
| - } else {
|
| - ASSERT(instr->temp() == NULL);
|
| + // Check for (0 / -x) as that will produce negative zero.
|
| + if (bailout_on_minus_zero) {
|
| + __ Cmp(divisor, 0);
|
| +
|
| + // If the divisor < 0 (mi), compare the dividend, and deopt if it is
|
| + // zero, ie. zero dividend with negative divisor deopts.
|
| + // If the divisor >= 0 (pl, the opposite of mi) set the flags to
|
| + // condition ne, so we don't deopt, ie. positive divisor doesn't deopt.
|
| + __ Ccmp(dividend, 0, NoFlag, mi);
|
| + DeoptimizeIf(eq, instr->environment());
|
| + }
|
| +
|
| + // Check for (kMinInt / -1).
|
| + if (can_overflow) {
|
| + // Test dividend for kMinInt by subtracting one (cmp) and checking for
|
| + // overflow.
|
| + __ Cmp(dividend, 1);
|
| + // If overflow is set, ie. dividend = kMinInt, compare the divisor with
|
| + // -1. If overflow is clear, set the flags for condition ne, as the
|
| + // dividend isn't -1, and thus we shouldn't deopt.
|
| + __ Ccmp(divisor, -1, NoFlag, vs);
|
| + DeoptimizeIf(eq, instr->environment());
|
| }
|
| +
|
| + // Compute remainder and deopt if it's not zero.
|
| + Register remainder = ToRegister32(instr->temp1());
|
| + __ Msub(remainder, result, divisor, dividend);
|
| + DeoptimizeIfNotZero(remainder, instr->environment());
|
| + }
|
| +
|
| + if (is_smi) {
|
| + __ SmiTag(result.X());
|
| }
|
| }
|
|
|
|
|