Reland "Handle non-power-of-2 divisors in division-like operations".

Fixed the flooring div bug and added a test case.

R=svenpanne@chromium.org

Review URL: https://codereview.chromium.org/191293012

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19749 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
bmeurer@chromium.org 2014-03-10 10:39:17 +00:00
parent a72468496d
commit bf86e624d4
29 changed files with 964 additions and 359 deletions

View File

@ -1369,7 +1369,7 @@ LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
LInstruction* LChunkBuilder::DoDivByPowerOf2I(HDiv* instr) {
ASSERT(instr->representation().IsSmiOrInteger32());
ASSERT(instr->representation().IsInteger32());
ASSERT(instr->left()->representation().Equals(instr->representation()));
ASSERT(instr->right()->representation().Equals(instr->representation()));
LOperand* dividend = UseRegister(instr->left());
@ -1387,6 +1387,25 @@ LInstruction* LChunkBuilder::DoDivByPowerOf2I(HDiv* instr) {
}
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();
bool truncating = instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32);
LOperand* temp = truncating ? NULL : TempRegister();
LInstruction* result =
DefineAsRegister(new(zone()) LDivByConstI(dividend, divisor, temp));
bool can_deopt =
divisor == 0 ||
(instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
instr->left()->RangeCanInclude(0) && divisor < 0) ||
!truncating;
return can_deopt ? AssignEnvironment(result) : result;
}
LInstruction* LChunkBuilder::DoDivI(HBinaryOperation* instr) {
ASSERT(instr->representation().IsSmiOrInteger32());
ASSERT(instr->left()->representation().Equals(instr->representation()));
@ -1402,10 +1421,13 @@ LInstruction* LChunkBuilder::DoDivI(HBinaryOperation* instr) {
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
if (instr->representation().IsSmiOrInteger32()) {
// TODO(all): Add Smi support to DoDivI and turn this into a ternary.
if (instr->RightIsPowerOf2()) return DoDivByPowerOf2I(instr);
if (instr->representation().IsInteger32()) return DoDivI(instr);
return DoArithmeticT(Token::DIV, 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 {
@ -1714,6 +1736,9 @@ LInstruction* LChunkBuilder::DoMapEnumLength(HMapEnumLength* instr) {
LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
ASSERT(instr->representation().IsInteger32());
ASSERT(instr->left()->representation().Equals(instr->representation()));
ASSERT(instr->right()->representation().Equals(instr->representation()));
LOperand* dividend = UseRegisterAtStart(instr->left());
int32_t divisor = instr->right()->GetInteger32Constant();
LInstruction* result =
@ -1725,6 +1750,22 @@ LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
}
LInstruction* LChunkBuilder::DoFlooringDivByConstI(HMathFloorOfDiv* 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()) LFlooringDivByConstI(dividend, divisor));
bool can_deopt =
divisor == 0 ||
(instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
instr->left()->RangeCanInclude(0) && divisor < 0);
return can_deopt ? AssignEnvironment(result) : result;
}
LInstruction* LChunkBuilder::DoFlooringDivI(HMathFloorOfDiv* instr) {
LOperand* dividend = UseRegister(instr->left());
LOperand* divisor = UseRegister(instr->right());
@ -1739,8 +1780,7 @@ LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
if (instr->RightIsPowerOf2()) {
return DoFlooringDivByPowerOf2I(instr);
} else if (instr->right()->IsConstant()) {
// TODO(svenpanne) Do something more efficient in this case.
return DoFlooringDivI(instr);
return DoFlooringDivByConstI(instr);
} else {
return DoFlooringDivI(instr);
}
@ -1767,7 +1807,7 @@ LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
LInstruction* LChunkBuilder::DoModByPowerOf2I(HMod* instr) {
ASSERT(instr->representation().IsSmiOrInteger32());
ASSERT(instr->representation().IsInteger32());
ASSERT(instr->left()->representation().Equals(instr->representation()));
ASSERT(instr->right()->representation().Equals(instr->representation()));
LOperand* dividend = UseRegisterAtStart(instr->left());
@ -1781,6 +1821,23 @@ LInstruction* LChunkBuilder::DoModByPowerOf2I(HMod* instr) {
}
LInstruction* LChunkBuilder::DoModByConstI(HMod* 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();
LOperand* temp = TempRegister();
LInstruction* result =
DefineAsRegister(new(zone()) LModByConstI(dividend, divisor, temp));
bool can_deopt =
divisor == 0 ||
(instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
instr->left()->CanBeNegative());
return can_deopt ? AssignEnvironment(result) : result;
}
LInstruction* LChunkBuilder::DoModI(HMod* instr) {
ASSERT(instr->representation().IsSmiOrInteger32());
ASSERT(instr->left()->representation().Equals(instr->representation()));
@ -1798,10 +1855,13 @@ LInstruction* LChunkBuilder::DoModI(HMod* instr) {
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
if (instr->representation().IsSmiOrInteger32()) {
// TODO(all): Add Smi support to DoDivI and turn this into a ternary.
if (instr->RightIsPowerOf2()) return DoModByPowerOf2I(instr);
if (instr->representation().IsInteger32()) return DoModI(instr);
return DoArithmeticT(Token::MOD, instr);
if (instr->RightIsPowerOf2()) {
return DoModByPowerOf2I(instr);
} else if (instr->right()->IsConstant()) {
return DoModByConstI(instr);
} else {
return DoModI(instr);
}
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::MOD, instr);
} else {

View File

@ -90,6 +90,7 @@ class LCodeGen;
V(DebugBreak) \
V(DeclareGlobals) \
V(Deoptimize) \
V(DivByConstI) \
V(DivByPowerOf2I) \
V(DivI) \
V(DoubleBits) \
@ -97,6 +98,7 @@ class LCodeGen;
V(Drop) \
V(Dummy) \
V(DummyUse) \
V(FlooringDivByConstI) \
V(FlooringDivByPowerOf2I) \
V(FlooringDivI) \
V(ForInCacheArray) \
@ -143,6 +145,7 @@ class LCodeGen;
V(MathPowHalf) \
V(MathRound) \
V(MathSqrt) \
V(ModByConstI) \
V(ModByPowerOf2I) \
V(ModI) \
V(MulConstIS) \
@ -1300,6 +1303,26 @@ class LDivByPowerOf2I V8_FINAL : public LTemplateInstruction<1, 1, 0> {
};
class LDivByConstI V8_FINAL : public LTemplateInstruction<1, 1, 1> {
public:
LDivByConstI(LOperand* dividend, int32_t divisor, LOperand* temp) {
inputs_[0] = dividend;
divisor_ = divisor;
temps_[0] = temp;
}
LOperand* dividend() { return inputs_[0]; }
int32_t divisor() const { return divisor_; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(DivByConstI, "div-by-const-i")
DECLARE_HYDROGEN_ACCESSOR(Div)
private:
int32_t divisor_;
};
class LDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
public:
LDivI(LOperand* left, LOperand* right, LOperand* temp) {
@ -1949,6 +1972,25 @@ class LFlooringDivByPowerOf2I V8_FINAL : public LTemplateInstruction<1, 1, 0> {
};
class LFlooringDivByConstI V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
LFlooringDivByConstI(LOperand* dividend, int32_t divisor) {
inputs_[0] = dividend;
divisor_ = divisor;
}
LOperand* dividend() { return inputs_[0]; }
int32_t divisor() const { return divisor_; }
LOperand* temp1() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(FlooringDivByConstI, "flooring-div-by-const-i")
DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
private:
int32_t divisor_;
};
class LFlooringDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
public:
LFlooringDivI(LOperand* dividend, LOperand* divisor, LOperand* temp) {
@ -2040,6 +2082,26 @@ class LModByPowerOf2I V8_FINAL : public LTemplateInstruction<1, 1, 0> {
};
class LModByConstI V8_FINAL : public LTemplateInstruction<1, 1, 1> {
public:
LModByConstI(LOperand* dividend, int32_t divisor, LOperand* temp) {
inputs_[0] = dividend;
divisor_ = divisor;
temps_[0] = temp;
}
LOperand* dividend() { return inputs_[0]; }
int32_t divisor() const { return divisor_; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(ModByConstI, "mod-by-const-i")
DECLARE_HYDROGEN_ACCESSOR(Mod)
private:
int32_t divisor_;
};
class LModI V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
LModI(LOperand* left, LOperand* right) {
@ -2931,10 +2993,13 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
#undef DECLARE_DO
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);
LInstruction* DoFlooringDivI(HMathFloorOfDiv* instr);
static bool HasMagicNumberForDivision(int32_t divisor);

View File

@ -1057,6 +1057,11 @@ void LCodeGen::DeoptimizeIfZero(Register rt, LEnvironment* environment) {
}
void LCodeGen::DeoptimizeIfNotZero(Register rt, LEnvironment* environment) {
DeoptimizeBranch(environment, reg_not_zero, rt);
}
void LCodeGen::DeoptimizeIfNegative(Register rt, LEnvironment* environment) {
int sign_bit = rt.Is64Bits() ? kXSignBit : kWSignBit;
DeoptimizeBranch(environment, reg_bit_set, rt, sign_bit);
@ -2634,6 +2639,39 @@ void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) {
}
void LCodeGen::DoDivByConstI(LDivByConstI* instr) {
Register dividend = ToRegister32(instr->dividend());
int32_t divisor = instr->divisor();
Register result = ToRegister32(instr->result());
ASSERT(!AreAliased(dividend, result));
if (divisor == 0) {
Deoptimize(instr->environment());
return;
}
// Check for (0 / -x) that will produce negative zero.
HDiv* hdiv = instr->hydrogen();
if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) &&
hdiv->left()->RangeCanInclude(0) && divisor < 0) {
DeoptimizeIfZero(dividend, instr->environment());
}
__ FlooringDiv(result, dividend, Abs(divisor));
__ Add(result, result, Operand(dividend, LSR, 31));
if (divisor < 0) __ Neg(result, result);
if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
Register temp = ToRegister32(instr->temp());
ASSERT(!AreAliased(dividend, result, temp));
__ Sxtw(dividend.X(), dividend);
__ Mov(temp, divisor);
__ Smsubl(temp.X(), result, temp, dividend.X());
DeoptimizeIfNotZero(temp, instr->environment());
}
}
void LCodeGen::DoDivI(LDivI* instr) {
Register dividend = ToRegister32(instr->left());
Register divisor = ToRegister32(instr->right());
@ -3839,6 +3877,29 @@ void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
}
void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) {
Register dividend = ToRegister32(instr->dividend());
int32_t divisor = instr->divisor();
Register result = ToRegister32(instr->result());
ASSERT(!AreAliased(dividend, result));
if (divisor == 0) {
Deoptimize(instr->environment());
return;
}
// Check for (0 / -x) that will produce negative zero.
HMathFloorOfDiv* hdiv = instr->hydrogen();
if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) &&
hdiv->left()->RangeCanInclude(0) && divisor < 0) {
__ Cmp(dividend, 0);
DeoptimizeIf(eq, instr->environment());
}
__ FlooringDiv(result, dividend, divisor);
}
void LCodeGen::DoFlooringDivI(LFlooringDivI* instr) {
Register dividend = ToRegister32(instr->dividend());
Register divisor = ToRegister32(instr->divisor());
@ -4098,6 +4159,36 @@ void LCodeGen::DoModByPowerOf2I(LModByPowerOf2I* instr) {
}
void LCodeGen::DoModByConstI(LModByConstI* instr) {
Register dividend = ToRegister32(instr->dividend());
int32_t divisor = instr->divisor();
Register result = ToRegister32(instr->result());
Register temp = ToRegister32(instr->temp());
ASSERT(!AreAliased(dividend, result, temp));
if (divisor == 0) {
Deoptimize(instr->environment());
return;
}
__ FlooringDiv(result, dividend, Abs(divisor));
__ Add(result, result, Operand(dividend, LSR, 31));
__ Sxtw(dividend.X(), dividend);
__ Mov(temp, Abs(divisor));
__ Smsubl(result.X(), result, temp, dividend.X());
// Check for negative zero.
HMod* hmod = instr->hydrogen();
if (hmod->CheckFlag(HValue::kBailoutOnMinusZero) &&
hmod->left()->CanBeNegative()) {
Label remainder_not_zero;
__ Cbnz(result, &remainder_not_zero);
DeoptimizeIfNegative(dividend, instr->environment());
__ bind(&remainder_not_zero);
}
}
void LCodeGen::DoModI(LModI* instr) {
Register dividend = ToRegister32(instr->left());
Register divisor = ToRegister32(instr->right());

View File

@ -226,6 +226,7 @@ class LCodeGen: public LCodeGenBase {
Deoptimizer::BailoutType* override_bailout_type = NULL);
void DeoptimizeIf(Condition cc, LEnvironment* environment);
void DeoptimizeIfZero(Register rt, LEnvironment* environment);
void DeoptimizeIfNotZero(Register rt, LEnvironment* environment);
void DeoptimizeIfNegative(Register rt, LEnvironment* environment);
void DeoptimizeIfSmi(Register rt, LEnvironment* environment);
void DeoptimizeIfNotSmi(Register rt, LEnvironment* environment);

View File

@ -4932,6 +4932,22 @@ bool MacroAssembler::IsCodeAgeSequence(byte* sequence) {
#endif
void MacroAssembler::FlooringDiv(Register result,
Register dividend,
int32_t divisor) {
Register tmp = WTmp0();
ASSERT(!AreAliased(result, dividend, tmp));
ASSERT(result.Is32Bits() && dividend.Is32Bits());
MultiplierAndShift ms(divisor);
Mov(tmp, Operand(ms.multiplier()));
Smull(result.X(), dividend, tmp);
Asr(result.X(), result.X(), 32);
if (divisor > 0 && ms.multiplier() < 0) Add(result, result, dividend);
if (divisor < 0 && ms.multiplier() > 0) Sub(result, result, dividend);
if (ms.shift() > 0) Asr(result, result, ms.shift());
}
#undef __
#define __ masm->

View File

@ -1677,6 +1677,10 @@ class MacroAssembler : public Assembler {
void LoadContext(Register dst, int context_chain_length);
// Emit code for a flooring division by a constant. The dividend register is
// unchanged and Tmp0() gets clobbered. Dividend and result must be different.
void FlooringDiv(Register result, Register dividend, int32_t divisor);
// ---------------------------------------------------------------------------
// StatsCounter support

View File

@ -1257,6 +1257,23 @@ LInstruction* LChunkBuilder::DoDivByPowerOf2I(HDiv* instr) {
}
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));
bool can_deopt =
divisor == 0 ||
(instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
instr->left()->RangeCanInclude(0) && divisor < 0) ||
!instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32);
return can_deopt ? AssignEnvironment(result) : result;
}
LInstruction* LChunkBuilder::DoDivI(HBinaryOperation* instr) {
ASSERT(instr->representation().IsSmiOrInteger32());
ASSERT(instr->left()->representation().Equals(instr->representation()));
@ -1271,7 +1288,13 @@ LInstruction* LChunkBuilder::DoDivI(HBinaryOperation* instr) {
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
if (instr->representation().IsSmiOrInteger32()) {
return instr->RightIsPowerOf2() ? DoDivByPowerOf2I(instr) : 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 {
@ -1280,29 +1303,6 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
}
bool LChunkBuilder::HasMagicNumberForDivisor(int32_t divisor) {
uint32_t divisor_abs = abs(divisor);
// Dividing by 0 or powers of 2 is easy.
if (divisor == 0 || IsPowerOf2(divisor_abs)) return true;
// We have magic numbers for a few specific divisors.
// Details and proofs can be found in:
// - Hacker's Delight, Henry S. Warren, Jr.
// - The PowerPC Compiler Writers Guide
// and probably many others.
//
// We handle
// <divisor with magic numbers> * <power of 2>
// but not
// <divisor with magic numbers> * <other divisor with magic numbers>
int32_t power_of_2_factor =
CompilerIntrinsics::CountTrailingZeros(divisor_abs);
DivMagicNumbers magic_numbers =
DivMagicNumberFor(divisor_abs >> power_of_2_factor);
return magic_numbers.M != InvalidDivMagicNumber.M;
}
LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
LOperand* dividend = UseRegisterAtStart(instr->left());
int32_t divisor = instr->right()->GetInteger32Constant();
@ -1317,15 +1317,18 @@ LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
LInstruction* LChunkBuilder::DoFlooringDivByConstI(HMathFloorOfDiv* instr) {
ASSERT(instr->representation().IsInteger32());
ASSERT(instr->left()->representation().Equals(instr->representation()));
ASSERT(instr->right()->representation().Equals(instr->representation()));
LOperand* dividend = UseRegister(instr->left());
LOperand* divisor = CpuFeatures::IsSupported(SUDIV)
? UseRegister(instr->right())
: UseOrConstant(instr->right());
LOperand* remainder = TempRegister();
int32_t divisor = instr->right()->GetInteger32Constant();
LInstruction* result =
DefineAsRegister(
new(zone()) LFlooringDivByConstI(dividend, divisor, remainder));
return AssignEnvironment(result);
DefineAsRegister(new(zone()) LFlooringDivByConstI(dividend, divisor));
bool can_deopt =
divisor == 0 ||
(instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
instr->left()->RangeCanInclude(0) && divisor < 0);
return can_deopt ? AssignEnvironment(result) : result;
}
@ -1333,12 +1336,7 @@ LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
if (instr->RightIsPowerOf2()) {
return DoFlooringDivByPowerOf2I(instr);
} else if (instr->right()->IsConstant()) {
// LMathFloorOfDiv can currently only handle a subset of divisors, so fall
// back to a flooring division in all other cases.
return (CpuFeatures::IsSupported(SUDIV) ||
HasMagicNumberForDivisor(instr->right()->GetInteger32Constant()))
? DoFlooringDivByConstI(instr)
: DoDivI(instr);
return DoFlooringDivByConstI(instr);
} else {
return DoDivI(instr);
}
@ -1360,6 +1358,22 @@ 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));
bool can_deopt =
divisor == 0 ||
(instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
instr->left()->CanBeNegative());
return can_deopt ? AssignEnvironment(result) : result;
}
LInstruction* LChunkBuilder::DoModI(HMod* instr) {
ASSERT(instr->representation().IsSmiOrInteger32());
ASSERT(instr->left()->representation().Equals(instr->representation()));
@ -1395,7 +1409,13 @@ LInstruction* LChunkBuilder::DoModI(HMod* instr) {
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
if (instr->representation().IsSmiOrInteger32()) {
return instr->RightIsPowerOf2() ? DoModByPowerOf2I(instr) : DoModI(instr);
if (instr->RightIsPowerOf2()) {
return DoModByPowerOf2I(instr);
} else if (instr->right()->IsConstant()) {
return DoModByConstI(instr);
} else {
return DoModI(instr);
}
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::MOD, instr);
} else {

View File

@ -86,6 +86,7 @@ class LCodeGen;
V(DebugBreak) \
V(DeclareGlobals) \
V(Deoptimize) \
V(DivByConstI) \
V(DivByPowerOf2I) \
V(DivI) \
V(DoubleBits) \
@ -137,6 +138,7 @@ class LCodeGen;
V(MathPowHalf) \
V(MathRound) \
V(MathSqrt) \
V(ModByConstI) \
V(ModByPowerOf2I) \
V(ModI) \
V(MulI) \
@ -638,6 +640,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, 2> {
public:
LModI(LOperand* left, LOperand* right, LOperand* temp, LOperand* temp2) {
@ -675,6 +695,24 @@ class LDivByPowerOf2I V8_FINAL : public LTemplateInstruction<1, 1, 0> {
};
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, 1> {
public:
LDivI(LOperand* left, LOperand* right, LOperand* temp) {
@ -713,20 +751,22 @@ class LFlooringDivByPowerOf2I V8_FINAL : public LTemplateInstruction<1, 1, 0> {
};
class LFlooringDivByConstI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
class LFlooringDivByConstI V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
LFlooringDivByConstI(LOperand* dividend, LOperand* divisor, LOperand* temp) {
LFlooringDivByConstI(LOperand* dividend, int32_t divisor) {
inputs_[0] = dividend;
inputs_[1] = divisor;
temps_[0] = temp;
divisor_ = divisor;
}
LOperand* dividend() { return inputs_[0]; }
LOperand* divisor() { return inputs_[1]; }
LOperand* temp() { return temps_[0]; }
int32_t divisor() const { return divisor_; }
LOperand* temp1() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(FlooringDivByConstI, "flooring-div-by-const-i")
DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
private:
int32_t divisor_;
};
@ -2711,8 +2751,10 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
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);

View File

@ -1144,6 +1144,36 @@ 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));
__ add(result, result, Operand(dividend, LSR, 31));
__ mov(ip, Operand(Abs(divisor)));
__ smull(result, ip, result, ip);
__ sub(result, dividend, result, SetCC);
// Check for negative zero.
HMod* hmod = instr->hydrogen();
if (hmod->CheckFlag(HValue::kBailoutOnMinusZero) &&
hmod->left()->CanBeNegative()) {
Label remainder_not_zero;
__ b(ne, &remainder_not_zero);
__ cmp(dividend, Operand::Zero());
DeoptimizeIf(lt, instr->environment());
__ bind(&remainder_not_zero);
}
}
void LCodeGen::DoModI(LModI* instr) {
HMod* hmod = instr->hydrogen();
HValue* left = hmod->left();
@ -1258,100 +1288,6 @@ void LCodeGen::DoModI(LModI* instr) {
}
void LCodeGen::EmitSignedIntegerDivisionByConstant(
Register result,
Register dividend,
int32_t divisor,
Register remainder,
Register scratch,
LEnvironment* environment) {
ASSERT(!AreAliased(dividend, scratch, ip));
ASSERT(LChunkBuilder::HasMagicNumberForDivisor(divisor));
uint32_t divisor_abs = abs(divisor);
int32_t power_of_2_factor =
CompilerIntrinsics::CountTrailingZeros(divisor_abs);
switch (divisor_abs) {
case 0:
DeoptimizeIf(al, environment);
return;
case 1:
if (divisor > 0) {
__ Move(result, dividend);
} else {
__ rsb(result, dividend, Operand::Zero(), SetCC);
DeoptimizeIf(vs, environment);
}
// Compute the remainder.
__ mov(remainder, Operand::Zero());
return;
default:
if (IsPowerOf2(divisor_abs)) {
// Branch and condition free code for integer division by a power
// of two.
int32_t power = WhichPowerOf2(divisor_abs);
if (power > 1) {
__ mov(scratch, Operand(dividend, ASR, power - 1));
}
__ add(scratch, dividend, Operand(scratch, LSR, 32 - power));
__ mov(result, Operand(scratch, ASR, power));
// Negate if necessary.
// We don't need to check for overflow because the case '-1' is
// handled separately.
if (divisor < 0) {
ASSERT(divisor != -1);
__ rsb(result, result, Operand::Zero());
}
// Compute the remainder.
if (divisor > 0) {
__ sub(remainder, dividend, Operand(result, LSL, power));
} else {
__ add(remainder, dividend, Operand(result, LSL, power));
}
return;
} else {
// Use magic numbers for a few specific divisors.
// Details and proofs can be found in:
// - Hacker's Delight, Henry S. Warren, Jr.
// - The PowerPC Compiler Writers Guide
// and probably many others.
//
// We handle
// <divisor with magic numbers> * <power of 2>
// but not
// <divisor with magic numbers> * <other divisor with magic numbers>
DivMagicNumbers magic_numbers =
DivMagicNumberFor(divisor_abs >> power_of_2_factor);
// Branch and condition free code for integer division by a power
// of two.
const int32_t M = magic_numbers.M;
const int32_t s = magic_numbers.s + power_of_2_factor;
__ mov(ip, Operand(M));
__ smull(ip, scratch, dividend, ip);
if (M < 0) {
__ add(scratch, scratch, Operand(dividend));
}
if (s > 0) {
__ mov(scratch, Operand(scratch, ASR, s));
}
__ add(result, scratch, Operand(dividend, LSR, 31));
if (divisor < 0) __ rsb(result, result, Operand::Zero());
// Compute the remainder.
__ mov(ip, Operand(divisor));
// This sequence could be replaced with 'mls' when
// it gets implemented.
__ mul(scratch, result, ip);
__ sub(remainder, dividend, scratch);
}
}
}
void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) {
Register dividend = ToRegister(instr->dividend());
int32_t divisor = instr->divisor();
@ -1398,6 +1334,38 @@ void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) {
}
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) &&
hdiv->left()->RangeCanInclude(0) && divisor < 0) {
__ cmp(dividend, Operand::Zero());
DeoptimizeIf(eq, instr->environment());
}
__ FlooringDiv(result, dividend, Abs(divisor));
__ add(result, result, Operand(dividend, LSR, 31));
if (divisor < 0) __ rsb(result, result, Operand::Zero());
if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
__ mov(ip, Operand(divisor));
__ smull(scratch0(), ip, result, ip);
__ sub(scratch0(), scratch0(), dividend, SetCC);
DeoptimizeIf(ne, instr->environment());
}
}
void LCodeGen::DoDivI(LDivI* instr) {
const Register left = ToRegister(instr->left());
const Register right = ToRegister(instr->right());
@ -1531,71 +1499,25 @@ void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) {
Register left = ToRegister(instr->dividend());
Register remainder = ToRegister(instr->temp());
Register scratch = scratch0();
Register dividend = ToRegister(instr->dividend());
int32_t divisor = instr->divisor();
Register result = ToRegister(instr->result());
ASSERT(!dividend.is(result));
if (!CpuFeatures::IsSupported(SUDIV)) {
// If the CPU doesn't support sdiv instruction, we only optimize when we
// have magic numbers for the divisor. The standard integer division routine
// is usually slower than transitionning to VFP.
ASSERT(instr->divisor()->IsConstantOperand());
int32_t divisor = ToInteger32(LConstantOperand::cast(instr->divisor()));
ASSERT(LChunkBuilder::HasMagicNumberForDivisor(divisor));
if (divisor < 0) {
__ cmp(left, Operand::Zero());
DeoptimizeIf(eq, instr->environment());
}
EmitSignedIntegerDivisionByConstant(result,
left,
divisor,
remainder,
scratch,
instr->environment());
// We performed a truncating division. Correct the result if necessary.
__ cmp(remainder, Operand::Zero());
__ teq(remainder, Operand(divisor), ne);
__ sub(result, result, Operand(1), LeaveCC, mi);
} else {
CpuFeatureScope scope(masm(), SUDIV);
// TODO(svenpanne) We *statically* know the divisor, use that fact!
Register right = ToRegister(instr->divisor());
// Check for x / 0.
__ cmp(right, Operand::Zero());
DeoptimizeIf(eq, instr->environment());
// Check for (kMinInt / -1).
if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
__ cmp(left, Operand(kMinInt));
__ cmp(right, Operand(-1), eq);
DeoptimizeIf(eq, instr->environment());
if (divisor == 0) {
DeoptimizeIf(al, instr->environment());
return;
}
// Check for (0 / -x) that will produce negative zero.
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
__ cmp(right, Operand::Zero());
__ cmp(left, Operand::Zero(), mi);
// "right" can't be null because the code would have already been
// deoptimized. The Z flag is set only if (right < 0) and (left == 0).
// In this case we need to deoptimize to produce a -0.
HMathFloorOfDiv* hdiv = instr->hydrogen();
if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) &&
hdiv->left()->RangeCanInclude(0) && divisor < 0) {
__ cmp(dividend, Operand::Zero());
DeoptimizeIf(eq, instr->environment());
}
Label done;
__ sdiv(result, left, right);
// If both operands have the same sign then we are done.
__ eor(remainder, left, Operand(right), SetCC);
__ b(pl, &done);
// Check if the result needs to be corrected.
__ mls(remainder, result, right, left);
__ cmp(remainder, Operand::Zero());
__ sub(result, result, Operand(1), LeaveCC, ne);
__ bind(&done);
}
__ FlooringDiv(result, dividend, divisor);
}

