Consistently use a separate Lithium instruction for flooring division.

Previously we tried to share some code on by a slightly confusing re-use
of LDivI for a (general) flooring division. Now we cleanly separate
concerns, just like for the rest of the division-like operations. Note
that ARM64 already did it this way.

If we really want to save some code, we can introduce some macro
assembler instructions and/or helper functions in the code generator in
a future CL, but we should really try to avoid being "clever" to save
just a few lines of trivial code. Effort != complexity. :-)

Renamed some related Lithium operands on the way for more consistency.

R=mstarzinger@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20395 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 10abff34
......@@ -1289,7 +1289,7 @@ LInstruction* LChunkBuilder::DoDivByConstI(HDiv* instr) {
}
LInstruction* LChunkBuilder::DoDivI(HBinaryOperation* instr) {
LInstruction* LChunkBuilder::DoDivI(HDiv* instr) {
ASSERT(instr->representation().IsSmiOrInteger32());
ASSERT(instr->left()->representation().Equals(instr->representation()));
ASSERT(instr->right()->representation().Equals(instr->representation()));
......@@ -1361,13 +1361,25 @@ LInstruction* LChunkBuilder::DoFlooringDivByConstI(HMathFloorOfDiv* instr) {
}
LInstruction* LChunkBuilder::DoFlooringDivI(HMathFloorOfDiv* instr) {
ASSERT(instr->representation().IsSmiOrInteger32());
ASSERT(instr->left()->representation().Equals(instr->representation()));
ASSERT(instr->right()->representation().Equals(instr->representation()));
LOperand* dividend = UseRegister(instr->left());
LOperand* divisor = UseRegister(instr->right());
LOperand* temp = CpuFeatures::IsSupported(SUDIV) ? NULL : FixedTemp(d4);
LFlooringDivI* div = new(zone()) LFlooringDivI(dividend, divisor, temp);
return AssignEnvironment(DefineAsRegister(div));
}
LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
if (instr->RightIsPowerOf2()) {
return DoFlooringDivByPowerOf2I(instr);
} else if (instr->right()->IsConstant()) {
return DoFlooringDivByConstI(instr);
} else {
return DoDivI(instr);
return DoFlooringDivI(instr);
}
}
......
......@@ -97,6 +97,7 @@ class LCodeGen;
V(DummyUse) \
V(FlooringDivByConstI) \
V(FlooringDivByPowerOf2I) \
V(FlooringDivI) \
V(ForInCacheArray) \
V(ForInPrepareMap) \
V(FunctionLiteral) \
......@@ -713,14 +714,14 @@ class LDivByConstI V8_FINAL : public LTemplateInstruction<1, 1, 0> {
class LDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
public:
LDivI(LOperand* left, LOperand* right, LOperand* temp) {
inputs_[0] = left;
inputs_[1] = right;
LDivI(LOperand* dividend, LOperand* divisor, LOperand* temp) {
inputs_[0] = dividend;
inputs_[1] = divisor;
temps_[0] = temp;
}
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
LOperand* dividend() { return inputs_[0]; }
LOperand* divisor() { return inputs_[1]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(DivI, "div-i")
......@@ -767,6 +768,23 @@ class LFlooringDivByConstI V8_FINAL : public LTemplateInstruction<1, 1, 2> {
};
class LFlooringDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
public:
LFlooringDivI(LOperand* dividend, LOperand* divisor, LOperand* temp) {
inputs_[0] = dividend;
inputs_[1] = divisor;
temps_[0] = temp;
}
LOperand* dividend() { return inputs_[0]; }
LOperand* divisor() { return inputs_[1]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(FlooringDivI, "flooring-div-i")
DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
};
class LMulI V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
LMulI(LOperand* left, LOperand* right) {
......@@ -2722,12 +2740,13 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
LInstruction* DoMathClz32(HUnaryMathOperation* instr);
LInstruction* DoDivByPowerOf2I(HDiv* instr);
LInstruction* DoDivByConstI(HDiv* instr);
LInstruction* DoDivI(HBinaryOperation* instr);
LInstruction* DoDivI(HDiv* 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);
private:
enum Status {
......
......@@ -1363,15 +1363,16 @@ void LCodeGen::DoDivByConstI(LDivByConstI* instr) {
}
// TODO(svenpanne) Refactor this to avoid code duplication with DoFlooringDivI.
void LCodeGen::DoDivI(LDivI* instr) {
HBinaryOperation* hdiv = instr->hydrogen();
Register left = ToRegister(instr->left());
Register right = ToRegister(instr->right());
Register dividend = ToRegister(instr->dividend());
Register divisor = ToRegister(instr->divisor());
Register result = ToRegister(instr->result());
// Check for x / 0.
if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
__ cmp(right, Operand::Zero());
__ cmp(divisor, Operand::Zero());
DeoptimizeIf(eq, instr->environment());
}
......@@ -1380,10 +1381,10 @@ void LCodeGen::DoDivI(LDivI* instr) {
Label positive;
if (!instr->hydrogen_value()->CheckFlag(HValue::kCanBeDivByZero)) {
// Do the test only if it hadn't be done above.
__ cmp(right, Operand::Zero());
__ cmp(divisor, Operand::Zero());
}
__ b(pl, &positive);
__ cmp(left, Operand::Zero());
__ cmp(dividend, Operand::Zero());
DeoptimizeIf(eq, instr->environment());
__ bind(&positive);
}
......@@ -1394,39 +1395,30 @@ void LCodeGen::DoDivI(LDivI* instr) {
!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32))) {
// We don't need to check for overflow when truncating with sdiv
// support because, on ARM, sdiv kMinInt, -1 -> kMinInt.
__ cmp(left, Operand(kMinInt));
__ cmp(right, Operand(-1), eq);
__ cmp(dividend, Operand(kMinInt));
__ cmp(divisor, Operand(-1), eq);
DeoptimizeIf(eq, instr->environment());
}
if (CpuFeatures::IsSupported(SUDIV)) {
CpuFeatureScope scope(masm(), SUDIV);
__ sdiv(result, left, right);
__ sdiv(result, dividend, divisor);
} else {
DoubleRegister vleft = ToDoubleRegister(instr->temp());
DoubleRegister vright = double_scratch0();
__ vmov(double_scratch0().low(), left);
__ vmov(double_scratch0().low(), dividend);
__ vcvt_f64_s32(vleft, double_scratch0().low());
__ vmov(double_scratch0().low(), right);
__ vmov(double_scratch0().low(), divisor);
__ vcvt_f64_s32(vright, double_scratch0().low());
__ vdiv(vleft, vleft, vright); // vleft now contains the result.
__ vcvt_s32_f64(double_scratch0().low(), vleft);
__ vmov(result, double_scratch0().low());
}
if (hdiv->IsMathFloorOfDiv()) {
Label done;
Register remainder = scratch0();
__ mls(remainder, result, right, left);
__ cmp(remainder, Operand::Zero());
__ b(eq, &done);
__ eor(remainder, remainder, Operand(right));
__ add(result, result, Operand(remainder, ASR, 31));
__ bind(&done);
} else if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
// Compute remainder and deopt if it's not zero.
Register remainder = scratch0();
__ mls(remainder, result, right, left);
__ mls(remainder, result, divisor, dividend);
__ cmp(remainder, Operand::Zero());
DeoptimizeIf(ne, instr->environment());
}
......@@ -1538,6 +1530,69 @@ void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) {
}
// TODO(svenpanne) Refactor this to avoid code duplication with DoDivI.
void LCodeGen::DoFlooringDivI(LFlooringDivI* instr) {
HBinaryOperation* hdiv = instr->hydrogen();
Register left = ToRegister(instr->dividend());
Register right = ToRegister(instr->divisor());
Register result = ToRegister(instr->result());
// Check for x / 0.
if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
__ cmp(right, Operand::Zero());
DeoptimizeIf(eq, instr->environment());
}
// Check for (0 / -x) that will produce negative zero.
if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
Label positive;
if (!instr->hydrogen_value()->CheckFlag(HValue::kCanBeDivByZero)) {
// Do the test only if it hadn't be done above.
__ cmp(right, Operand::Zero());
}
__ b(pl, &positive);
__ cmp(left, Operand::Zero());
DeoptimizeIf(eq, instr->environment());
__ bind(&positive);
}
// Check for (kMinInt / -1).
if (hdiv->CheckFlag(HValue::kCanOverflow) &&
(!CpuFeatures::IsSupported(SUDIV) ||
!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32))) {
// We don't need to check for overflow when truncating with sdiv
// support because, on ARM, sdiv kMinInt, -1 -> kMinInt.
__ cmp(left, Operand(kMinInt));
__ cmp(right, Operand(-1), eq);
DeoptimizeIf(eq, instr->environment());
}
if (CpuFeatures::IsSupported(SUDIV)) {
CpuFeatureScope scope(masm(), SUDIV);
__ sdiv(result, left, right);
} else {
DoubleRegister vleft = ToDoubleRegister(instr->temp());
DoubleRegister vright = double_scratch0();
__ vmov(double_scratch0().low(), left);
__ vcvt_f64_s32(vleft, double_scratch0().low());
__ vmov(double_scratch0().low(), right);
__ vcvt_f64_s32(vright, double_scratch0().low());
__ vdiv(vleft, vleft, vright); // vleft now contains the result.
__ vcvt_s32_f64(double_scratch0().low(), vleft);
__ vmov(result, double_scratch0().low());
}
Label done;
Register remainder = scratch0();
__ mls(remainder, result, right, left);
__ cmp(remainder, Operand::Zero());
__ b(eq, &done);
__ eor(remainder, remainder, Operand(right));
__ add(result, result, Operand(remainder, ASR, 31));
__ bind(&done);
}
void LCodeGen::DoMulI(LMulI* instr) {
Register result = ToRegister(instr->result());
// Note that result may alias left.
......
......@@ -1324,14 +1324,14 @@ class LDivByConstI V8_FINAL : public LTemplateInstruction<1, 1, 1> {
class LDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
public:
LDivI(LOperand* left, LOperand* right, LOperand* temp) {
inputs_[0] = left;
inputs_[1] = right;
LDivI(LOperand* dividend, LOperand* divisor, LOperand* temp) {
inputs_[0] = dividend;
inputs_[1] = divisor;
temps_[0] = temp;
}
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
LOperand* dividend() { return inputs_[0]; }
LOperand* divisor() { return inputs_[1]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(DivI, "div-i")
......
......@@ -2707,10 +2707,11 @@ void LCodeGen::DoDivByConstI(LDivByConstI* instr) {
}
// TODO(svenpanne) Refactor this to avoid code duplication with DoFlooringDivI.
void LCodeGen::DoDivI(LDivI* instr) {
HBinaryOperation* hdiv = instr->hydrogen();
Register dividend = ToRegister32(instr->left());
Register divisor = ToRegister32(instr->right());
Register dividend = ToRegister32(instr->dividend());
Register divisor = ToRegister32(instr->divisor());
Register result = ToRegister32(instr->result());
// Issue the division first, and then check for any deopt cases whilst the
......@@ -3936,6 +3937,7 @@ void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) {
}
// TODO(svenpanne) Refactor this to avoid code duplication with DoDivI.
void LCodeGen::DoFlooringDivI(LFlooringDivI* instr) {
Register dividend = ToRegister32(instr->dividend());
Register divisor = ToRegister32(instr->divisor());
......
......@@ -1556,10 +1556,11 @@ void LCodeGen::DoDivByConstI(LDivByConstI* instr) {
}
// TODO(svenpanne) Refactor this to avoid code duplication with DoFlooringDivI.
void LCodeGen::DoDivI(LDivI* instr) {
HBinaryOperation* hdiv = instr->hydrogen();
Register dividend = ToRegister(instr->left());
Register divisor = ToRegister(instr->right());
Register dividend = ToRegister(instr->dividend());
Register divisor = ToRegister(instr->divisor());
Register remainder = ToRegister(instr->temp());
Register result = ToRegister(instr->result());
ASSERT(dividend.is(eax));
......@@ -1598,15 +1599,7 @@ void LCodeGen::DoDivI(LDivI* instr) {
__ cdq();
__ idiv(divisor);
if (hdiv->IsMathFloorOfDiv()) {
Label done;
__ test(remainder, remainder);
__ j(zero, &done, Label::kNear);
__ xor_(remainder, divisor);
__ sar(remainder, 31);
__ add(result, remainder);
__ bind(&done);
} else if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
// Deoptimize if remainder is not 0.
__ test(remainder, remainder);
DeoptimizeIf(not_zero, instr->environment());
......@@ -1696,6 +1689,59 @@ void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) {
}
// TODO(svenpanne) Refactor this to avoid code duplication with DoDivI.
void LCodeGen::DoFlooringDivI(LFlooringDivI* instr) {
HBinaryOperation* hdiv = instr->hydrogen();
Register dividend = ToRegister(instr->dividend());
Register divisor = ToRegister(instr->divisor());
Register remainder = ToRegister(instr->temp());
Register result = ToRegister(instr->result());
ASSERT(dividend.is(eax));
ASSERT(remainder.is(edx));
ASSERT(result.is(eax));
ASSERT(!divisor.is(eax));
ASSERT(!divisor.is(edx));
// Check for x / 0.
if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
__ test(divisor, divisor);
DeoptimizeIf(zero, instr->environment());
}
// Check for (0 / -x) that will produce negative zero.
if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
Label dividend_not_zero;
__ test(dividend, dividend);
__ j(not_zero, &dividend_not_zero, Label::kNear);
__ test(divisor, divisor);
DeoptimizeIf(sign, instr->environment());
__ bind(&dividend_not_zero);
}
// Check for (kMinInt / -1).
if (hdiv->CheckFlag(HValue::kCanOverflow)) {
Label dividend_not_min_int;
__ cmp(dividend, kMinInt);
__ j(not_zero, &dividend_not_min_int, Label::kNear);
__ cmp(divisor, -1);
DeoptimizeIf(zero, instr->environment());
__ bind(&dividend_not_min_int);
}
// Sign extend to edx (= remainder).
__ cdq();
__ idiv(divisor);
Label done;
__ test(remainder, remainder);
__ j(zero, &done, Label::kNear);
__ xor_(remainder, divisor);
__ sar(remainder, 31);
__ add(result, remainder);
__ bind(&done);
}
void LCodeGen::DoMulI(LMulI* instr) {
Register left = ToRegister(instr->left());
LOperand* right = instr->right();
......
......@@ -1365,7 +1365,7 @@ LInstruction* LChunkBuilder::DoDivByConstI(HDiv* instr) {
}
LInstruction* LChunkBuilder::DoDivI(HBinaryOperation* instr) {
LInstruction* LChunkBuilder::DoDivI(HDiv* instr) {
ASSERT(instr->representation().IsSmiOrInteger32());
ASSERT(instr->left()->representation().Equals(instr->representation()));
ASSERT(instr->right()->representation().Equals(instr->representation()));
......@@ -1377,8 +1377,7 @@ LInstruction* LChunkBuilder::DoDivI(HBinaryOperation* instr) {
if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
instr->CheckFlag(HValue::kCanOverflow) ||
(!instr->IsMathFloorOfDiv() &&
!instr->CheckFlag(HValue::kAllUsesTruncatingToInt32))) {
!instr->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
result = AssignEnvironment(result);
}
return result;
......@@ -1442,13 +1441,31 @@ LInstruction* LChunkBuilder::DoFlooringDivByConstI(HMathFloorOfDiv* instr) {
}
LInstruction* LChunkBuilder::DoFlooringDivI(HMathFloorOfDiv* instr) {
ASSERT(instr->representation().IsSmiOrInteger32());
ASSERT(instr->left()->representation().Equals(instr->representation()));
ASSERT(instr->right()->representation().Equals(instr->representation()));
LOperand* dividend = UseFixed(instr->left(), eax);
LOperand* divisor = UseRegister(instr->right());
LOperand* temp = FixedTemp(edx);
LInstruction* result = DefineFixed(new(zone()) LFlooringDivI(
dividend, divisor, temp), eax);
if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
instr->CheckFlag(HValue::kCanOverflow)) {
result = AssignEnvironment(result);
}
return result;
}
LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
if (instr->RightIsPowerOf2()) {
return DoFlooringDivByPowerOf2I(instr);
} else if (instr->right()->IsConstant()) {
return DoFlooringDivByConstI(instr);
} else {
return DoDivI(instr);
return DoFlooringDivI(instr);
}
}
......
......@@ -99,6 +99,7 @@ class LCodeGen;
V(DummyUse) \
V(FlooringDivByConstI) \
V(FlooringDivByPowerOf2I) \
V(FlooringDivI) \
V(ForInCacheArray) \
V(ForInPrepareMap) \
V(FunctionLiteral) \
......@@ -744,14 +745,14 @@ class LDivByConstI V8_FINAL : public LTemplateInstruction<1, 1, 2> {
class LDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
public:
LDivI(LOperand* left, LOperand* right, LOperand* temp) {
inputs_[0] = left;
inputs_[1] = right;
LDivI(LOperand* dividend, LOperand* divisor, LOperand* temp) {
inputs_[0] = dividend;
inputs_[1] = divisor;
temps_[0] = temp;
}
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
LOperand* dividend() { return inputs_[0]; }
LOperand* divisor() { return inputs_[1]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(DivI, "div-i")
......@@ -806,6 +807,23 @@ class LFlooringDivByConstI V8_FINAL : public LTemplateInstruction<1, 1, 3> {
};
class LFlooringDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
public:
LFlooringDivI(LOperand* dividend, LOperand* divisor, LOperand* temp) {
inputs_[0] = dividend;
inputs_[1] = divisor;
temps_[0] = temp;
}
LOperand* dividend() { return inputs_[0]; }
LOperand* divisor() { return inputs_[1]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(FlooringDivI, "flooring-div-i")
DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
};
class LMulI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
public:
LMulI(LOperand* left, LOperand* right, LOperand* temp) {
......@@ -2750,12 +2768,13 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
LInstruction* DoMathClz32(HUnaryMathOperation* instr);
LInstruction* DoDivByPowerOf2I(HDiv* instr);
LInstruction* DoDivByConstI(HDiv* instr);
LInstruction* DoDivI(HBinaryOperation* instr);
LInstruction* DoDivI(HDiv* 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);
private:
enum Status {
......
......@@ -1205,6 +1205,59 @@ void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) {
}
// TODO(svenpanne) Refactor this to avoid code duplication with DoDivI.
void LCodeGen::DoFlooringDivI(LFlooringDivI* instr) {
HBinaryOperation* hdiv = instr->hydrogen();
Register dividend = ToRegister(instr->dividend());
Register divisor = ToRegister(instr->divisor());
Register remainder = ToRegister(instr->temp());
Register result = ToRegister(instr->result());
ASSERT(dividend.is(rax));
ASSERT(remainder.is(rdx));
ASSERT(result.is(rax));
ASSERT(!divisor.is(rax));
ASSERT(!divisor.is(rdx));
// Check for x / 0.
if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
__ testl(divisor, divisor);
DeoptimizeIf(zero, instr->environment());
}
// Check for (0 / -x) that will produce negative zero.
if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
Label dividend_not_zero;
__ testl(dividend, dividend);
__ j(not_zero, &dividend_not_zero, Label::kNear);
__ testl(divisor, divisor);
DeoptimizeIf(sign, instr->environment());
__ bind(&dividend_not_zero);
}
// Check for (kMinInt / -1).
if (hdiv->CheckFlag(HValue::kCanOverflow)) {
Label dividend_not_min_int;
__ cmpl(dividend, Immediate(kMinInt));
__ j(not_zero, &dividend_not_min_int, Label::kNear);
__ cmpl(divisor, Immediate(-1));
DeoptimizeIf(zero, instr->environment());
__ bind(&dividend_not_min_int);
}
// Sign extend to rdx (= remainder).
__ cdq();
__ idivl(divisor);
Label done;
__ testl(remainder, remainder);
__ j(zero, &done, Label::kNear);
__ xorl(remainder, divisor);
__ sarl(remainder, Immediate(31));
__ addl(result, remainder);
__ bind(&done);
}
void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) {
Register dividend = ToRegister(instr->dividend());
int32_t divisor = instr->divisor();
......@@ -1272,10 +1325,11 @@ void LCodeGen::DoDivByConstI(LDivByConstI* instr) {
}
// TODO(svenpanne) Refactor this to avoid code duplication with DoFlooringDivI.
void LCodeGen::DoDivI(LDivI* instr) {
HBinaryOperation* hdiv = instr->hydrogen();
Register dividend = ToRegister(instr->left());
Register divisor = ToRegister(instr->right());
Register dividend = ToRegister(instr->dividend());
Register divisor = ToRegister(instr->divisor());
Register remainder = ToRegister(instr->temp());
Register result = ToRegister(instr->result());
ASSERT(dividend.is(rax));
......@@ -1314,15 +1368,7 @@ void LCodeGen::DoDivI(LDivI* instr) {
__ cdq();
__ idivl(divisor);
if (hdiv->IsMathFloorOfDiv()) {
Label done;
__ testl(remainder, remainder);
__ j(zero, &done, Label::kNear);
__ xorl(remainder, divisor);
__ sarl(remainder, Immediate(31));
__ addl(result, remainder);
__ bind(&done);
} else if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
// Deoptimize if remainder is not 0.
__ testl(remainder, remainder);
DeoptimizeIf(not_zero, instr->environment());
......
......@@ -1310,7 +1310,7 @@ LInstruction* LChunkBuilder::DoDivByConstI(HDiv* instr) {
}
LInstruction* LChunkBuilder::DoDivI(HBinaryOperation* instr) {
LInstruction* LChunkBuilder::DoDivI(HDiv* instr) {
ASSERT(instr->representation().IsSmiOrInteger32());
ASSERT(instr->left()->representation().Equals(instr->representation()));
ASSERT(instr->right()->representation().Equals(instr->representation()));
......@@ -1322,8 +1322,7 @@ LInstruction* LChunkBuilder::DoDivI(HBinaryOperation* instr) {
if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
instr->CheckFlag(HValue::kCanOverflow) ||
(!instr->IsMathFloorOfDiv() &&
!instr->CheckFlag(HValue::kAllUsesTruncatingToInt32))) {
!instr->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
result = AssignEnvironment(result);
}
return result;
......@@ -1387,13 +1386,31 @@ LInstruction* LChunkBuilder::DoFlooringDivByConstI(HMathFloorOfDiv* instr) {
}
LInstruction* LChunkBuilder::DoFlooringDivI(HMathFloorOfDiv* instr) {
ASSERT(instr->representation().IsSmiOrInteger32());
ASSERT(instr->left()->representation().Equals(instr->representation()));
ASSERT(instr->right()->representation().Equals(instr->representation()));
LOperand* dividend = UseFixed(instr->left(), rax);
LOperand* divisor = UseRegister(instr->right());
LOperand* temp = FixedTemp(rdx);
LInstruction* result = DefineFixed(new(zone()) LFlooringDivI(
dividend, divisor, temp), rax);
if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
instr->CheckFlag(HValue::kCanOverflow)) {
result = AssignEnvironment(result);
}
return result;
}
LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
if (instr->RightIsPowerOf2()) {
return DoFlooringDivByPowerOf2I(instr);
} else if (instr->right()->IsConstant()) {
return DoFlooringDivByConstI(instr);
} else {
return DoDivI(instr);
return DoFlooringDivI(instr);
}
}
......
......@@ -97,6 +97,7 @@ class LCodeGen;
V(Dummy) \
V(FlooringDivByConstI) \
V(FlooringDivByPowerOf2I) \
V(FlooringDivI) \
V(ForInCacheArray) \
V(ForInPrepareMap) \
V(FunctionLiteral) \
......@@ -732,14 +733,14 @@ class LDivByConstI V8_FINAL : public LTemplateInstruction<1, 1, 2> {
class LDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
public:
LDivI(LOperand* left, LOperand* right, LOperand* temp) {
inputs_[0] = left;
inputs_[1] = right;
LDivI(LOperand* dividend, LOperand* divisor, LOperand* temp) {
inputs_[0] = dividend;
inputs_[1] = divisor;
temps_[0] = temp;
}
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
LOperand* dividend() { return inputs_[0]; }
LOperand* divisor() { return inputs_[1]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(DivI, "div-i")
......@@ -794,6 +795,23 @@ class LFlooringDivByConstI V8_FINAL : public LTemplateInstruction<1, 1, 3> {
};
class LFlooringDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
public:
LFlooringDivI(LOperand* dividend, LOperand* divisor, LOperand* temp) {
inputs_[0] = dividend;
inputs_[1] = divisor;
temps_[0] = temp;
}
LOperand* dividend() { return inputs_[0]; }
LOperand* divisor() { return inputs_[1]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(FlooringDivI, "flooring-div-i")
DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
};
class LMulI V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
LMulI(LOperand* left, LOperand* right) {
......@@ -2681,12 +2699,13 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
LInstruction* DoMathClz32(HUnaryMathOperation* instr);
LInstruction* DoDivByPowerOf2I(HDiv* instr);
LInstruction* DoDivByConstI(HDiv* instr);
LInstruction* DoDivI(HBinaryOperation* instr);
LInstruction* DoDivI(HDiv* 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);
private:
enum Status {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment