From: plind44@gmail.com Date: Fri, 14 Mar 2014 19:03:10 +0000 (+0000) Subject: MIPS: Fix Lithium div, mod and floor. X-Git-Tag: upstream/4.7.83~10252 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2970f43330044e49d7f7a0e809e1da6846a469e5;p=platform%2Fupstream%2Fv8.git MIPS: Fix Lithium div, mod and floor. BUG= R=plind44@gmail.com Review URL: https://codereview.chromium.org/200423004 Patch from Balazs Kilvady . git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19949 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc index 0f19ce2..edbc9b5 100644 --- a/src/mips/lithium-codegen-mips.cc +++ b/src/mips/lithium-codegen-mips.cc @@ -1100,6 +1100,34 @@ void LCodeGen::DoModByPowerOf2I(LModByPowerOf2I* instr) { } +void LCodeGen::DoModByConstI(LModByConstI* instr) { + Register dividend = ToRegister(instr->dividend()); + int32_t divisor = instr->divisor(); + Register result = ToRegister(instr->result()); + ASSERT(!dividend.is(result)); + + if (divisor == 0) { + DeoptimizeIf(al, instr->environment()); + return; + } + + __ FlooringDiv(result, dividend, Abs(divisor)); + __ srl(at, dividend, 31); + __ Addu(result, result, at); + __ Mul(result, result, Operand(Abs(divisor))); + __ Subu(result, dividend, Operand(result)); + + // Check for negative zero. + HMod* hmod = instr->hydrogen(); + if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { + Label remainder_not_zero; + __ Branch(&remainder_not_zero, ne, result, Operand(zero_reg)); + DeoptimizeIf(lt, instr->environment(), dividend, Operand(zero_reg)); + __ bind(&remainder_not_zero); + } +} + + void LCodeGen::DoModI(LModI* instr) { HMod* hmod = instr->hydrogen(); const Register left_reg = ToRegister(instr->left()); @@ -1141,6 +1169,80 @@ void LCodeGen::DoModI(LModI* instr) { } +void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) { + Register dividend = ToRegister(instr->dividend()); + int32_t divisor = instr->divisor(); + Register result = ToRegister(instr->result()); + ASSERT(divisor == kMinInt || (divisor != 0 && IsPowerOf2(Abs(divisor)))); + ASSERT(!result.is(dividend)); + + // Check for (0 / -x) that will produce negative zero. + HDiv* hdiv = instr->hydrogen(); + if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) { + DeoptimizeIf(eq, instr->environment(), dividend, Operand(zero_reg)); + } + // Check for (kMinInt / -1). + if (hdiv->CheckFlag(HValue::kCanOverflow) && divisor == -1) { + DeoptimizeIf(eq, instr->environment(), dividend, Operand(kMinInt)); + } + // Deoptimize if remainder will not be 0. + if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) && + divisor != 1 && divisor != -1) { + int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1); + __ And(at, dividend, Operand(mask)); + DeoptimizeIf(ne, instr->environment(), at, Operand(zero_reg)); + } + + if (divisor == -1) { // Nice shortcut, not needed for correctness. + __ Subu(result, zero_reg, dividend); + return; + } + uint16_t shift = WhichPowerOf2Abs(divisor); + if (shift == 0) { + __ Move(result, dividend); + } else if (shift == 1) { + __ srl(result, dividend, 31); + __ Addu(result, dividend, Operand(result)); + } else { + __ sra(result, dividend, 31); + __ srl(result, result, 32 - shift); + __ Addu(result, dividend, Operand(result)); + } + if (shift > 0) __ sra(result, result, shift); + if (divisor < 0) __ Subu(result, zero_reg, result); +} + + +void LCodeGen::DoDivByConstI(LDivByConstI* instr) { + Register dividend = ToRegister(instr->dividend()); + int32_t divisor = instr->divisor(); + Register result = ToRegister(instr->result()); + ASSERT(!dividend.is(result)); + + if (divisor == 0) { + DeoptimizeIf(al, instr->environment()); + return; + } + + // Check for (0 / -x) that will produce negative zero. + HDiv* hdiv = instr->hydrogen(); + if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) { + DeoptimizeIf(eq, instr->environment(), dividend, Operand(zero_reg)); + } + + __ FlooringDiv(result, dividend, Abs(divisor)); + __ srl(at, dividend, 31); + __ Addu(result, result, Operand(at)); + if (divisor < 0) __ Subu(result, zero_reg, result); + + if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) { + __ Mul(scratch0(), result, Operand(divisor)); + __ Subu(scratch0(), scratch0(), dividend); + DeoptimizeIf(ne, instr->environment(), scratch0(), Operand(zero_reg)); + } +} + + void LCodeGen::DoDivI(LDivI* instr) { HBinaryOperation* hdiv = instr->hydrogen(); const Register left = ToRegister(instr->left()); @@ -1173,11 +1275,24 @@ void LCodeGen::DoDivI(LDivI* instr) { __ bind(&left_not_min_int); } - if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) { + if (hdiv->IsMathFloorOfDiv()) { + // We performed a truncating division. Correct the result if necessary. + Label done; + Register remainder = scratch0(); + __ mfhi(remainder); + __ mflo(result); + __ Branch(&done, eq, remainder, Operand(zero_reg), USE_DELAY_SLOT); + __ Xor(remainder, remainder, Operand(right)); + __ Branch(&done, ge, remainder, Operand(zero_reg)); + __ Subu(result, result, Operand(1)); + __ bind(&done); + } else if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) { __ mfhi(result); DeoptimizeIf(ne, instr->environment(), result, Operand(zero_reg)); + __ mflo(result); + } else { + __ mflo(result); } - __ mflo(result); } @@ -1220,7 +1335,6 @@ void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) { if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) { // Note that we could emit branch-free code, but that would need one more // register. - __ Xor(at, scratch, result); if (divisor == -1) { DeoptimizeIf(ge, instr->environment(), at, Operand(zero_reg)); @@ -1261,50 +1375,6 @@ void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) { } -void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) { - const Register result = ToRegister(instr->result()); - const Register left = ToRegister(instr->left()); - const Register remainder = ToRegister(instr->temp()); - const Register scratch = scratch0(); - - Label done; - const Register right = ToRegister(instr->right()); - - // On MIPS div is asynchronous - it will run in the background while we - // check for special cases. - __ div(left, right); - - // Check for x / 0. - DeoptimizeIf(eq, instr->environment(), right, Operand(zero_reg)); - - // Check for (0 / -x) that will produce negative zero. - if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { - Label left_not_zero; - __ Branch(&left_not_zero, ne, left, Operand(zero_reg)); - DeoptimizeIf(lt, instr->environment(), right, Operand(zero_reg)); - __ bind(&left_not_zero); - } - - // Check for (kMinInt / -1). - if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { - Label left_not_min_int; - __ Branch(&left_not_min_int, ne, left, Operand(kMinInt)); - DeoptimizeIf(eq, instr->environment(), right, Operand(-1)); - __ bind(&left_not_min_int); - } - - __ mfhi(remainder); - __ mflo(result); - - // We performed a truncating division. Correct the result if necessary. - __ Branch(&done, eq, remainder, Operand(zero_reg), USE_DELAY_SLOT); - __ Xor(scratch , remainder, Operand(right)); - __ Branch(&done, ge, scratch, Operand(zero_reg)); - __ Subu(result, result, Operand(1)); - __ bind(&done); -} - - void LCodeGen::DoMulI(LMulI* instr) { Register scratch = scratch0(); Register result = ToRegister(instr->result()); diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc index ca3c28f..d2473fc 100644 --- a/src/mips/lithium-mips.cc +++ b/src/mips/lithium-mips.cc @@ -1255,6 +1255,41 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) { } +LInstruction* LChunkBuilder::DoDivByPowerOf2I(HDiv* instr) { + ASSERT(instr->representation().IsSmiOrInteger32()); + ASSERT(instr->left()->representation().Equals(instr->representation())); + ASSERT(instr->right()->representation().Equals(instr->representation())); + LOperand* dividend = UseRegister(instr->left()); + int32_t divisor = instr->right()->GetInteger32Constant(); + LInstruction* result = DefineAsRegister(new(zone()) LDivByPowerOf2I( + dividend, divisor)); + if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) || + (instr->CheckFlag(HValue::kCanOverflow) && divisor == -1) || + (!instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) && + divisor != 1 && divisor != -1)) { + result = AssignEnvironment(result); + } + return result; +} + + +LInstruction* LChunkBuilder::DoDivByConstI(HDiv* instr) { + ASSERT(instr->representation().IsInteger32()); + ASSERT(instr->left()->representation().Equals(instr->representation())); + ASSERT(instr->right()->representation().Equals(instr->representation())); + LOperand* dividend = UseRegister(instr->left()); + int32_t divisor = instr->right()->GetInteger32Constant(); + LInstruction* result = DefineAsRegister(new(zone()) LDivByConstI( + dividend, divisor)); + if (divisor == 0 || + (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) || + !instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) { + result = AssignEnvironment(result); + } + return result; +} + + LInstruction* LChunkBuilder::DoDivI(HBinaryOperation* instr) { ASSERT(instr->representation().IsSmiOrInteger32()); ASSERT(instr->left()->representation().Equals(instr->representation())); @@ -1268,7 +1303,13 @@ LInstruction* LChunkBuilder::DoDivI(HBinaryOperation* instr) { LInstruction* LChunkBuilder::DoDiv(HDiv* instr) { if (instr->representation().IsSmiOrInteger32()) { - return DoDivI(instr); + if (instr->RightIsPowerOf2()) { + return DoDivByPowerOf2I(instr); + } else if (instr->right()->IsConstant()) { + return DoDivByConstI(instr); + } else { + return DoDivI(instr); + } } else if (instr->representation().IsDouble()) { return DoArithmeticD(Token::DIV, instr); } else { @@ -1308,15 +1349,10 @@ LInstruction* LChunkBuilder::DoFlooringDivByConstI(HMathFloorOfDiv* instr) { LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) { if (instr->RightIsPowerOf2()) { return DoFlooringDivByPowerOf2I(instr); - } else if (instr->right()->IsConstant()) { - return DoFlooringDivByConstI(instr); + } else if (false && instr->right()->IsConstant()) { + return DoFlooringDivByConstI(instr); // TODO(svenpanne) Fix and re-enable. } else { - HValue* right = instr->right(); - LOperand* dividend = UseRegister(instr->left()); - LOperand* divisor = UseRegisterOrConstant(right); - LOperand* remainder = TempRegister(); - return AssignEnvironment(DefineAsRegister( - new(zone()) LMathFloorOfDiv(dividend, divisor, remainder))); + return DoDivI(instr); } } @@ -1336,6 +1372,21 @@ LInstruction* LChunkBuilder::DoModByPowerOf2I(HMod* instr) { } +LInstruction* LChunkBuilder::DoModByConstI(HMod* instr) { + ASSERT(instr->representation().IsSmiOrInteger32()); + ASSERT(instr->left()->representation().Equals(instr->representation())); + ASSERT(instr->right()->representation().Equals(instr->representation())); + LOperand* dividend = UseRegister(instr->left()); + int32_t divisor = instr->right()->GetInteger32Constant(); + LInstruction* result = DefineAsRegister(new(zone()) LModByConstI( + dividend, divisor)); + if (divisor == 0 || instr->CheckFlag(HValue::kBailoutOnMinusZero)) { + result = AssignEnvironment(result); + } + return result; +} + + LInstruction* LChunkBuilder::DoModI(HMod* instr) { ASSERT(instr->representation().IsSmiOrInteger32()); ASSERT(instr->left()->representation().Equals(instr->representation())); diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h index 1cfcbc8..81f7fb6 100644 --- a/src/mips/lithium-mips.h +++ b/src/mips/lithium-mips.h @@ -86,6 +86,8 @@ class LCodeGen; V(DebugBreak) \ V(DeclareGlobals) \ V(Deoptimize) \ + V(DivByConstI) \ + V(DivByPowerOf2I) \ V(DivI) \ V(DoubleToI) \ V(DoubleBits) \ @@ -130,12 +132,12 @@ class LCodeGen; V(MathExp) \ V(MathClz32) \ V(MathFloor) \ - V(MathFloorOfDiv) \ V(MathLog) \ V(MathMinMax) \ V(MathPowHalf) \ V(MathRound) \ V(MathSqrt) \ + V(ModByConstI) \ V(ModByPowerOf2I) \ V(ModI) \ V(MulI) \ @@ -635,6 +637,24 @@ class LModByPowerOf2I V8_FINAL : public LTemplateInstruction<1, 1, 0> { }; +class LModByConstI V8_FINAL : public LTemplateInstruction<1, 1, 0> { + public: + LModByConstI(LOperand* dividend, int32_t divisor) { + inputs_[0] = dividend; + divisor_ = divisor; + } + + LOperand* dividend() { return inputs_[0]; } + int32_t divisor() const { return divisor_; } + + DECLARE_CONCRETE_INSTRUCTION(ModByConstI, "mod-by-const-i") + DECLARE_HYDROGEN_ACCESSOR(Mod) + + private: + int32_t divisor_; +}; + + class LModI V8_FINAL : public LTemplateInstruction<1, 2, 3> { public: LModI(LOperand* left, @@ -651,6 +671,42 @@ class LModI V8_FINAL : public LTemplateInstruction<1, 2, 3> { }; +class LDivByPowerOf2I V8_FINAL : public LTemplateInstruction<1, 1, 0> { + public: + LDivByPowerOf2I(LOperand* dividend, int32_t divisor) { + inputs_[0] = dividend; + divisor_ = divisor; + } + + LOperand* dividend() { return inputs_[0]; } + int32_t divisor() const { return divisor_; } + + DECLARE_CONCRETE_INSTRUCTION(DivByPowerOf2I, "div-by-power-of-2-i") + DECLARE_HYDROGEN_ACCESSOR(Div) + + private: + int32_t divisor_; +}; + + +class LDivByConstI V8_FINAL : public LTemplateInstruction<1, 1, 0> { + public: + LDivByConstI(LOperand* dividend, int32_t divisor) { + inputs_[0] = dividend; + divisor_ = divisor; + } + + LOperand* dividend() { return inputs_[0]; } + int32_t divisor() const { return divisor_; } + + DECLARE_CONCRETE_INSTRUCTION(DivByConstI, "div-by-const-i") + DECLARE_HYDROGEN_ACCESSOR(Div) + + private: + int32_t divisor_; +}; + + class LDivI V8_FINAL : public LTemplateInstruction<1, 2, 0> { public: LDivI(LOperand* left, LOperand* right) { @@ -704,25 +760,6 @@ class LFlooringDivByConstI V8_FINAL : public LTemplateInstruction<1, 1, 0> { }; -class LMathFloorOfDiv V8_FINAL : public LTemplateInstruction<1, 2, 1> { - public: - LMathFloorOfDiv(LOperand* left, - LOperand* right, - LOperand* temp = NULL) { - inputs_[0] = left; - inputs_[1] = right; - temps_[0] = temp; - } - - LOperand* left() { return inputs_[0]; } - LOperand* right() { return inputs_[1]; } - LOperand* temp() { return temps_[0]; } - - DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv, "math-floor-of-div") - DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv) -}; - - class LMulI V8_FINAL : public LTemplateInstruction<1, 2, 0> { public: LMulI(LOperand* left, LOperand* right) { @@ -2639,8 +2676,11 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase { LInstruction* DoMathSqrt(HUnaryMathOperation* instr); LInstruction* DoMathPowHalf(HUnaryMathOperation* instr); LInstruction* DoMathClz32(HUnaryMathOperation* instr); + LInstruction* DoDivByPowerOf2I(HDiv* instr); + LInstruction* DoDivByConstI(HDiv* instr); LInstruction* DoDivI(HBinaryOperation* instr); LInstruction* DoModByPowerOf2I(HMod* instr); + LInstruction* DoModByConstI(HMod* instr); LInstruction* DoModI(HMod* instr); LInstruction* DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr); LInstruction* DoFlooringDivByConstI(HMathFloorOfDiv* instr);