View File

@ -349,17 +349,6 @@ class LCodeGen: public LCodeGenBase {
int* offset,
AllocationSiteMode mode);
// Emit optimized code for integer division.
// Inputs are signed.
// All registers are clobbered.
// If 'remainder' is no_reg, it is not computed.
void EmitSignedIntegerDivisionByConstant(Register result,
Register dividend,
int32_t divisor,
Register remainder,
Register scratch,
LEnvironment* environment);
void EnsureSpaceForLazyDeopt(int space_needed) V8_OVERRIDE;
void DoLoadKeyedExternalArray(LLoadKeyed* instr);
void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr);

View File

@ -4032,6 +4032,25 @@ void CodePatcher::EmitCondition(Condition cond) {
}
void MacroAssembler::FlooringDiv(Register result,
Register dividend,
int32_t divisor) {
ASSERT(!dividend.is(result));
ASSERT(!dividend.is(ip));
ASSERT(!result.is(ip));
MultiplierAndShift ms(divisor);
mov(ip, Operand(ms.multiplier()));
smull(ip, result, dividend, ip);
if (divisor > 0 && ms.multiplier() < 0) {
add(result, result, Operand(dividend));
}
if (divisor < 0 && ms.multiplier() > 0) {
sub(result, result, Operand(dividend));
}
if (ms.shift() > 0) mov(result, Operand(result, ASR, ms.shift()));
}
} } // namespace v8::internal
#endif // V8_TARGET_ARCH_ARM

View File

@ -1155,6 +1155,10 @@ class MacroAssembler: public Assembler {
}
// Emit code for a flooring division by a constant. The dividend register is
// unchanged and ip gets clobbered. Dividend and result must be different.
void FlooringDiv(Register result, Register dividend, int32_t divisor);
// ---------------------------------------------------------------------------
// StatsCounter support

View File

@ -1593,4 +1593,38 @@ bool PositionsRecorder::WriteRecordedPositions() {
return written;
}
MultiplierAndShift::MultiplierAndShift(int32_t d) {
ASSERT(d <= -2 || 2 <= d);
const uint32_t two31 = 0x80000000;
uint32_t ad = Abs(d);
uint32_t t = two31 + (uint32_t(d) >> 31);
uint32_t anc = t - 1 - t % ad; // Absolute value of nc.
int32_t p = 31; // Init. p.
uint32_t q1 = two31 / anc; // Init. q1 = 2**p/|nc|.
uint32_t r1 = two31 - q1 * anc; // Init. r1 = rem(2**p, |nc|).
uint32_t q2 = two31 / ad; // Init. q2 = 2**p/|d|.
uint32_t r2 = two31 - q2 * ad; // Init. r2 = rem(2**p, |d|).
uint32_t delta;
do {
p++;
q1 *= 2; // Update q1 = 2**p/|nc|.
r1 *= 2; // Update r1 = rem(2**p, |nc|).
if (r1 >= anc) { // Must be an unsigned comparison here.
q1++;
r1 = r1 - anc;
}
q2 *= 2; // Update q2 = 2**p/|d|.
r2 *= 2; // Update r2 = rem(2**p, |d|).
if (r2 >= ad) { // Must be an unsigned comparison here.
q2++;
r2 = r2 - ad;
}
delta = ad - r2;
} while (q1 < delta || (q1 == delta && r1 == 0));
int32_t mul = static_cast<int32_t>(q2 + 1);
multiplier_ = (d < 0) ? -mul : mul;
shift_ = p - 32;
}
} } // namespace v8::internal

View File

@ -1037,6 +1037,21 @@ class NullCallWrapper : public CallWrapper {
virtual void AfterCall() const { }
};
// The multiplier and shift for signed division via multiplication, see Warren's
// "Hacker's Delight", chapter 10.
class MultiplierAndShift {
public:
explicit MultiplierAndShift(int32_t d);
int32_t multiplier() const { return multiplier_; }
int32_t shift() const { return shift_; }
private:
int32_t multiplier_;
int32_t shift_;
};
} } // namespace v8::internal
#endif // V8_ASSEMBLER_H_

View File

@ -1401,6 +1401,37 @@ void LCodeGen::DoModByPowerOf2I(LModByPowerOf2I* instr) {
}
void LCodeGen::DoModByConstI(LModByConstI* instr) {
Register dividend = ToRegister(instr->dividend());
int32_t divisor = instr->divisor();
ASSERT(ToRegister(instr->result()).is(eax));
if (divisor == 0) {
DeoptimizeIf(no_condition, instr->environment());
return;
}
__ FlooringDiv(dividend, Abs(divisor));
__ mov(eax, dividend);
__ shr(eax, 31);
__ add(edx, eax);
__ imul(edx, edx, Abs(divisor));
__ mov(eax, dividend);
__ sub(eax, edx);
// Check for negative zero.
HMod* hmod = instr->hydrogen();
if (hmod->CheckFlag(HValue::kBailoutOnMinusZero) &&
hmod->left()->CanBeNegative()) {
Label remainder_not_zero;
__ j(not_zero, &remainder_not_zero, Label::kNear);
__ cmp(dividend, Immediate(0));
DeoptimizeIf(less, instr->environment());
__ bind(&remainder_not_zero);
}
}
void LCodeGen::DoModI(LModI* instr) {
HMod* hmod = instr->hydrogen();
HValue* left = hmod->left();
@ -1500,6 +1531,39 @@ void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) {
}
void LCodeGen::DoDivByConstI(LDivByConstI* instr) {
Register dividend = ToRegister(instr->dividend());
int32_t divisor = instr->divisor();
ASSERT(ToRegister(instr->result()).is(edx));
if (divisor == 0) {
DeoptimizeIf(no_condition, instr->environment());
return;
}
// Check for (0 / -x) that will produce negative zero.
HDiv* hdiv = instr->hydrogen();
if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) &&
hdiv->left()->RangeCanInclude(0) && divisor < 0) {
__ test(dividend, dividend);
DeoptimizeIf(zero, instr->environment());
}
__ FlooringDiv(dividend, Abs(divisor));
__ mov(eax, dividend);
__ shr(eax, 31);
__ add(edx, eax);
if (divisor < 0) __ neg(edx);
if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
__ mov(eax, edx);
__ imul(eax, eax, divisor);
__ sub(eax, dividend);
DeoptimizeIf(not_equal, instr->environment());
}
}
void LCodeGen::DoDivI(LDivI* instr) {
Register dividend = ToRegister(instr->left());
Register divisor = ToRegister(instr->right());
@ -1599,8 +1663,6 @@ void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) {
Register dividend = ToRegister(instr->dividend());
int32_t divisor = instr->divisor();
Register scratch = ToRegister(instr->temp());
ASSERT(ToRegister(instr->dividend()).is(eax));
ASSERT(ToRegister(instr->result()).is(edx));
if (divisor == 0) {
@ -1608,52 +1670,15 @@ void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) {
return;
}
// Find b which: 2^b < divisor_abs < 2^(b+1).
uint32_t divisor_abs = abs(divisor);
unsigned b = 31 - CompilerIntrinsics::CountLeadingZeros(divisor_abs);
unsigned shift = 32 + b; // Precision +1bit (effectively).
double multiplier_f =
static_cast<double>(static_cast<uint64_t>(1) << shift) / divisor_abs;
int64_t multiplier;
if (multiplier_f - std::floor(multiplier_f) < 0.5) {
multiplier = static_cast<int64_t>(std::floor(multiplier_f));
} else {
multiplier = static_cast<int64_t>(std::floor(multiplier_f)) + 1;
}
// The multiplier is a uint32.
ASSERT(multiplier > 0 &&
multiplier < (static_cast<int64_t>(1) << 32));
__ mov(scratch, dividend);
if (divisor < 0 &&
instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
// Check for (0 / -x) that will produce negative zero.
HMathFloorOfDiv* hdiv = instr->hydrogen();
if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) &&
hdiv->left()->RangeCanInclude(0) && divisor < 0) {
__ test(dividend, dividend);
DeoptimizeIf(zero, instr->environment());
}
__ mov(edx, static_cast<int32_t>(multiplier));
__ imul(edx);
if (static_cast<int32_t>(multiplier) < 0) {
__ add(edx, scratch);
}
Register reg_lo = eax;
Register reg_byte_scratch = scratch;
if (!reg_byte_scratch.is_byte_register()) {
__ xchg(reg_lo, reg_byte_scratch);
reg_lo = scratch;
reg_byte_scratch = eax;
}
if (divisor < 0) {
__ xor_(reg_byte_scratch, reg_byte_scratch);
__ cmp(reg_lo, 0x40000000);
__ setcc(above, reg_byte_scratch);
__ neg(edx);
__ sub(edx, reg_byte_scratch);
} else {
__ xor_(reg_byte_scratch, reg_byte_scratch);
__ cmp(reg_lo, 0xC0000000);
__ setcc(above_equal, reg_byte_scratch);
__ add(edx, reg_byte_scratch);
}
__ sar(edx, shift - 32);
__ FlooringDiv(dividend, divisor);
}

View File

@ -1340,6 +1340,26 @@ LInstruction* LChunkBuilder::DoDivByPowerOf2I(HDiv* instr) {
}
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();
LOperand* temp1 = FixedTemp(eax);
LOperand* temp2 = FixedTemp(edx);
LInstruction* result =
DefineFixed(
new(zone()) LDivByConstI(dividend, divisor, temp1, temp2), edx);
bool can_deopt =
divisor == 0 ||
(instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
instr->left()->RangeCanInclude(0) && divisor < 0) ||
!instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32);
return can_deopt ? AssignEnvironment(result) : result;
}
LInstruction* LChunkBuilder::DoDivI(HBinaryOperation* instr) {
ASSERT(instr->representation().IsSmiOrInteger32());
ASSERT(instr->left()->representation().Equals(instr->representation()));
@ -1347,14 +1367,21 @@ LInstruction* LChunkBuilder::DoDivI(HBinaryOperation* instr) {
LOperand* dividend = UseFixed(instr->left(), eax);
LOperand* divisor = UseRegister(instr->right());
LOperand* temp = FixedTemp(edx);
LDivI* result = new(zone()) LDivI(dividend, divisor, temp);
return AssignEnvironment(DefineFixed(result, eax));
LInstruction* result =
DefineFixed(new(zone()) LDivI(dividend, divisor, temp), eax);
return AssignEnvironment(result);
}
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
if (instr->representation().IsSmiOrInteger32()) {
return instr->RightIsPowerOf2() ? DoDivByPowerOf2I(instr) : 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 {
@ -1376,13 +1403,23 @@ LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
LInstruction* LChunkBuilder::DoFlooringDivByConstI(HMathFloorOfDiv* instr) {
LOperand* dividend = UseFixed(instr->left(), eax);
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();
LOperand* temp = TempRegister();
LOperand* temp1 = FixedTemp(eax);
LOperand* temp2 = FixedTemp(edx);
LInstruction* result =
DefineFixed(
new(zone()) LFlooringDivByConstI(dividend, divisor, temp), edx);
bool can_deopt = divisor <= 0;
DefineFixed(new(zone()) LFlooringDivByConstI(dividend,
divisor,
temp1,
temp2),
edx);
bool can_deopt =
divisor == 0 ||
(instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
instr->left()->RangeCanInclude(0) && divisor < 0);
return can_deopt ? AssignEnvironment(result) : result;
}
@ -1413,6 +1450,25 @@ 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();
LOperand* temp1 = FixedTemp(eax);
LOperand* temp2 = FixedTemp(edx);
LInstruction* result =
DefineFixed(
new(zone()) LModByConstI(dividend, divisor, temp1, temp2), eax);
bool can_deopt =
divisor == 0 ||
(instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
instr->left()->CanBeNegative());
return can_deopt ? AssignEnvironment(result) : result;
}
LInstruction* LChunkBuilder::DoModI(HMod* instr) {
ASSERT(instr->representation().IsSmiOrInteger32());
ASSERT(instr->left()->representation().Equals(instr->representation()));
@ -1435,7 +1491,13 @@ LInstruction* LChunkBuilder::DoModI(HMod* instr) {
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
if (instr->representation().IsSmiOrInteger32()) {
return instr->RightIsPowerOf2() ? DoModByPowerOf2I(instr) : DoModI(instr);
if (instr->RightIsPowerOf2()) {
return DoModByPowerOf2I(instr);
} else if (instr->right()->IsConstant()) {
return DoModByConstI(instr);
} else {
return DoModI(instr);
}
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::MOD, instr);
} else {

View File

@ -88,6 +88,7 @@ class LCodeGen;
V(DebugBreak) \
V(DeclareGlobals) \
V(Deoptimize) \
V(DivByConstI) \
V(DivByPowerOf2I) \
V(DivI) \
V(DoubleBits) \
@ -139,6 +140,7 @@ class LCodeGen;
V(MathPowHalf) \
V(MathRound) \
V(MathSqrt) \
V(ModByConstI) \
V(ModByPowerOf2I) \
V(ModI) \
V(MulI) \
@ -657,6 +659,31 @@ class LModByPowerOf2I V8_FINAL : public LTemplateInstruction<1, 1, 0> {
};
class LModByConstI V8_FINAL : public LTemplateInstruction<1, 1, 2> {
public:
LModByConstI(LOperand* dividend,
int32_t divisor,
LOperand* temp1,
LOperand* temp2) {
inputs_[0] = dividend;
divisor_ = divisor;
temps_[0] = temp1;
temps_[1] = temp2;
}
LOperand* dividend() { return inputs_[0]; }
int32_t divisor() const { return divisor_; }
LOperand* temp1() { return temps_[0]; }
LOperand* temp2() { return temps_[1]; }
DECLARE_CONCRETE_INSTRUCTION(ModByConstI, "mod-by-const-i")
DECLARE_HYDROGEN_ACCESSOR(Mod)
private:
int32_t divisor_;
};
class LModI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
public:
LModI(LOperand* left, LOperand* right, LOperand* temp) {
@ -692,6 +719,31 @@ class LDivByPowerOf2I V8_FINAL : public LTemplateInstruction<1, 1, 0> {
};
class LDivByConstI V8_FINAL : public LTemplateInstruction<1, 1, 2> {
public:
LDivByConstI(LOperand* dividend,
int32_t divisor,
LOperand* temp1,
LOperand* temp2) {
inputs_[0] = dividend;
divisor_ = divisor;
temps_[0] = temp1;
temps_[1] = temp2;
}
LOperand* dividend() { return inputs_[0]; }
int32_t divisor() const { return divisor_; }
LOperand* temp1() { return temps_[0]; }
LOperand* temp2() { return temps_[1]; }
DECLARE_CONCRETE_INSTRUCTION(DivByConstI, "div-by-const-i")
DECLARE_HYDROGEN_ACCESSOR(Div)
private:
int32_t divisor_;
};
class LDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
public:
LDivI(LOperand* left, LOperand* right, LOperand* temp) {
@ -730,17 +782,22 @@ class LFlooringDivByPowerOf2I V8_FINAL : public LTemplateInstruction<1, 1, 0> {
};
class LFlooringDivByConstI V8_FINAL : public LTemplateInstruction<1, 1, 1> {
class LFlooringDivByConstI V8_FINAL : public LTemplateInstruction<1, 1, 2> {
public:
LFlooringDivByConstI(LOperand* dividend, int32_t divisor, LOperand* temp) {
LFlooringDivByConstI(LOperand* dividend,
int32_t divisor,
LOperand* temp1,
LOperand* temp2) {
inputs_[0] = dividend;
divisor_ = divisor;
temps_[0] = temp;
temps_[0] = temp1;
temps_[1] = temp2;
}
LOperand* dividend() { return inputs_[0]; }
int32_t divisor() const { return divisor_; }
LOperand* temp() { return temps_[0]; }
LOperand* temp1() { return temps_[0]; }
LOperand* temp2() { return temps_[1]; }
DECLARE_CONCRETE_INSTRUCTION(FlooringDivByConstI, "flooring-div-by-const-i")
DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
@ -2720,8 +2777,10 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
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);

View File

@ -3603,6 +3603,19 @@ void MacroAssembler::JumpIfDictionaryInPrototypeChain(
j(not_equal, &loop_again);
}
void MacroAssembler::FlooringDiv(Register dividend, int32_t divisor) {
ASSERT(!dividend.is(eax));
ASSERT(!dividend.is(edx));
MultiplierAndShift ms(divisor);
mov(eax, Immediate(ms.multiplier()));
imul(dividend);
if (divisor > 0 && ms.multiplier() < 0) add(edx, dividend);
if (divisor < 0 && ms.multiplier() > 0) sub(edx, dividend);
if (ms.shift() > 0) sar(edx, ms.shift());
}
} } // namespace v8::internal
#endif // V8_TARGET_ARCH_IA32

View File

@ -855,6 +855,10 @@ class MacroAssembler: public Assembler {
// Insert code to verify that the x87 stack has the specified depth (0-7)
void VerifyX87StackDepth(uint32_t depth);
// Emit code for a flooring division by a constant. The dividend register is
// unchanged, the result is in edx, and eax gets clobbered.
void FlooringDiv(Register dividend, int32_t divisor);
// ---------------------------------------------------------------------------
// StatsCounter support

View File

@ -97,18 +97,4 @@ char* SimpleStringBuilder::Finalize() {
}
const DivMagicNumbers DivMagicNumberFor(int32_t divisor) {
switch (divisor) {
case 3: return DivMagicNumberFor3;
case 5: return DivMagicNumberFor5;
case 7: return DivMagicNumberFor7;
case 9: return DivMagicNumberFor9;
case 11: return DivMagicNumberFor11;
case 25: return DivMagicNumberFor25;
case 125: return DivMagicNumberFor125;
case 625: return DivMagicNumberFor625;
default: return InvalidDivMagicNumber;
}
}
} } // namespace v8::internal

View File

@ -105,32 +105,6 @@ inline int MostSignificantBit(uint32_t x) {
}
// Magic numbers for integer division.
// These are kind of 2's complement reciprocal of the divisors.
// Details and proofs can be found in:
// - Hacker's Delight, Henry S. Warren, Jr.
// - The PowerPC Compiler Writers Guide
// and probably many others.
// See details in the implementation of the algorithm in
// lithium-codegen-arm.cc : LCodeGen::TryEmitSignedIntegerDivisionByConstant().
struct DivMagicNumbers {
unsigned M;
unsigned s;
};
const DivMagicNumbers InvalidDivMagicNumber= {0, 0};
const DivMagicNumbers DivMagicNumberFor3 = {0x55555556, 0};
const DivMagicNumbers DivMagicNumberFor5 = {0x66666667, 1};
const DivMagicNumbers DivMagicNumberFor7 = {0x92492493, 2};
const DivMagicNumbers DivMagicNumberFor9 = {0x38e38e39, 1};
const DivMagicNumbers DivMagicNumberFor11 = {0x2e8ba2e9, 1};
const DivMagicNumbers DivMagicNumberFor25 = {0x51eb851f, 3};
const DivMagicNumbers DivMagicNumberFor125 = {0x10624dd3, 3};
const DivMagicNumbers DivMagicNumberFor625 = {0x68db8bad, 8};
const DivMagicNumbers DivMagicNumberFor(int32_t divisor);
// The C++ standard leaves the semantics of '>>' undefined for
// negative signed operands. Most implementations do the right thing,
// though.

View File

@ -1065,6 +1065,14 @@ void Assembler::imul(Register dst, Register src, Immediate imm) {
}
void Assembler::imull(Register src) {
EnsureSpace ensure_space(this);
emit_optional_rex_32(src);
emit(0xF7);
emit_modrm(0x5, src);
}
void Assembler::imull(Register dst, Register src) {
EnsureSpace ensure_space(this);
emit_optional_rex_32(dst, src);

View File

@ -937,6 +937,7 @@ class Assembler : public AssemblerBase {
void imul(Register dst, const Operand& src); // dst = dst * src.
void imul(Register dst, Register src, Immediate imm); // dst = src * imm.
// Signed 32-bit multiply instructions.
void imull(Register src); // edx:eax = eax * src.
void imull(Register dst, Register src); // dst = dst * src.
void imull(Register dst, const Operand& src); // dst = dst * src.
void imull(Register dst, Register src, Immediate imm); // dst = src * imm.

View File

@ -1016,6 +1016,37 @@ void LCodeGen::DoModByPowerOf2I(LModByPowerOf2I* instr) {
}
void LCodeGen::DoModByConstI(LModByConstI* instr) {
Register dividend = ToRegister(instr->dividend());
int32_t divisor = instr->divisor();
ASSERT(ToRegister(instr->result()).is(rax));
if (divisor == 0) {
DeoptimizeIf(no_condition, instr->environment());
return;
}
__ FlooringDiv(dividend, Abs(divisor));
__ movl(rax, dividend);
__ shrl(rax, Immediate(31));
__ addl(rdx, rax);
__ imull(rdx, rdx, Immediate(Abs(divisor)));
__ movl(rax, dividend);
__ subl(rax, rdx);
// Check for negative zero.
HMod* hmod = instr->hydrogen();
if (hmod->CheckFlag(HValue::kBailoutOnMinusZero) &&
hmod->left()->CanBeNegative()) {
Label remainder_not_zero;
__ j(not_zero, &remainder_not_zero, Label::kNear);
__ cmpl(dividend, Immediate(0));
DeoptimizeIf(less, instr->environment());
__ bind(&remainder_not_zero);
}
}
void LCodeGen::DoModI(LModI* instr) {
if (instr->hydrogen()->RightIsPowerOf2()) {
return DoModByPowerOf2I(reinterpret_cast<LModByPowerOf2I*>(instr));
@ -1119,42 +1150,22 @@ void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) {
Register dividend = ToRegister(instr->dividend());
int32_t divisor = instr->divisor();
Register temp = ToRegister(instr->temp());
Register result = ToRegister(instr->result());
ASSERT(ToRegister(instr->result()).is(rdx));
if (divisor == 0) {
DeoptimizeIf(no_condition, instr->environment());
return;
}
// Find b which: 2^b < divisor_abs < 2^(b+1).
uint32_t divisor_abs = abs(divisor);
unsigned b = 31 - CompilerIntrinsics::CountLeadingZeros(divisor_abs);
unsigned shift = 32 + b; // Precision +1bit (effectively).
double multiplier_f =
static_cast<double>(static_cast<uint64_t>(1) << shift) / divisor_abs;
int64_t multiplier;
if (multiplier_f - std::floor(multiplier_f) < 0.5) {
multiplier = static_cast<int64_t>(std::floor(multiplier_f));
} else {
multiplier = static_cast<int64_t>(std::floor(multiplier_f)) + 1;
}
// The multiplier is a uint32.
ASSERT(multiplier > 0 &&
multiplier < (static_cast<int64_t>(1) << 32));
// The multiply is int64, so sign-extend to r64.
__ movsxlq(temp, dividend);
if (divisor < 0 &&
instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
__ neg(temp);
// Check for (0 / -x) that will produce negative zero.
HMathFloorOfDiv* hdiv = instr->hydrogen();
if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) &&
hdiv->left()->RangeCanInclude(0) && divisor < 0) {
__ testl(dividend, dividend);
DeoptimizeIf(zero, instr->environment());
}
__ Set(result, multiplier);
// Result just fit in r64, because it's int32 * uint32.
__ imul(result, temp);
__ addq(result, Immediate(1 << 30));
__ sar(result, Immediate(shift));
__ FlooringDiv(dividend, divisor);
}
@ -1198,6 +1209,39 @@ void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) {
}
void LCodeGen::DoDivByConstI(LDivByConstI* instr) {
Register dividend = ToRegister(instr->dividend());
int32_t divisor = instr->divisor();
ASSERT(ToRegister(instr->result()).is(rdx));
if (divisor == 0) {
DeoptimizeIf(no_condition, instr->environment());
return;
}
// Check for (0 / -x) that will produce negative zero.
HDiv* hdiv = instr->hydrogen();
if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) &&
hdiv->left()->RangeCanInclude(0) && divisor < 0) {
__ testl(dividend, dividend);
DeoptimizeIf(zero, instr->environment());
}
__ FlooringDiv(dividend, Abs(divisor));
__ movl(rax, dividend);
__ shrl(rax, Immediate(31));
__ addl(rdx, rax);
if (divisor < 0) __ neg(rdx);
if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
__ movl(rax, rdx);
__ imull(rax, rax, Immediate(divisor));
__ subl(rax, dividend);
DeoptimizeIf(not_equal, instr->environment());
}
}
void LCodeGen::DoDivI(LDivI* instr) {
Register dividend = ToRegister(instr->left());
Register divisor = ToRegister(instr->right());

View File

@ -1261,6 +1261,26 @@ LInstruction* LChunkBuilder::DoDivByPowerOf2I(HDiv* instr) {
}
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();
LOperand* temp1 = FixedTemp(rax);
LOperand* temp2 = FixedTemp(rdx);
LInstruction* result =
DefineFixed(
new(zone()) LDivByConstI(dividend, divisor, temp1, temp2), rdx);
bool can_deopt =
divisor == 0 ||
(instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
instr->left()->RangeCanInclude(0) && divisor < 0) ||
!instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32);
return can_deopt ? AssignEnvironment(result) : result;
}
LInstruction* LChunkBuilder::DoDivI(HBinaryOperation* instr) {
ASSERT(instr->representation().IsSmiOrInteger32());
ASSERT(instr->left()->representation().Equals(instr->representation()));
@ -1276,7 +1296,13 @@ LInstruction* LChunkBuilder::DoDivI(HBinaryOperation* instr) {
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
if (instr->representation().IsSmiOrInteger32()) {
return instr->RightIsPowerOf2() ? DoDivByPowerOf2I(instr) : 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 {
@ -1298,13 +1324,23 @@ LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
LInstruction* LChunkBuilder::DoFlooringDivByConstI(HMathFloorOfDiv* instr) {
LOperand* dividend = UseRegisterAtStart(instr->left());
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();
LOperand* temp = TempRegister();
LOperand* temp1 = FixedTemp(rax);
LOperand* temp2 = FixedTemp(rdx);
LInstruction* result =
DefineAsRegister(
new(zone()) LFlooringDivByConstI(dividend, divisor, temp));
bool can_deopt = divisor <= 0;
DefineFixed(new(zone()) LFlooringDivByConstI(dividend,
divisor,
temp1,
temp2),
rdx);
bool can_deopt =
divisor == 0 ||
(instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
instr->left()->RangeCanInclude(0) && divisor < 0);
return can_deopt ? AssignEnvironment(result) : result;
}
@ -1335,6 +1371,25 @@ 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();
LOperand* temp1 = FixedTemp(rax);
LOperand* temp2 = FixedTemp(rdx);
LInstruction* result =
DefineFixed(
new(zone()) LModByConstI(dividend, divisor, temp1, temp2), rax);
bool can_deopt =
divisor == 0 ||
(instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
instr->left()->CanBeNegative());
return can_deopt ? AssignEnvironment(result) : result;
}
LInstruction* LChunkBuilder::DoModI(HMod* instr) {
ASSERT(instr->representation().IsSmiOrInteger32());
ASSERT(instr->left()->representation().Equals(instr->representation()));
@ -1357,7 +1412,13 @@ LInstruction* LChunkBuilder::DoModI(HMod* instr) {
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
if (instr->representation().IsSmiOrInteger32()) {
return instr->RightIsPowerOf2() ? DoModByPowerOf2I(instr) : DoModI(instr);
if (instr->RightIsPowerOf2()) {
return DoModByPowerOf2I(instr);
} else if (instr->right()->IsConstant()) {
return DoModByConstI(instr);
} else {
return DoModI(instr);
}
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::MOD, instr);
} else {

View File

@ -86,6 +86,7 @@ class LCodeGen;
V(DebugBreak) \
V(DeclareGlobals) \
V(Deoptimize) \
V(DivByConstI) \
V(DivByPowerOf2I) \
V(DivI) \
V(DoubleBits) \
@ -137,6 +138,7 @@ class LCodeGen;
V(MathPowHalf) \
V(MathRound) \
V(MathSqrt) \
V(ModByConstI) \
V(ModByPowerOf2I) \
V(ModI) \
V(MulI) \
@ -638,6 +640,31 @@ class LModByPowerOf2I V8_FINAL : public LTemplateInstruction<1, 1, 0> {
};
class LModByConstI V8_FINAL : public LTemplateInstruction<1, 1, 2> {
public:
LModByConstI(LOperand* dividend,
int32_t divisor,
LOperand* temp1,
LOperand* temp2) {
inputs_[0] = dividend;
divisor_ = divisor;
temps_[0] = temp1;
temps_[1] = temp2;
}
LOperand* dividend() { return inputs_[0]; }
int32_t divisor() const { return divisor_; }
LOperand* temp1() { return temps_[0]; }
LOperand* temp2() { return temps_[1]; }
DECLARE_CONCRETE_INSTRUCTION(ModByConstI, "mod-by-const-i")
DECLARE_HYDROGEN_ACCESSOR(Mod)
private:
int32_t divisor_;
};
class LModI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
public:
LModI(LOperand* left, LOperand* right, LOperand* temp) {
@ -673,6 +700,31 @@ class LDivByPowerOf2I V8_FINAL : public LTemplateInstruction<1, 1, 0> {
};
class LDivByConstI V8_FINAL : public LTemplateInstruction<1, 1, 2> {
public:
LDivByConstI(LOperand* dividend,
int32_t divisor,
LOperand* temp1,
LOperand* temp2) {
inputs_[0] = dividend;
divisor_ = divisor;
temps_[0] = temp1;
temps_[1] = temp2;
}
LOperand* dividend() { return inputs_[0]; }
int32_t divisor() const { return divisor_; }
LOperand* temp1() { return temps_[0]; }
LOperand* temp2() { return temps_[1]; }
DECLARE_CONCRETE_INSTRUCTION(DivByConstI, "div-by-const-i")
DECLARE_HYDROGEN_ACCESSOR(Div)
private:
int32_t divisor_;
};
class LDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
public:
LDivI(LOperand* left, LOperand* right, LOperand* temp) {
@ -711,17 +763,22 @@ class LFlooringDivByPowerOf2I V8_FINAL : public LTemplateInstruction<1, 1, 0> {
};
class LFlooringDivByConstI V8_FINAL : public LTemplateInstruction<1, 1, 1> {
class LFlooringDivByConstI V8_FINAL : public LTemplateInstruction<1, 1, 2> {
public:
LFlooringDivByConstI(LOperand* dividend, int32_t divisor, LOperand* temp) {
LFlooringDivByConstI(LOperand* dividend,
int32_t divisor,
LOperand* temp1,
LOperand* temp2) {
inputs_[0] = dividend;
divisor_ = divisor;
temps_[0] = temp;
temps_[0] = temp1;
temps_[1] = temp2;
}
LOperand* dividend() { return inputs_[0]; }
int32_t divisor() const { return divisor_; }
LOperand* temp() { return temps_[0]; }
LOperand* temp1() { return temps_[0]; }
LOperand* temp2() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(FlooringDivByConstI, "flooring-div-by-const-i")
DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
@ -2634,8 +2691,10 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
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);

View File

@ -4979,6 +4979,18 @@ void MacroAssembler::JumpIfDictionaryInPrototypeChain(
}
void MacroAssembler::FlooringDiv(Register dividend, int32_t divisor) {
ASSERT(!dividend.is(rax));
ASSERT(!dividend.is(rdx));
MultiplierAndShift ms(divisor);
movl(rax, Immediate(ms.multiplier()));
imull(dividend);
if (divisor > 0 && ms.multiplier() < 0) addl(rdx, dividend);
if (divisor < 0 && ms.multiplier() > 0) subl(rdx, dividend);
if (ms.shift() > 0) sarl(rdx, Immediate(ms.shift()));
}
} } // namespace v8::internal
#endif // V8_TARGET_ARCH_X64

View File

@ -1363,6 +1363,10 @@ class MacroAssembler: public Assembler {
Register filler);
// Emit code for a flooring division by a constant. The dividend register is
// unchanged, the result is in rdx, and rax gets clobbered.
void FlooringDiv(Register dividend, int32_t divisor);
// ---------------------------------------------------------------------------
// StatsCounter support

View File

@ -286,3 +286,14 @@ test_div_deopt_div_by_zero_v();
test_div_deopt_minus_zero_v();
test_div_deopt_overflow_v();
test_div_deopt_div_by_zero_v();
// Test for flooring division with negative dividend.
function flooring_div_by_3(y) {
return Math.floor(y / 3);
}
assertEquals(-1, flooring_div_by_3(-2));
assertEquals(-1, flooring_div_by_3(-2));
%OptimizeFunctionOnNextCall(flooring_div_by_3);
assertEquals(-1, flooring_div_by_3(-2));