Consistenly handle power-of-2 divisors in division-like operations

Lithium currently supports 3 division-like operations on integral operands: "Normal" division (rounding towards zero), flooring division (rounding towards -Infinity) and modulus calculation (the counterpart for the "normal" division). For divisors which are a power of 2, one can efficiently use some bit fiddling to avoid the actual division for such operations. This CL cleanly splits off these operations into separate Lithium instructions, making the code much more maintainable and more consistent across platforms.

There are 2 basic variations of these bit fiddling algorithms: One involving branches and a seemingly more clever one without branches. Choosing between the two is not as easy as it seems: Benchmarks (and probably real-world) programs seem to favor positive dividends, registers and shifting units are sometimes scarce resources, and branch prediction is quite good in modern processors. Therefore only the "normal" division by a power of 2 is implemented in a branch-free manner, this seems to be the best approach in practice. If this turns out to be wrong, we can easily and locally change this.

R=bmeurer@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19715 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
svenpanne@chromium.org 2014-03-07 10:36:28 +00:00
parent a1e59cca73
commit 819315db4e
14 changed files with 1468 additions and 964 deletions

View File

@ -1368,23 +1368,44 @@ LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* 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));
bool can_deopt =
(instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
instr->left()->RangeCanInclude(0) && divisor < 0) ||
(instr->CheckFlag(HValue::kCanOverflow) &&
instr->left()->RangeCanInclude(kMinInt) && divisor == -1) ||
(!instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
divisor != 1 && divisor != -1);
return can_deopt ? AssignEnvironment(result) : result;
}
LInstruction* LChunkBuilder::DoDivI(HBinaryOperation* 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 = instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)
? NULL : TempRegister();
LDivI* div = new(zone()) LDivI(dividend, divisor, temp);
return AssignEnvironment(DefineAsRegister(div));
}
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
if (instr->representation().IsInteger32()) {
// TODO(all): Update this case to support smi inputs.
ASSERT(instr->left()->representation().Equals(instr->representation()));
ASSERT(instr->right()->representation().Equals(instr->representation()));
if (instr->RightIsPowerOf2()) {
ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
LOperand* value = UseRegister(instr->left());
LDivI* div = new(zone()) LDivI(value, UseConstant(instr->right()), NULL);
return AssignEnvironment(DefineAsRegister(div));
}
LOperand* dividend = UseRegister(instr->left());
LOperand* divisor = UseRegister(instr->right());
LOperand* temp = instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)
? NULL : TempRegister();
LDivI* div = new(zone()) LDivI(dividend, divisor, temp);
return AssignEnvironment(DefineAsRegister(div));
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);
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::DIV, instr);
} else {
@ -1692,13 +1713,37 @@ LInstruction* LChunkBuilder::DoMapEnumLength(HMapEnumLength* instr) {
}
LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
HValue* right = instr->right();
LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
LOperand* dividend = UseRegisterAtStart(instr->left());
int32_t divisor = instr->right()->GetInteger32Constant();
LInstruction* result =
DefineSameAsFirst(new(zone()) LFlooringDivByPowerOf2I(dividend, divisor));
bool can_deopt =
(instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
(instr->left()->RangeCanInclude(kMinInt) && divisor == -1);
return can_deopt ? AssignEnvironment(result) : result;
}
LInstruction* LChunkBuilder::DoFlooringDivI(HMathFloorOfDiv* instr) {
LOperand* dividend = UseRegister(instr->left());
LOperand* divisor = UseRegister(right);
LOperand* divisor = UseRegister(instr->right());
LOperand* remainder = TempRegister();
return AssignEnvironment(DefineAsRegister(
new(zone()) LMathFloorOfDiv(dividend, divisor, remainder)));
LInstruction* result =
DefineAsRegister(new(zone()) LFlooringDivI(dividend, divisor, remainder));
return AssignEnvironment(result);
}
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);
} else {
return DoFlooringDivI(instr);
}
}
@ -1721,38 +1766,46 @@ LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
}
LInstruction* LChunkBuilder::DoMod(HMod* hmod) {
HValue* hleft = hmod->left();
HValue* hright = hmod->right();
LInstruction* LChunkBuilder::DoModByPowerOf2I(HMod* instr) {
ASSERT(instr->representation().IsSmiOrInteger32());
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 =
DefineSameAsFirst(new(zone()) LModByPowerOf2I(dividend, divisor));
bool can_deopt =
instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
instr->left()->CanBeNegative();
return can_deopt ? AssignEnvironment(result) : result;
}
// TODO(jbramley): Add smi support.
if (hmod->representation().IsInteger32()) {
ASSERT(hleft->representation().IsInteger32());
ASSERT(hleft->representation().IsInteger32());
LOperand* left_op;
LOperand* right_op;
if (hmod->RightIsPowerOf2()) {
left_op = UseRegisterAtStart(hleft);
right_op = UseConstant(hright);
} else {
right_op = UseRegister(hright);
left_op = UseRegister(hleft);
}
LInstruction* LChunkBuilder::DoModI(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());
LOperand* divisor = UseRegister(instr->right());
LInstruction* result =
DefineAsRegister(new(zone()) LModI(dividend, divisor));
bool can_deopt = (instr->right()->CanBeZero() ||
(instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
instr->left()->CanBeNegative() && instr->CanBeZero()));
return can_deopt ? AssignEnvironment(result) : result;
}
LModI* lmod = new(zone()) LModI(left_op, right_op);
if (hmod->right()->CanBeZero() ||
(hmod->CheckFlag(HValue::kBailoutOnMinusZero) &&
hmod->left()->CanBeNegative() && hmod->CanBeZero())) {
AssignEnvironment(lmod);
}
return DefineAsRegister(lmod);
} else if (hmod->representation().IsSmiOrTagged()) {
return DoArithmeticT(Token::MOD, hmod);
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);
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::MOD, instr);
} else {
return DoArithmeticD(Token::MOD, hmod);
return DoArithmeticT(Token::MOD, instr);
}
}

View File

@ -89,11 +89,14 @@ class LCodeGen;
V(DebugBreak) \
V(DeclareGlobals) \
V(Deoptimize) \
V(DivByPowerOf2I) \
V(DivI) \
V(DoubleToIntOrSmi) \
V(Drop) \
V(Dummy) \
V(DummyUse) \
V(FlooringDivByPowerOf2I) \
V(FlooringDivI) \
V(ForInCacheArray) \
V(ForInPrepareMap) \
V(FunctionLiteral) \
@ -133,12 +136,12 @@ class LCodeGen;
V(MathClz32) \
V(MathExp) \
V(MathFloor) \
V(MathFloorOfDiv) \
V(MathLog) \
V(MathMinMax) \
V(MathPowHalf) \
V(MathRound) \
V(MathSqrt) \
V(ModByPowerOf2I) \
V(ModI) \
V(MulConstIS) \
V(MulI) \
@ -1248,6 +1251,24 @@ class LDeoptimize V8_FINAL : public LTemplateInstruction<0, 0, 0> {
};
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 LDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
public:
LDivI(LOperand* left, LOperand* right, LOperand* temp) {
@ -1263,7 +1284,7 @@ class LDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
bool is_flooring() { return hydrogen_value()->IsMathFloorOfDiv(); }
DECLARE_CONCRETE_INSTRUCTION(DivI, "div-i")
DECLARE_HYDROGEN_ACCESSOR(Div)
DECLARE_HYDROGEN_ACCESSOR(BinaryOperation)
};
@ -1878,21 +1899,38 @@ class LMathFloor V8_FINAL : public LUnaryMathOperation<0> {
};
class LMathFloorOfDiv V8_FINAL : public LTemplateInstruction<1, 2, 1> {
class LFlooringDivByPowerOf2I V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
LMathFloorOfDiv(LOperand* left,
LOperand* right,
LOperand* temp = NULL) {
inputs_[0] = left;
inputs_[1] = right;
LFlooringDivByPowerOf2I(LOperand* dividend, int32_t divisor) {
inputs_[0] = dividend;
divisor_ = divisor;
}
LOperand* dividend() { return inputs_[0]; }
int32_t divisor() const { return divisor_; }
DECLARE_CONCRETE_INSTRUCTION(FlooringDivByPowerOf2I,
"flooring-div-by-power-of-2-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) {
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(MathFloorOfDiv, "math-floor-of-div")
DECLARE_CONCRETE_INSTRUCTION(FlooringDivI, "flooring-div-i")
DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
};
@ -1953,6 +1991,24 @@ class LMathSqrt V8_FINAL : public LUnaryMathOperation<0> {
};
class LModByPowerOf2I V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
LModByPowerOf2I(LOperand* dividend, int32_t divisor) {
inputs_[0] = dividend;
divisor_ = divisor;
}
LOperand* dividend() { return inputs_[0]; }
int32_t divisor() const { return divisor_; }
DECLARE_CONCRETE_INSTRUCTION(ModByPowerOf2I, "mod-by-power-of-2-i")
DECLARE_HYDROGEN_ACCESSOR(Mod)
private:
int32_t divisor_;
};
class LModI V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
LModI(LOperand* left, LOperand* right) {
@ -2843,6 +2899,13 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
#undef DECLARE_DO
LInstruction* DoDivByPowerOf2I(HDiv* instr);
LInstruction* DoDivI(HBinaryOperation* instr);
LInstruction* DoModByPowerOf2I(HMod* instr);
LInstruction* DoModI(HMod* instr);
LInstruction* DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr);
LInstruction* DoFlooringDivI(HMathFloorOfDiv* instr);
static bool HasMagicNumberForDivision(int32_t divisor);
private:

View File

@ -2564,50 +2564,53 @@ void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
}
void LCodeGen::DoDivI(LDivI* instr) {
if (!instr->is_flooring() && instr->hydrogen()->RightIsPowerOf2()) {
HDiv* hdiv = instr->hydrogen();
Register dividend = ToRegister32(instr->left());
int32_t divisor = hdiv->right()->GetInteger32Constant();
Register result = ToRegister32(instr->result());
ASSERT(!result.is(dividend));
void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) {
Register dividend = ToRegister32(instr->dividend());
int32_t divisor = instr->divisor();
Register result = ToRegister32(instr->result());
ASSERT(divisor == kMinInt || (divisor != 0 && IsPowerOf2(Abs(divisor))));
ASSERT(!result.is(dividend));
// Check for (0 / -x) that will produce negative zero.
if (hdiv->left()->RangeCanInclude(0) && divisor < 0 &&
hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
__ Cmp(dividend, 0);
DeoptimizeIf(eq, instr->environment());
}
// Check for (kMinInt / -1).
if (hdiv->left()->RangeCanInclude(kMinInt) && divisor == -1 &&
hdiv->CheckFlag(HValue::kCanOverflow)) {
__ Cmp(dividend, kMinInt);
DeoptimizeIf(eq, instr->environment());
}
// Deoptimize if remainder will not be 0.
if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
Abs(divisor) != 1) {
__ Tst(dividend, Abs(divisor) - 1);
DeoptimizeIf(ne, instr->environment());
}
if (divisor == -1) { // Nice shortcut, not needed for correctness.
__ Neg(result, dividend);
return;
}
int32_t shift = WhichPowerOf2(Abs(divisor));
if (shift == 0) {
__ Mov(result, dividend);
} else if (shift == 1) {
__ Add(result, dividend, Operand(dividend, LSR, 31));
} else {
__ Mov(result, Operand(dividend, ASR, 31));
__ Add(result, dividend, Operand(result, LSR, 32 - shift));
}
if (shift > 0) __ Mov(result, Operand(result, ASR, shift));
if (divisor < 0) __ Neg(result, result);
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, 0);
DeoptimizeIf(eq, instr->environment());
}
// Check for (kMinInt / -1).
if (hdiv->CheckFlag(HValue::kCanOverflow) &&
hdiv->left()->RangeCanInclude(kMinInt) && divisor == -1) {
__ Cmp(dividend, kMinInt);
DeoptimizeIf(eq, instr->environment());
}
// 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);
__ Tst(dividend, mask);
DeoptimizeIf(ne, instr->environment());
}
if (divisor == -1) { // Nice shortcut, not needed for correctness.
__ Neg(result, dividend);
return;
}
int32_t shift = WhichPowerOf2Abs(divisor);
if (shift == 0) {
__ Mov(result, dividend);
} else if (shift == 1) {
__ Add(result, dividend, Operand(dividend, LSR, 31));
} else {
__ Mov(result, Operand(dividend, ASR, 31));
__ Add(result, dividend, Operand(result, LSR, 32 - shift));
}
if (shift > 0) __ Mov(result, Operand(result, ASR, shift));
if (divisor < 0) __ Neg(result, result);
}
void LCodeGen::DoDivI(LDivI* instr) {
Register dividend = ToRegister32(instr->left());
Register divisor = ToRegister32(instr->right());
Register result = ToRegister32(instr->result());
@ -3780,44 +3783,81 @@ void LCodeGen::DoMathFloor(LMathFloor* instr) {
}
void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
Register result = ToRegister32(instr->result());
Register left = ToRegister32(instr->left());
Register right = ToRegister32(instr->right());
void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
Register dividend = ToRegister32(instr->dividend());
int32_t divisor = instr->divisor();
ASSERT(dividend.is(ToRegister32(instr->result())));
// If the divisor is positive, things are easy: There can be no deopts and we
// can simply do an arithmetic right shift.
if (divisor == 1) return;
int32_t shift = WhichPowerOf2Abs(divisor);
if (divisor > 1) {
__ Mov(dividend, Operand(dividend, ASR, shift));
return;
}
// If the divisor is negative, we have to negate and handle edge cases.
Label not_kmin_int, done;
__ Negs(dividend, dividend);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(eq, instr->environment());
}
if (instr->hydrogen()->left()->RangeCanInclude(kMinInt)) {
// Note that we could emit branch-free code, but that would need one more
// register.
__ B(vc, &not_kmin_int);
if (divisor == -1) {
Deoptimize(instr->environment());
} else {
__ Mov(dividend, kMinInt / divisor);
__ B(&done);
}
}
__ bind(&not_kmin_int);
__ Mov(dividend, Operand(dividend, ASR, shift));
__ bind(&done);
}
void LCodeGen::DoFlooringDivI(LFlooringDivI* instr) {
Register dividend = ToRegister32(instr->dividend());
Register divisor = ToRegister32(instr->divisor());
Register remainder = ToRegister32(instr->temp());
Register result = ToRegister32(instr->result());
// This can't cause an exception on ARM, so we can speculatively
// execute it already now.
__ Sdiv(result, left, right);
__ Sdiv(result, dividend, divisor);
// Check for x / 0.
DeoptimizeIfZero(right, instr->environment());
DeoptimizeIfZero(divisor, instr->environment());
// Check for (kMinInt / -1).
if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
// The V flag will be set iff left == kMinInt.
__ Cmp(left, 1);
__ Ccmp(right, -1, NoFlag, vs);
// The V flag will be set iff dividend == kMinInt.
__ Cmp(dividend, 1);
__ Ccmp(divisor, -1, NoFlag, vs);
DeoptimizeIf(eq, instr->environment());
}
// Check for (0 / -x) that will produce negative zero.
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
__ Cmp(right, 0);
__ Ccmp(left, 0, ZFlag, 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).
__ Cmp(divisor, 0);
__ Ccmp(dividend, 0, ZFlag, mi);
// "divisor" can't be null because the code would have already been
// deoptimized. The Z flag is set only if (divisor < 0) and (dividend == 0).
// In this case we need to deoptimize to produce a -0.
DeoptimizeIf(eq, instr->environment());
}
Label done;
// If both operands have the same sign then we are done.
__ Eor(remainder, left, right);
__ Eor(remainder, dividend, divisor);
__ Tbz(remainder, kWSignBit, &done);
// Check if the result needs to be corrected.
__ Msub(remainder, result, right, left);
__ Msub(remainder, result, divisor, dividend);
__ Cbz(remainder, &done);
__ Sub(result, result, 1);
@ -4006,58 +4046,64 @@ void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
}
void LCodeGen::DoModI(LModI* instr) {
void LCodeGen::DoModByPowerOf2I(LModByPowerOf2I* instr) {
Register dividend = ToRegister32(instr->dividend());
int32_t divisor = instr->divisor();
ASSERT(dividend.is(ToRegister32(instr->result())));
// Theoretically, a variation of the branch-free code for integer division by
// a power of 2 (calculating the remainder via an additional multiplication
// (which gets simplified to an 'and') and subtraction) should be faster, and
// this is exactly what GCC and clang emit. Nevertheless, benchmarks seem to
// indicate that positive dividends are heavily favored, so the branching
// version performs better.
HMod* hmod = instr->hydrogen();
HValue* hleft = hmod->left();
HValue* hright = hmod->right();
int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
Label dividend_is_not_negative, done;
if (hmod->left()->CanBeNegative()) {
__ Cmp(dividend, 0);
__ B(pl, &dividend_is_not_negative);
// Note that this is correct even for kMinInt operands.
__ Neg(dividend, dividend);
__ And(dividend, dividend, Operand(mask));
__ Neg(dividend, dividend);
if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(eq, instr->environment());
}
__ B(&done);
}
Label done;
Register result = ToRegister32(instr->result());
__ bind(&dividend_is_not_negative);
__ And(dividend, dividend, Operand(mask));
__ bind(&done);
}
void LCodeGen::DoModI(LModI* instr) {
Register dividend = ToRegister32(instr->left());
Register divisor = ToRegister32(instr->right());
Register result = ToRegister32(instr->result());
bool need_minus_zero_check = (hmod->CheckFlag(HValue::kBailoutOnMinusZero) &&
hleft->CanBeNegative() && hmod->CanBeZero());
if (hmod->RightIsPowerOf2()) {
// Note: The code below even works when right contains kMinInt.
int32_t divisor = Abs(hright->GetInteger32Constant());
if (hleft->CanBeNegative()) {
__ Cmp(dividend, 0);
__ Cneg(result, dividend, mi);
__ And(result, result, divisor - 1);
__ Cneg(result, result, mi);
if (need_minus_zero_check) {
__ Cbnz(result, &done);
// The result is 0. Deoptimize if the dividend was negative.
DeoptimizeIf(mi, instr->environment());
}
Label deopt, done;
// modulo = dividend - quotient * divisor
__ Sdiv(result, dividend, divisor);
if (instr->hydrogen()->right()->CanBeZero()) {
// Combine the deoptimization sites.
Label ok;
__ Cbnz(divisor, &ok);
__ Bind(&deopt);
Deoptimize(instr->environment());
__ Bind(&ok);
}
__ Msub(result, result, divisor, dividend);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero) &&
instr->hydrogen()->left()->CanBeNegative() &&
instr->hydrogen()->CanBeZero()) {
__ Cbnz(result, &done);
if (deopt.is_bound()) { // TODO(all) This is a hack, remove this...
__ Tbnz(dividend, kWSignBit, &deopt);
} else {
__ And(result, dividend, divisor - 1);
}
} else {
Label deopt;
Register divisor = ToRegister32(instr->right());
// Compute:
// modulo = dividend - quotient * divisor
__ Sdiv(result, dividend, divisor);
if (hright->CanBeZero()) {
// Combine the deoptimization sites.
Label ok;
__ Cbnz(divisor, &ok);
__ Bind(&deopt);
Deoptimize(instr->environment());
__ Bind(&ok);
}
__ Msub(result, result, divisor, dividend);
if (need_minus_zero_check) {
__ Cbnz(result, &done);
if (deopt.is_bound()) {
__ Tbnz(dividend, kWSignBit, &deopt);
} else {
DeoptimizeIfNegative(dividend, instr->environment());
}
DeoptimizeIfNegative(dividend, instr->environment());
}
}
__ Bind(&done);

View File

@ -1238,21 +1238,40 @@ 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));
bool can_deopt =
(instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
instr->left()->RangeCanInclude(0) && divisor < 0) ||
(instr->CheckFlag(HValue::kCanOverflow) &&
instr->left()->RangeCanInclude(kMinInt) && divisor == -1) ||
(!instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
divisor != 1 && divisor != -1);
return can_deopt ? AssignEnvironment(result) : result;
}
LInstruction* LChunkBuilder::DoDivI(HBinaryOperation* 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);
LDivI* div = new(zone()) LDivI(dividend, divisor, temp);
return AssignEnvironment(DefineAsRegister(div));
}
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
if (instr->representation().IsSmiOrInteger32()) {
ASSERT(instr->left()->representation().Equals(instr->representation()));
ASSERT(instr->right()->representation().Equals(instr->representation()));
if (instr->RightIsPowerOf2()) {
ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
LOperand* value = UseRegister(instr->left());
LDivI* div = new(zone()) LDivI(value, UseConstant(instr->right()), NULL);
return AssignEnvironment(DefineAsRegister(div));
}
LOperand* dividend = UseRegister(instr->left());
LOperand* divisor = UseRegister(instr->right());
LOperand* temp = CpuFeatures::IsSupported(SUDIV) ? NULL : FixedTemp(d4);
LDivI* div = new(zone()) LDivI(dividend, divisor, temp);
return AssignEnvironment(DefineAsRegister(div));
return instr->RightIsPowerOf2() ? DoDivByPowerOf2I(instr) : DoDivI(instr);
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::DIV, instr);
} else {
@ -1263,10 +1282,8 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
bool LChunkBuilder::HasMagicNumberForDivisor(int32_t divisor) {
uint32_t divisor_abs = abs(divisor);
// Dividing by 0, 1, and powers of 2 is easy.
// Note that IsPowerOf2(0) returns true;
ASSERT(IsPowerOf2(0) == true);
if (IsPowerOf2(divisor_abs)) return true;
// 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:
@ -1282,77 +1299,103 @@ bool LChunkBuilder::HasMagicNumberForDivisor(int32_t divisor) {
CompilerIntrinsics::CountTrailingZeros(divisor_abs);
DivMagicNumbers magic_numbers =
DivMagicNumberFor(divisor_abs >> power_of_2_factor);
if (magic_numbers.M != InvalidDivMagicNumber.M) return true;
return magic_numbers.M != InvalidDivMagicNumber.M;
}
return false;
LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
LOperand* dividend = UseRegisterAtStart(instr->left());
int32_t divisor = instr->right()->GetInteger32Constant();
LInstruction* result =
DefineSameAsFirst(
new(zone()) LFlooringDivByPowerOf2I(dividend, divisor));
bool can_deopt =
(instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
(instr->left()->RangeCanInclude(kMinInt) && divisor == -1);
return can_deopt ? AssignEnvironment(result) : result;
}
LInstruction* LChunkBuilder::DoFlooringDivByConstI(HMathFloorOfDiv* instr) {
LOperand* dividend = UseRegister(instr->left());
LOperand* divisor = CpuFeatures::IsSupported(SUDIV)
? UseRegister(instr->right())
: UseOrConstant(instr->right());
LOperand* remainder = TempRegister();
LInstruction* result =
DefineAsRegister(
new(zone()) LFlooringDivByConstI(dividend, divisor, remainder));
return AssignEnvironment(result);
}
LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
// LMathFloorOfDiv can only handle a subset of divisors, so fall
// back to a flooring division in all other cases.
HValue* right = instr->right();
if (!right->IsInteger32Constant() ||
(!CpuFeatures::IsSupported(SUDIV) &&
!HasMagicNumberForDivisor(HConstant::cast(right)->Integer32Value()))) {
LOperand* dividend = UseRegister(instr->left());
LOperand* divisor = UseRegister(right);
LOperand* temp = CpuFeatures::IsSupported(SUDIV) ? NULL : FixedTemp(d4);
LDivI* div = new(zone()) LDivI(dividend, divisor, temp);
return AssignEnvironment(DefineAsRegister(div));
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);
} else {
return DoDivI(instr);
}
}
LOperand* dividend = UseRegister(instr->left());
LOperand* divisor = CpuFeatures::IsSupported(SUDIV)
? UseRegister(right)
: UseOrConstant(right);
LOperand* remainder = TempRegister();
return AssignEnvironment(DefineAsRegister(
new(zone()) LMathFloorOfDiv(dividend, divisor, remainder)));
LInstruction* LChunkBuilder::DoModByPowerOf2I(HMod* instr) {
ASSERT(instr->representation().IsSmiOrInteger32());
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 =
DefineSameAsFirst(new(zone()) LModByPowerOf2I(dividend, divisor));
bool can_deopt =
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()));
ASSERT(instr->right()->representation().Equals(instr->representation()));
if (CpuFeatures::IsSupported(SUDIV)) {
LOperand* dividend = UseRegister(instr->left());
LOperand* divisor = UseRegister(instr->right());
LInstruction* result =
DefineAsRegister(new(zone()) LModI(dividend, divisor, NULL, NULL));
bool can_deopt = (instr->right()->CanBeZero() ||
(instr->left()->RangeCanInclude(kMinInt) &&
instr->right()->RangeCanInclude(-1) &&
instr->CheckFlag(HValue::kBailoutOnMinusZero)) ||
(instr->left()->CanBeNegative() &&
instr->CanBeZero() &&
instr->CheckFlag(HValue::kBailoutOnMinusZero)));
return can_deopt ? AssignEnvironment(result) : result;
} else {
LOperand* dividend = UseRegister(instr->left());
LOperand* divisor = UseRegister(instr->right());
LOperand* temp = FixedTemp(d10);
LOperand* temp2 = FixedTemp(d11);
LInstruction* result =
DefineAsRegister(new(zone()) LModI(dividend, divisor, temp, temp2));
bool can_deopt = (instr->right()->CanBeZero() ||
(instr->left()->CanBeNegative() &&
instr->CanBeZero() &&
instr->CheckFlag(HValue::kBailoutOnMinusZero)));
return can_deopt ? AssignEnvironment(result) : result;
}
}
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
HValue* left = instr->left();
HValue* right = instr->right();
if (instr->representation().IsSmiOrInteger32()) {
ASSERT(instr->left()->representation().Equals(instr->representation()));
ASSERT(instr->right()->representation().Equals(instr->representation()));
if (instr->RightIsPowerOf2()) {
ASSERT(!right->CanBeZero());
LModI* mod = new(zone()) LModI(UseRegisterAtStart(left),
UseConstant(right));
LInstruction* result = DefineAsRegister(mod);
return (left->CanBeNegative() &&
instr->CheckFlag(HValue::kBailoutOnMinusZero))
? AssignEnvironment(result)
: result;
} else if (CpuFeatures::IsSupported(SUDIV)) {
LModI* mod = new(zone()) LModI(UseRegister(left),
UseRegister(right));
LInstruction* result = DefineAsRegister(mod);
return (right->CanBeZero() ||
(left->RangeCanInclude(kMinInt) &&
right->RangeCanInclude(-1) &&
instr->CheckFlag(HValue::kBailoutOnMinusZero)) ||
(left->CanBeNegative() &&
instr->CanBeZero() &&
instr->CheckFlag(HValue::kBailoutOnMinusZero)))
? AssignEnvironment(result)
: result;
} else {
LModI* mod = new(zone()) LModI(UseRegister(left),
UseRegister(right),
FixedTemp(d10),
FixedTemp(d11));
LInstruction* result = DefineAsRegister(mod);
return (right->CanBeZero() ||
(left->CanBeNegative() &&
instr->CanBeZero() &&
instr->CheckFlag(HValue::kBailoutOnMinusZero)))
? AssignEnvironment(result)
: result;
}
return instr->RightIsPowerOf2() ? DoModByPowerOf2I(instr) : DoModI(instr);
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::MOD, instr);
} else {

View File

@ -85,12 +85,15 @@ class LCodeGen;
V(DebugBreak) \
V(DeclareGlobals) \
V(Deoptimize) \
V(DivByPowerOf2I) \
V(DivI) \
V(DoubleToI) \
V(DoubleToSmi) \
V(Drop) \
V(Dummy) \
V(DummyUse) \
V(FlooringDivByConstI) \
V(FlooringDivByPowerOf2I) \
V(ForInCacheArray) \
V(ForInPrepareMap) \
V(FunctionLiteral) \
@ -127,12 +130,12 @@ class LCodeGen;
V(MathClz32) \
V(MathExp) \
V(MathFloor) \
V(MathFloorOfDiv) \
V(MathLog) \
V(MathMinMax) \
V(MathPowHalf) \
V(MathRound) \
V(MathSqrt) \
V(ModByPowerOf2I) \
V(ModI) \
V(MulI) \
V(MultiplyAddD) \
@ -615,12 +618,27 @@ class LArgumentsElements V8_FINAL : public LTemplateInstruction<1, 0, 0> {
};
class LModByPowerOf2I V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
LModByPowerOf2I(LOperand* dividend, int32_t divisor) {
inputs_[0] = dividend;
divisor_ = divisor;
}
LOperand* dividend() { return inputs_[0]; }
int32_t divisor() const { return divisor_; }
DECLARE_CONCRETE_INSTRUCTION(ModByPowerOf2I, "mod-by-power-of-2-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 = NULL,
LOperand* temp2 = NULL) {
LModI(LOperand* left, LOperand* right, LOperand* temp, LOperand* temp2) {
inputs_[0] = left;
inputs_[1] = right;
temps_[0] = temp;
@ -637,6 +655,24 @@ class LModI V8_FINAL : public LTemplateInstruction<1, 2, 2> {
};
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 LDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
public:
LDivI(LOperand* left, LOperand* right, LOperand* temp) {
@ -652,25 +688,42 @@ class LDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
bool is_flooring() { return hydrogen_value()->IsMathFloorOfDiv(); }
DECLARE_CONCRETE_INSTRUCTION(DivI, "div-i")
DECLARE_HYDROGEN_ACCESSOR(Div)
DECLARE_HYDROGEN_ACCESSOR(BinaryOperation)
};
class LMathFloorOfDiv V8_FINAL : public LTemplateInstruction<1, 2, 1> {
class LFlooringDivByPowerOf2I V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
LMathFloorOfDiv(LOperand* left,
LOperand* right,
LOperand* temp = NULL) {
inputs_[0] = left;
inputs_[1] = right;
LFlooringDivByPowerOf2I(LOperand* dividend, int32_t divisor) {
inputs_[0] = dividend;
divisor_ = divisor;
}
LOperand* dividend() { return inputs_[0]; }
int32_t divisor() { return divisor_; }
DECLARE_CONCRETE_INSTRUCTION(FlooringDivByPowerOf2I,
"flooring-div-by-power-of-2-i")
DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
private:
int32_t divisor_;
};
class LFlooringDivByConstI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
public:
LFlooringDivByConstI(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(MathFloorOfDiv, "math-floor-of-div")
DECLARE_CONCRETE_INSTRUCTION(FlooringDivByConstI, "flooring-div-by-const-i")
DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
};
@ -2628,6 +2681,12 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
LInstruction* DoMathSqrt(HUnaryMathOperation* instr);
LInstruction* DoMathPowHalf(HUnaryMathOperation* instr);
LInstruction* DoMathClz32(HUnaryMathOperation* instr);
LInstruction* DoDivByPowerOf2I(HDiv* instr);
LInstruction* DoDivI(HBinaryOperation* instr);
LInstruction* DoModByPowerOf2I(HMod* instr);
LInstruction* DoModI(HMod* instr);
LInstruction* DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr);
LInstruction* DoFlooringDivByConstI(HMathFloorOfDiv* instr);
private:
enum Status {

View File

@ -1111,36 +1111,44 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
}
void LCodeGen::DoModByPowerOf2I(LModByPowerOf2I* instr) {
Register dividend = ToRegister(instr->dividend());
int32_t divisor = instr->divisor();
ASSERT(dividend.is(ToRegister(instr->result())));
// Theoretically, a variation of the branch-free code for integer division by
// a power of 2 (calculating the remainder via an additional multiplication
// (which gets simplified to an 'and') and subtraction) should be faster, and
// this is exactly what GCC and clang emit. Nevertheless, benchmarks seem to
// indicate that positive dividends are heavily favored, so the branching
// version performs better.
HMod* hmod = instr->hydrogen();
int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
Label dividend_is_not_negative, done;
if (hmod->left()->CanBeNegative()) {
__ cmp(dividend, Operand::Zero());
__ b(pl, &dividend_is_not_negative);
// Note that this is correct even for kMinInt operands.
__ rsb(dividend, dividend, Operand::Zero());
__ and_(dividend, dividend, Operand(mask));
__ rsb(dividend, dividend, Operand::Zero(), SetCC);
if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(eq, instr->environment());
}
__ b(&done);
}
__ bind(&dividend_is_not_negative);
__ and_(dividend, dividend, Operand(mask));
__ bind(&done);
}
void LCodeGen::DoModI(LModI* instr) {
HMod* hmod = instr->hydrogen();
HValue* left = hmod->left();
HValue* right = hmod->right();
if (hmod->RightIsPowerOf2()) {
// TODO(svenpanne) We should really do the strength reduction on the
// Hydrogen level.
Register left_reg = ToRegister(instr->left());
Register result_reg = ToRegister(instr->result());
// Note: The code below even works when right contains kMinInt.
int32_t divisor = Abs(right->GetInteger32Constant());
Label left_is_not_negative, done;
if (left->CanBeNegative()) {
__ cmp(left_reg, Operand::Zero());
__ b(pl, &left_is_not_negative);
__ rsb(result_reg, left_reg, Operand::Zero());
__ and_(result_reg, result_reg, Operand(divisor - 1));
__ rsb(result_reg, result_reg, Operand::Zero(), SetCC);
if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(eq, instr->environment());
}
__ b(&done);
}
__ bind(&left_is_not_negative);
__ and_(result_reg, left_reg, Operand(divisor - 1));
__ bind(&done);
} else if (CpuFeatures::IsSupported(SUDIV)) {
if (CpuFeatures::IsSupported(SUDIV)) {
CpuFeatureScope scope(masm(), SUDIV);
Register left_reg = ToRegister(instr->left());
@ -1344,50 +1352,53 @@ void LCodeGen::EmitSignedIntegerDivisionByConstant(
}
void LCodeGen::DoDivI(LDivI* instr) {
if (!instr->is_flooring() && instr->hydrogen()->RightIsPowerOf2()) {
Register dividend = ToRegister(instr->left());
HDiv* hdiv = instr->hydrogen();
int32_t divisor = hdiv->right()->GetInteger32Constant();
Register result = ToRegister(instr->result());
ASSERT(!result.is(dividend));
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.
if (hdiv->left()->RangeCanInclude(0) && divisor < 0 &&
hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
__ cmp(dividend, Operand::Zero());
DeoptimizeIf(eq, instr->environment());
}
// Check for (kMinInt / -1).
if (hdiv->left()->RangeCanInclude(kMinInt) && divisor == -1 &&
hdiv->CheckFlag(HValue::kCanOverflow)) {
__ cmp(dividend, Operand(kMinInt));
DeoptimizeIf(eq, instr->environment());
}
// Deoptimize if remainder will not be 0.
if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
Abs(divisor) != 1) {
__ tst(dividend, Operand(Abs(divisor) - 1));
DeoptimizeIf(ne, instr->environment());
}
if (divisor == -1) { // Nice shortcut, not needed for correctness.
__ rsb(result, dividend, Operand(0));
return;
}
int32_t shift = WhichPowerOf2(Abs(divisor));
if (shift == 0) {
__ mov(result, dividend);
} else if (shift == 1) {
__ add(result, dividend, Operand(dividend, LSR, 31));
} else {
__ mov(result, Operand(dividend, ASR, 31));
__ add(result, dividend, Operand(result, LSR, 32 - shift));
}
if (shift > 0) __ mov(result, Operand(result, ASR, shift));
if (divisor < 0) __ rsb(result, result, Operand(0));
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());
}
// Check for (kMinInt / -1).
if (hdiv->CheckFlag(HValue::kCanOverflow) &&
hdiv->left()->RangeCanInclude(kMinInt) && divisor == -1) {
__ cmp(dividend, Operand(kMinInt));
DeoptimizeIf(eq, instr->environment());
}
// 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);
__ tst(dividend, Operand(mask));
DeoptimizeIf(ne, instr->environment());
}
if (divisor == -1) { // Nice shortcut, not needed for correctness.
__ rsb(result, dividend, Operand(0));
return;
}
int32_t shift = WhichPowerOf2Abs(divisor);
if (shift == 0) {
__ mov(result, dividend);
} else if (shift == 1) {
__ add(result, dividend, Operand(dividend, LSR, 31));
} else {
__ mov(result, Operand(dividend, ASR, 31));
__ add(result, dividend, Operand(result, LSR, 32 - shift));
}
if (shift > 0) __ mov(result, Operand(result, ASR, shift));
if (divisor < 0) __ rsb(result, result, Operand(0));
}
void LCodeGen::DoDivI(LDivI* instr) {
const Register left = ToRegister(instr->left());
const Register right = ToRegister(instr->right());
const Register result = ToRegister(instr->result());
@ -1482,18 +1493,55 @@ void LCodeGen::DoMultiplySubD(LMultiplySubD* 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();
void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
Register dividend = ToRegister(instr->dividend());
int32_t divisor = instr->divisor();
ASSERT(dividend.is(ToRegister(instr->result())));
// If the divisor is positive, things are easy: There can be no deopts and we
// can simply do an arithmetic right shift.
if (divisor == 1) return;
int32_t shift = WhichPowerOf2Abs(divisor);
if (divisor > 1) {
__ mov(dividend, Operand(dividend, ASR, shift));
return;
}
// If the divisor is negative, we have to negate and handle edge cases.
Label not_kmin_int, done;
__ rsb(dividend, dividend, Operand::Zero(), SetCC);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(eq, instr->environment());
}
if (instr->hydrogen()->left()->RangeCanInclude(kMinInt)) {
// Note that we could emit branch-free code, but that would need one more
// register.
__ b(vc, &not_kmin_int);
if (divisor == -1) {
DeoptimizeIf(al, instr->environment());
} else {
__ mov(dividend, Operand(kMinInt / divisor));
__ b(&done);
}
}
__ bind(&not_kmin_int);
__ mov(dividend, Operand(dividend, ASR, shift));
__ bind(&done);
}
void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) {
Register left = ToRegister(instr->dividend());
Register remainder = ToRegister(instr->temp());
Register scratch = scratch0();
Register result = ToRegister(instr->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->right()->IsConstantOperand());
int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right()));
ASSERT(instr->divisor()->IsConstantOperand());
int32_t divisor = ToInteger32(LConstantOperand::cast(instr->divisor()));
ASSERT(LChunkBuilder::HasMagicNumberForDivisor(divisor));
if (divisor < 0) {
__ cmp(left, Operand::Zero());
@ -1511,7 +1559,8 @@ void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
__ sub(result, result, Operand(1), LeaveCC, mi);
} else {
CpuFeatureScope scope(masm(), SUDIV);
const Register right = ToRegister(instr->right());
// TODO(svenpanne) We *statically* know the divisor, use that fact!
Register right = ToRegister(instr->divisor());
// Check for x / 0.
__ cmp(right, Operand::Zero());

View File

@ -3713,6 +3713,12 @@ class HBinaryOperation : public HTemplateInstruction<3> {
set_operand_position(zone, 2, right_pos);
}
bool RightIsPowerOf2() {
if (!right()->IsInteger32Constant()) return false;
int32_t value = right()->GetInteger32Constant();
return value != 0 && (IsPowerOf2(value) || IsPowerOf2(-value));
}
DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation)
private:
@ -4089,12 +4095,6 @@ class HArithmeticBinaryOperation : public HBinaryOperation {
}
}
bool RightIsPowerOf2() {
if (!right()->IsInteger32Constant()) return false;
int32_t value = right()->GetInteger32Constant();
return value != 0 && (IsPowerOf2(value) || IsPowerOf2(-value));
}
DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation)
private:

View File

@ -1368,286 +1368,292 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
}
void LCodeGen::DoModByPowerOf2I(LModByPowerOf2I* instr) {
Register dividend = ToRegister(instr->dividend());
int32_t divisor = instr->divisor();
ASSERT(dividend.is(ToRegister(instr->result())));
// Theoretically, a variation of the branch-free code for integer division by
// a power of 2 (calculating the remainder via an additional multiplication
// (which gets simplified to an 'and') and subtraction) should be faster, and
// this is exactly what GCC and clang emit. Nevertheless, benchmarks seem to
// indicate that positive dividends are heavily favored, so the branching
// version performs better.
HMod* hmod = instr->hydrogen();
int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
Label dividend_is_not_negative, done;
if (hmod->left()->CanBeNegative()) {
__ test(dividend, dividend);
__ j(not_sign, &dividend_is_not_negative, Label::kNear);
// Note that this is correct even for kMinInt operands.
__ neg(dividend);
__ and_(dividend, mask);
__ neg(dividend);
if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(zero, instr->environment());
}
__ jmp(&done, Label::kNear);
}
__ bind(&dividend_is_not_negative);
__ and_(dividend, mask);
__ bind(&done);
}
void LCodeGen::DoModI(LModI* instr) {
HMod* hmod = instr->hydrogen();
HValue* left = hmod->left();
HValue* right = hmod->right();
if (hmod->RightIsPowerOf2()) {
// TODO(svenpanne) We should really do the strength reduction on the
// Hydrogen level.
Register left_reg = ToRegister(instr->left());
ASSERT(left_reg.is(ToRegister(instr->result())));
// Note: The code below even works when right contains kMinInt.
int32_t divisor = Abs(right->GetInteger32Constant());
Register left_reg = ToRegister(instr->left());
ASSERT(left_reg.is(eax));
Register right_reg = ToRegister(instr->right());
ASSERT(!right_reg.is(eax));
ASSERT(!right_reg.is(edx));
Register result_reg = ToRegister(instr->result());
ASSERT(result_reg.is(edx));
Label left_is_not_negative, done;
if (left->CanBeNegative()) {
__ test(left_reg, Operand(left_reg));
__ j(not_sign, &left_is_not_negative, Label::kNear);
__ neg(left_reg);
__ and_(left_reg, divisor - 1);
__ neg(left_reg);
if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(zero, instr->environment());
}
__ jmp(&done, Label::kNear);
}
__ bind(&left_is_not_negative);
__ and_(left_reg, divisor - 1);
__ bind(&done);
} else {
Register left_reg = ToRegister(instr->left());
ASSERT(left_reg.is(eax));
Register right_reg = ToRegister(instr->right());
ASSERT(!right_reg.is(eax));
ASSERT(!right_reg.is(edx));
Register result_reg = ToRegister(instr->result());
ASSERT(result_reg.is(edx));
Label done;
// Check for x % 0, idiv would signal a divide error. We have to
// deopt in this case because we can't return a NaN.
if (right->CanBeZero()) {
__ test(right_reg, Operand(right_reg));
DeoptimizeIf(zero, instr->environment());
}
// Check for kMinInt % -1, idiv would signal a divide error. We
// have to deopt if we care about -0, because we can't return that.
if (left->RangeCanInclude(kMinInt) && right->RangeCanInclude(-1)) {
Label no_overflow_possible;
__ cmp(left_reg, kMinInt);
__ j(not_equal, &no_overflow_possible, Label::kNear);
__ cmp(right_reg, -1);
if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(equal, instr->environment());
} else {
__ j(not_equal, &no_overflow_possible, Label::kNear);
__ Set(result_reg, Immediate(0));
__ jmp(&done, Label::kNear);
}
__ bind(&no_overflow_possible);
}
// Sign extend dividend in eax into edx:eax.
__ cdq();
// If we care about -0, test if the dividend is <0 and the result is 0.
if (left->CanBeNegative() &&
hmod->CanBeZero() &&
hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
Label positive_left;
__ test(left_reg, Operand(left_reg));
__ j(not_sign, &positive_left, Label::kNear);
__ idiv(right_reg);
__ test(result_reg, Operand(result_reg));
DeoptimizeIf(zero, instr->environment());
__ jmp(&done, Label::kNear);
__ bind(&positive_left);
}
__ idiv(right_reg);
__ bind(&done);
Label done;
// Check for x % 0, idiv would signal a divide error. We have to
// deopt in this case because we can't return a NaN.
if (right->CanBeZero()) {
__ test(right_reg, Operand(right_reg));
DeoptimizeIf(zero, instr->environment());
}
// Check for kMinInt % -1, idiv would signal a divide error. We
// have to deopt if we care about -0, because we can't return that.
if (left->RangeCanInclude(kMinInt) && right->RangeCanInclude(-1)) {
Label no_overflow_possible;
__ cmp(left_reg, kMinInt);
__ j(not_equal, &no_overflow_possible, Label::kNear);
__ cmp(right_reg, -1);
if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(equal, instr->environment());
} else {
__ j(not_equal, &no_overflow_possible, Label::kNear);
__ Set(result_reg, Immediate(0));
__ jmp(&done, Label::kNear);
}
__ bind(&no_overflow_possible);
}
// Sign extend dividend in eax into edx:eax.
__ cdq();
// If we care about -0, test if the dividend is <0 and the result is 0.
if (left->CanBeNegative() &&
hmod->CanBeZero() &&
hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
Label positive_left;
__ test(left_reg, Operand(left_reg));
__ j(not_sign, &positive_left, Label::kNear);
__ idiv(right_reg);
__ test(result_reg, Operand(result_reg));
DeoptimizeIf(zero, instr->environment());
__ jmp(&done, Label::kNear);
__ bind(&positive_left);
}
__ idiv(right_reg);
__ bind(&done);
}
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) &&
hdiv->left()->RangeCanInclude(0) && divisor < 0) {
__ test(dividend, dividend);
DeoptimizeIf(zero, instr->environment());
}
// Check for (kMinInt / -1).
if (hdiv->CheckFlag(HValue::kCanOverflow) &&
hdiv->left()->RangeCanInclude(kMinInt) && divisor == -1) {
__ cmp(dividend, kMinInt);
DeoptimizeIf(zero, instr->environment());
}
// 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);
__ test(dividend, Immediate(mask));
DeoptimizeIf(not_zero, instr->environment());
}
__ Move(result, dividend);
int32_t shift = WhichPowerOf2Abs(divisor);
if (shift > 0) {
// The arithmetic shift is always OK, the 'if' is an optimization only.
if (shift > 1) __ sar(result, 31);
__ shr(result, 32 - shift);
__ add(result, dividend);
__ sar(result, shift);
}
if (divisor < 0) __ neg(result);
}
void LCodeGen::DoDivI(LDivI* instr) {
if (!instr->is_flooring() && instr->hydrogen()->RightIsPowerOf2()) {
Register dividend = ToRegister(instr->left());
HDiv* hdiv = instr->hydrogen();
int32_t divisor = hdiv->right()->GetInteger32Constant();
Register result = ToRegister(instr->result());
ASSERT(!result.is(dividend));
// Check for (0 / -x) that will produce negative zero.
if (hdiv->left()->RangeCanInclude(0) && divisor < 0 &&
hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
__ test(dividend, Operand(dividend));
DeoptimizeIf(zero, instr->environment());
}
// Check for (kMinInt / -1).
if (hdiv->left()->RangeCanInclude(kMinInt) && divisor == -1 &&
hdiv->CheckFlag(HValue::kCanOverflow)) {
__ cmp(dividend, kMinInt);
DeoptimizeIf(zero, instr->environment());
}
// Deoptimize if remainder will not be 0.
if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
Abs(divisor) != 1) {
__ test(dividend, Immediate(Abs(divisor) - 1));
DeoptimizeIf(not_zero, instr->environment());
}
__ Move(result, dividend);
int32_t shift = WhichPowerOf2(Abs(divisor));
if (shift > 0) {
// The arithmetic shift is always OK, the 'if' is an optimization only.
if (shift > 1) __ sar(result, 31);
__ shr(result, 32 - shift);
__ add(result, dividend);
__ sar(result, shift);
}
if (divisor < 0) __ neg(result);
return;
}
LOperand* right = instr->right();
ASSERT(ToRegister(instr->result()).is(eax));
ASSERT(ToRegister(instr->left()).is(eax));
ASSERT(!ToRegister(instr->right()).is(eax));
ASSERT(!ToRegister(instr->right()).is(edx));
Register left_reg = eax;
Register dividend = ToRegister(instr->left());
Register divisor = ToRegister(instr->right());
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.
Register right_reg = ToRegister(right);
if (instr->hydrogen_value()->CheckFlag(HValue::kCanBeDivByZero)) {
__ test(right_reg, ToOperand(right));
HBinaryOperation* hdiv = instr->hydrogen();
if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
__ test(divisor, divisor);
DeoptimizeIf(zero, instr->environment());
}
// Check for (0 / -x) that will produce negative zero.
if (instr->hydrogen_value()->CheckFlag(HValue::kBailoutOnMinusZero)) {
Label left_not_zero;
__ test(left_reg, Operand(left_reg));
__ j(not_zero, &left_not_zero, Label::kNear);
__ test(right_reg, ToOperand(right));
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(&left_not_zero);
__ bind(&dividend_not_zero);
}
// Check for (kMinInt / -1).
if (instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)) {
Label left_not_min_int;
__ cmp(left_reg, kMinInt);
__ j(not_zero, &left_not_min_int, Label::kNear);
__ cmp(right_reg, -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(&left_not_min_int);
__ bind(&dividend_not_min_int);
}
// Sign extend to edx.
// Sign extend to edx (= remainder).
__ cdq();
__ idiv(right_reg);
__ idiv(divisor);
if (instr->is_flooring()) {
Label done;
__ test(edx, edx);
__ test(remainder, remainder);
__ j(zero, &done, Label::kNear);
__ xor_(edx, right_reg);
__ sar(edx, 31);
__ add(eax, edx);
__ xor_(remainder, divisor);
__ sar(remainder, 31);
__ add(result, remainder);
__ bind(&done);
} else if (!instr->hydrogen()->CheckFlag(
HInstruction::kAllUsesTruncatingToInt32)) {
// Deoptimize if remainder is not 0.
__ test(edx, Operand(edx));
__ test(remainder, remainder);
DeoptimizeIf(not_zero, instr->environment());
}
}
void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
ASSERT(instr->right()->IsConstantOperand());
void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
Register dividend = ToRegister(instr->dividend());
int32_t divisor = instr->divisor();
ASSERT(dividend.is(ToRegister(instr->result())));
Register dividend = ToRegister(instr->left());
int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right()));
Register result = ToRegister(instr->result());
// If the divisor is positive, things are easy: There can be no deopts and we
// can simply do an arithmetic right shift.
if (divisor == 1) return;
int32_t shift = WhichPowerOf2Abs(divisor);
if (divisor > 1) {
__ sar(dividend, shift);
return;
}
switch (divisor) {
case 0:
// If the divisor is negative, we have to negate and handle edge cases.
Label not_kmin_int, done;
__ neg(dividend);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(zero, instr->environment());
}
if (instr->hydrogen()->left()->RangeCanInclude(kMinInt)) {
// Note that we could emit branch-free code, but that would need one more
// register.
__ j(no_overflow, &not_kmin_int, Label::kNear);
if (divisor == -1) {
DeoptimizeIf(no_condition, instr->environment());
} else {
__ mov(dividend, Immediate(kMinInt / divisor));
__ jmp(&done, Label::kNear);
}
}
__ bind(&not_kmin_int);
__ sar(dividend, shift);
__ bind(&done);
}
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) {
DeoptimizeIf(no_condition, instr->environment());
return;
case 1:
__ Move(result, dividend);
return;
case -1:
__ Move(result, dividend);
__ neg(result);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(zero, instr->environment());
}
if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
DeoptimizeIf(overflow, instr->environment());
}
return;
}
// Find b which: 2^b < divisor_abs < 2^(b+1).
uint32_t divisor_abs = abs(divisor);
if (IsPowerOf2(divisor_abs)) {
int32_t power = WhichPowerOf2(divisor_abs);
if (divisor < 0) {
// Input[dividend] is clobbered.
// The sequence is tedious because neg(dividend) might overflow.
__ mov(result, dividend);
__ sar(dividend, 31);
__ neg(result);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(zero, instr->environment());
}
__ shl(dividend, 32 - power);
__ sar(result, power);
__ not_(dividend);
// Clear result.sign if dividend.sign is set.
__ and_(result, dividend);
} else {
__ Move(result, dividend);
__ sar(result, power);
}
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 {
ASSERT(ToRegister(instr->left()).is(eax));
ASSERT(ToRegister(instr->result()).is(edx));
Register scratch = ToRegister(instr->temp());
// Find b which: 2^b < divisor_abs < 2^(b+1).
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)) {
__ 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);
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)) {
__ 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);
}

View File

@ -1321,24 +1321,40 @@ 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));
bool can_deopt =
(instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
instr->left()->RangeCanInclude(0) && divisor < 0) ||
(instr->CheckFlag(HValue::kCanOverflow) &&
instr->left()->RangeCanInclude(kMinInt) && divisor == -1) ||
(!instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
divisor != 1 && divisor != -1);
return can_deopt ? AssignEnvironment(result) : result;
}
LInstruction* LChunkBuilder::DoDivI(HBinaryOperation* 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);
LDivI* result = new(zone()) LDivI(dividend, divisor, temp);
return AssignEnvironment(DefineFixed(result, eax));
}
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
if (instr->representation().IsSmiOrInteger32()) {
ASSERT(instr->left()->representation().Equals(instr->representation()));
ASSERT(instr->right()->representation().Equals(instr->representation()));
if (instr->RightIsPowerOf2()) {
ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
LOperand* value = UseRegister(instr->left());
LDivI* div =
new(zone()) LDivI(value, UseOrConstant(instr->right()), NULL);
return AssignEnvironment(DefineAsRegister(div));
}
// The temporary operand is necessary to ensure that right is not allocated
// into edx.
LOperand* temp = FixedTemp(edx);
LOperand* dividend = UseFixed(instr->left(), eax);
LOperand* divisor = UseRegister(instr->right());
LDivI* result = new(zone()) LDivI(dividend, divisor, temp);
return AssignEnvironment(DefineFixed(result, eax));
return instr->RightIsPowerOf2() ? DoDivByPowerOf2I(instr) : DoDivI(instr);
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::DIV, instr);
} else {
@ -1347,79 +1363,79 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
}
LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
HValue* right = instr->right();
if (!right->IsConstant()) {
ASSERT(right->representation().IsInteger32());
// The temporary operand is necessary to ensure that right is not allocated
// into edx.
LOperand* temp = FixedTemp(edx);
LOperand* dividend = UseFixed(instr->left(), eax);
LOperand* divisor = UseRegister(instr->right());
LDivI* flooring_div = new(zone()) LDivI(dividend, divisor, temp);
return AssignEnvironment(DefineFixed(flooring_div, eax));
}
LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
LOperand* dividend = UseRegisterAtStart(instr->left());
int32_t divisor = instr->right()->GetInteger32Constant();
LInstruction* result =
DefineSameAsFirst(new(zone()) LFlooringDivByPowerOf2I(dividend, divisor));
bool can_deopt =
(instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
(instr->left()->RangeCanInclude(kMinInt) && divisor == -1);
return can_deopt ? AssignEnvironment(result) : result;
}
ASSERT(right->IsConstant() && HConstant::cast(right)->HasInteger32Value());
LOperand* divisor = chunk_->DefineConstantOperand(HConstant::cast(right));
int32_t divisor_si = HConstant::cast(right)->Integer32Value();
if (divisor_si == 0) {
LOperand* dividend = UseRegister(instr->left());
return AssignEnvironment(DefineAsRegister(
new(zone()) LMathFloorOfDiv(dividend, divisor, NULL)));
} else if (IsPowerOf2(abs(divisor_si))) {
// use dividend as temp if divisor < 0 && divisor != -1
LOperand* dividend = divisor_si < -1 ? UseTempRegister(instr->left()) :
UseRegisterAtStart(instr->left());
LInstruction* result = DefineAsRegister(
new(zone()) LMathFloorOfDiv(dividend, divisor, NULL));
return divisor_si < 0 ? AssignEnvironment(result) : result;
LInstruction* LChunkBuilder::DoFlooringDivByConstI(HMathFloorOfDiv* instr) {
LOperand* dividend = UseFixed(instr->left(), eax);
int32_t divisor = instr->right()->GetInteger32Constant();
LOperand* temp = TempRegister();
LInstruction* result =
DefineFixed(
new(zone()) LFlooringDivByConstI(dividend, divisor, temp), edx);
bool can_deopt = divisor <= 0;
return can_deopt ? AssignEnvironment(result) : result;
}
LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
if (instr->RightIsPowerOf2()) {
return DoFlooringDivByPowerOf2I(instr);
} else if (instr->right()->IsConstant()) {
return DoFlooringDivByConstI(instr);
} else {
// needs edx:eax, plus a temp
LOperand* dividend = UseFixed(instr->left(), eax);
LOperand* temp = TempRegister();
LInstruction* result = DefineFixed(
new(zone()) LMathFloorOfDiv(dividend, divisor, temp), edx);
return divisor_si < 0 ? AssignEnvironment(result) : result;
return DoDivI(instr);
}
}
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
HValue* left = instr->left();
HValue* right = instr->right();
if (instr->representation().IsSmiOrInteger32()) {
ASSERT(instr->left()->representation().Equals(instr->representation()));
ASSERT(instr->right()->representation().Equals(instr->representation()));
LInstruction* LChunkBuilder::DoModByPowerOf2I(HMod* instr) {
ASSERT(instr->representation().IsSmiOrInteger32());
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 =
DefineSameAsFirst(new(zone()) LModByPowerOf2I(dividend, divisor));
bool can_deopt =
instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
instr->left()->CanBeNegative();
return can_deopt ? AssignEnvironment(result) : result;
}
if (instr->RightIsPowerOf2()) {
ASSERT(!right->CanBeZero());
LModI* mod = new(zone()) LModI(UseRegisterAtStart(left),
UseOrConstant(right),
NULL);
LInstruction* result = DefineSameAsFirst(mod);
return (left->CanBeNegative() &&
instr->CheckFlag(HValue::kBailoutOnMinusZero))
? AssignEnvironment(result)
: result;
return AssignEnvironment(DefineSameAsFirst(mod));
} else {
// The temporary operand is necessary to ensure that right is not
// allocated into edx.
LModI* mod = new(zone()) LModI(UseFixed(left, eax),
UseRegister(right),
FixedTemp(edx));
LInstruction* result = DefineFixed(mod, edx);
return (right->CanBeZero() ||
(left->RangeCanInclude(kMinInt) &&
right->RangeCanInclude(-1) &&
instr->CheckFlag(HValue::kBailoutOnMinusZero)) ||
(left->CanBeNegative() &&
instr->CanBeZero() &&
instr->CheckFlag(HValue::kBailoutOnMinusZero)))
? AssignEnvironment(result)
: result;
}
LInstruction* LChunkBuilder::DoModI(HMod* 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()) LModI(dividend, divisor, temp), edx);
bool can_deopt = (instr->right()->CanBeZero() ||
(instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
instr->left()->RangeCanInclude(kMinInt) &&
instr->right()->RangeCanInclude(-1)) ||
(instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
instr->left()->CanBeNegative() &&
instr->CanBeZero()));
return can_deopt ? AssignEnvironment(result) : result;
}
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
if (instr->representation().IsSmiOrInteger32()) {
return instr->RightIsPowerOf2() ? DoModByPowerOf2I(instr) : DoModI(instr);
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::MOD, instr);
} else {

View File

@ -87,12 +87,15 @@ class LCodeGen;
V(DebugBreak) \
V(DeclareGlobals) \
V(Deoptimize) \
V(DivByPowerOf2I) \
V(DivI) \
V(DoubleToI) \
V(DoubleToSmi) \
V(Drop) \
V(Dummy) \
V(DummyUse) \
V(FlooringDivByConstI) \
V(FlooringDivByPowerOf2I) \
V(ForInCacheArray) \
V(ForInPrepareMap) \
V(FunctionLiteral) \
@ -129,12 +132,12 @@ class LCodeGen;
V(MathClz32) \
V(MathExp) \
V(MathFloor) \
V(MathFloorOfDiv) \
V(MathLog) \
V(MathMinMax) \
V(MathPowHalf) \
V(MathRound) \
V(MathSqrt) \
V(ModByPowerOf2I) \
V(ModI) \
V(MulI) \
V(NumberTagD) \
@ -634,6 +637,24 @@ class LDebugBreak V8_FINAL : public LTemplateInstruction<0, 0, 0> {
};
class LModByPowerOf2I V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
LModByPowerOf2I(LOperand* dividend, int32_t divisor) {
inputs_[0] = dividend;
divisor_ = divisor;
}
LOperand* dividend() { return inputs_[0]; }
int32_t divisor() const { return divisor_; }
DECLARE_CONCRETE_INSTRUCTION(ModByPowerOf2I, "mod-by-power-of-2-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) {
@ -651,6 +672,24 @@ class LModI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
};
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 LDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
public:
LDivI(LOperand* left, LOperand* right, LOperand* temp) {
@ -661,30 +700,51 @@ class LDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
LOperand* temp() { return temps_[0]; }
bool is_flooring() { return hydrogen_value()->IsMathFloorOfDiv(); }
DECLARE_CONCRETE_INSTRUCTION(DivI, "div-i")
DECLARE_HYDROGEN_ACCESSOR(Div)
DECLARE_HYDROGEN_ACCESSOR(BinaryOperation)
};
class LMathFloorOfDiv V8_FINAL : public LTemplateInstruction<1, 2, 1> {
class LFlooringDivByPowerOf2I V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
LMathFloorOfDiv(LOperand* left,
LOperand* right,
LOperand* temp = NULL) {
inputs_[0] = left;
inputs_[1] = right;
LFlooringDivByPowerOf2I(LOperand* dividend, int32_t divisor) {
inputs_[0] = dividend;
divisor_ = divisor;
}
LOperand* dividend() { return inputs_[0]; }
int32_t divisor() const { return divisor_; }
DECLARE_CONCRETE_INSTRUCTION(FlooringDivByPowerOf2I,
"flooring-div-by-power-of-2-i")
DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
private:
int32_t divisor_;
};
class LFlooringDivByConstI V8_FINAL : public LTemplateInstruction<1, 1, 1> {
public:
LFlooringDivByConstI(LOperand* dividend, int32_t divisor, LOperand* temp) {
inputs_[0] = dividend;
divisor_ = divisor;
temps_[0] = temp;
}
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
LOperand* dividend() { return inputs_[0]; }
int32_t divisor() const { return divisor_; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv, "math-floor-of-div")
DECLARE_CONCRETE_INSTRUCTION(FlooringDivByConstI, "flooring-div-by-const-i")
DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
private:
int32_t divisor_;
};
@ -2630,6 +2690,12 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
LInstruction* DoMathSqrt(HUnaryMathOperation* instr);
LInstruction* DoMathPowHalf(HUnaryMathOperation* instr);
LInstruction* DoMathClz32(HUnaryMathOperation* instr);
LInstruction* DoDivByPowerOf2I(HDiv* instr);
LInstruction* DoDivI(HBinaryOperation* instr);
LInstruction* DoModByPowerOf2I(HMod* instr);
LInstruction* DoModI(HMod* instr);
LInstruction* DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr);
LInstruction* DoFlooringDivByConstI(HMathFloorOfDiv* instr);
private:
enum Status {

View File

@ -283,6 +283,12 @@ inline int StrLength(const char* string) {
}
// TODO(svenpanne) Clean up the whole power-of-2 mess.
inline int32_t WhichPowerOf2Abs(int32_t x) {
return (x == kMinInt) ? 31 : WhichPowerOf2(Abs(x));
}
// ----------------------------------------------------------------------------
// BitField is a help template for encoding and decode bitfield with
// unsigned content.

View File

@ -983,264 +983,275 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
}
void LCodeGen::DoModI(LModI* instr) {
void LCodeGen::DoModByPowerOf2I(LModByPowerOf2I* instr) {
Register dividend = ToRegister(instr->dividend());
int32_t divisor = instr->divisor();
ASSERT(dividend.is(ToRegister(instr->result())));
// Theoretically, a variation of the branch-free code for integer division by
// a power of 2 (calculating the remainder via an additional multiplication
// (which gets simplified to an 'and') and subtraction) should be faster, and
// this is exactly what GCC and clang emit. Nevertheless, benchmarks seem to
// indicate that positive dividends are heavily favored, so the branching
// version performs better.
HMod* hmod = instr->hydrogen();
HValue* left = hmod->left();
HValue* right = hmod->right();
if (hmod->RightIsPowerOf2()) {
// TODO(svenpanne) We should really do the strength reduction on the
// Hydrogen level.
Register left_reg = ToRegister(instr->left());
ASSERT(left_reg.is(ToRegister(instr->result())));
// Note: The code below even works when right contains kMinInt.
int32_t divisor = Abs(right->GetInteger32Constant());
Label left_is_not_negative, done;
if (left->CanBeNegative()) {
__ testl(left_reg, left_reg);
__ j(not_sign, &left_is_not_negative, Label::kNear);
__ negl(left_reg);
__ andl(left_reg, Immediate(divisor - 1));
__ negl(left_reg);
if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(zero, instr->environment());
}
__ jmp(&done, Label::kNear);
}
__ bind(&left_is_not_negative);
__ andl(left_reg, Immediate(divisor - 1));
__ bind(&done);
} else {
Register left_reg = ToRegister(instr->left());
ASSERT(left_reg.is(rax));
Register right_reg = ToRegister(instr->right());
ASSERT(!right_reg.is(rax));
ASSERT(!right_reg.is(rdx));
Register result_reg = ToRegister(instr->result());
ASSERT(result_reg.is(rdx));
Label done;
// Check for x % 0, idiv would signal a divide error. We have to
// deopt in this case because we can't return a NaN.
if (right->CanBeZero()) {
__ testl(right_reg, right_reg);
int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
Label dividend_is_not_negative, done;
if (hmod->left()->CanBeNegative()) {
__ testl(dividend, dividend);
__ j(not_sign, &dividend_is_not_negative, Label::kNear);
// Note that this is correct even for kMinInt operands.
__ negl(dividend);
__ andl(dividend, Immediate(mask));
__ negl(dividend);
if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(zero, instr->environment());
}
// Check for kMinInt % -1, idiv would signal a divide error. We
// have to deopt if we care about -0, because we can't return that.
if (left->RangeCanInclude(kMinInt) && right->RangeCanInclude(-1)) {
Label no_overflow_possible;
__ cmpl(left_reg, Immediate(kMinInt));
__ j(not_zero, &no_overflow_possible, Label::kNear);
__ cmpl(right_reg, Immediate(-1));
if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(equal, instr->environment());
} else {
__ j(not_equal, &no_overflow_possible, Label::kNear);
__ Set(result_reg, 0);
__ jmp(&done, Label::kNear);
}
__ bind(&no_overflow_possible);
}
// Sign extend dividend in eax into edx:eax, since we are using only the low
// 32 bits of the values.
__ cdq();
// If we care about -0, test if the dividend is <0 and the result is 0.
if (left->CanBeNegative() &&
hmod->CanBeZero() &&
hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
Label positive_left;
__ testl(left_reg, left_reg);
__ j(not_sign, &positive_left, Label::kNear);
__ idivl(right_reg);
__ testl(result_reg, result_reg);
DeoptimizeIf(zero, instr->environment());
__ jmp(&done, Label::kNear);
__ bind(&positive_left);
}
__ idivl(right_reg);
__ bind(&done);
__ jmp(&done, Label::kNear);
}
__ bind(&dividend_is_not_negative);
__ andl(dividend, Immediate(mask));
__ bind(&done);
}
void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
ASSERT(instr->right()->IsConstantOperand());
void LCodeGen::DoModI(LModI* instr) {
if (instr->hydrogen()->RightIsPowerOf2()) {
return DoModByPowerOf2I(reinterpret_cast<LModByPowerOf2I*>(instr));
}
HMod* hmod = instr->hydrogen();
HValue* left = hmod->left();
HValue* right = hmod->right();
const Register dividend = ToRegister(instr->left());
int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right()));
const Register result = ToRegister(instr->result());
Register left_reg = ToRegister(instr->left());
ASSERT(left_reg.is(rax));
Register right_reg = ToRegister(instr->right());
ASSERT(!right_reg.is(rax));
ASSERT(!right_reg.is(rdx));
Register result_reg = ToRegister(instr->result());
ASSERT(result_reg.is(rdx));
switch (divisor) {
case 0:
Label done;
// Check for x % 0, idiv would signal a divide error. We have to
// deopt in this case because we can't return a NaN.
if (right->CanBeZero()) {
__ testl(right_reg, right_reg);
DeoptimizeIf(zero, instr->environment());
}
// Check for kMinInt % -1, idiv would signal a divide error. We
// have to deopt if we care about -0, because we can't return that.
if (left->RangeCanInclude(kMinInt) && right->RangeCanInclude(-1)) {
Label no_overflow_possible;
__ cmpl(left_reg, Immediate(kMinInt));
__ j(not_zero, &no_overflow_possible, Label::kNear);
__ cmpl(right_reg, Immediate(-1));
if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(equal, instr->environment());
} else {
__ j(not_equal, &no_overflow_possible, Label::kNear);
__ Set(result_reg, 0);
__ jmp(&done, Label::kNear);
}
__ bind(&no_overflow_possible);
}
// Sign extend dividend in eax into edx:eax, since we are using only the low
// 32 bits of the values.
__ cdq();
// If we care about -0, test if the dividend is <0 and the result is 0.
if (left->CanBeNegative() &&
hmod->CanBeZero() &&
hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
Label positive_left;
__ testl(left_reg, left_reg);
__ j(not_sign, &positive_left, Label::kNear);
__ idivl(right_reg);
__ testl(result_reg, result_reg);
DeoptimizeIf(zero, instr->environment());
__ jmp(&done, Label::kNear);
__ bind(&positive_left);
}
__ idivl(right_reg);
__ bind(&done);
}
void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
Register dividend = ToRegister(instr->dividend());
int32_t divisor = instr->divisor();
ASSERT(dividend.is(ToRegister(instr->result())));
// If the divisor is positive, things are easy: There can be no deopts and we
// can simply do an arithmetic right shift.
if (divisor == 1) return;
int32_t shift = WhichPowerOf2Abs(divisor);
if (divisor > 1) {
__ sarl(dividend, Immediate(shift));
return;
}
// If the divisor is negative, we have to negate and handle edge cases.
Label not_kmin_int, done;
__ negl(dividend);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(zero, instr->environment());
}
if (instr->hydrogen()->left()->RangeCanInclude(kMinInt)) {
// Note that we could emit branch-free code, but that would need one more
// register.
__ j(no_overflow, &not_kmin_int, Label::kNear);
if (divisor == -1) {
DeoptimizeIf(no_condition, instr->environment());
} else {
__ movl(dividend, Immediate(kMinInt / divisor));
__ jmp(&done, Label::kNear);
}
}
__ bind(&not_kmin_int);
__ sarl(dividend, Immediate(shift));
__ bind(&done);
}
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());
if (divisor == 0) {
DeoptimizeIf(no_condition, instr->environment());
return;
case 1:
if (!result.is(dividend)) {
__ movl(result, dividend);
}
return;
case -1:
if (!result.is(dividend)) {
__ movl(result, dividend);
}
__ negl(result);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(zero, instr->environment());
}
if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
DeoptimizeIf(overflow, instr->environment());
}
return;
}
// Find b which: 2^b < divisor_abs < 2^(b+1).
uint32_t divisor_abs = abs(divisor);
if (IsPowerOf2(divisor_abs)) {
int32_t power = WhichPowerOf2(divisor_abs);
if (divisor < 0) {
__ movsxlq(result, dividend);
__ neg(result);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(zero, instr->environment());
}
__ sar(result, Immediate(power));
} else {
if (!result.is(dividend)) {
__ movl(result, dividend);
}
__ sarl(result, Immediate(power));
}
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 {
Register reg1 = ToRegister(instr->temp());
Register reg2 = ToRegister(instr->result());
// Find b which: 2^b < divisor_abs < 2^(b+1).
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(reg1, dividend);
if (divisor < 0 &&
instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
__ neg(reg1);
DeoptimizeIf(zero, instr->environment());
}
__ Set(reg2, multiplier);
// Result just fit in r64, because it's int32 * uint32.
__ imul(reg2, reg1);
__ addq(reg2, Immediate(1 << 30));
__ sar(reg2, Immediate(shift));
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);
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));
}
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) &&
hdiv->left()->RangeCanInclude(0) && divisor < 0) {
__ testl(dividend, dividend);
DeoptimizeIf(zero, instr->environment());
}
// Check for (kMinInt / -1).
if (hdiv->CheckFlag(HValue::kCanOverflow) &&
hdiv->left()->RangeCanInclude(kMinInt) && divisor == -1) {
__ cmpl(dividend, Immediate(kMinInt));
DeoptimizeIf(zero, instr->environment());
}
// 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);
__ testl(dividend, Immediate(mask));
DeoptimizeIf(not_zero, instr->environment());
}
__ Move(result, dividend);
int32_t shift = WhichPowerOf2Abs(divisor);
if (shift > 0) {
// The arithmetic shift is always OK, the 'if' is an optimization only.
if (shift > 1) __ sarl(result, Immediate(31));
__ shrl(result, Immediate(32 - shift));
__ addl(result, dividend);
__ sarl(result, Immediate(shift));
}
if (divisor < 0) __ negl(result);
}
void LCodeGen::DoDivI(LDivI* instr) {
if (!instr->is_flooring() && instr->hydrogen()->RightIsPowerOf2()) {
Register dividend = ToRegister(instr->left());
HDiv* hdiv = instr->hydrogen();
int32_t divisor = hdiv->right()->GetInteger32Constant();
Register result = ToRegister(instr->result());
ASSERT(!result.is(dividend));
// Check for (0 / -x) that will produce negative zero.
if (hdiv->left()->RangeCanInclude(0) && divisor < 0 &&
hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
__ testl(dividend, dividend);
DeoptimizeIf(zero, instr->environment());
}
// Check for (kMinInt / -1).
if (hdiv->left()->RangeCanInclude(kMinInt) && divisor == -1 &&
hdiv->CheckFlag(HValue::kCanOverflow)) {
__ cmpl(dividend, Immediate(kMinInt));
DeoptimizeIf(zero, instr->environment());
}
// Deoptimize if remainder will not be 0.
if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
__ testl(dividend, Immediate(Abs(divisor) - 1));
DeoptimizeIf(not_zero, instr->environment());
}
__ Move(result, dividend);
int32_t shift = WhichPowerOf2(Abs(divisor));
if (shift > 0) {
// The arithmetic shift is always OK, the 'if' is an optimization only.
if (shift > 1) __ sarl(result, Immediate(31));
__ shrl(result, Immediate(32 - shift));
__ addl(result, dividend);
__ sarl(result, Immediate(shift));
}
if (divisor < 0) __ negl(result);
return;
}
LOperand* right = instr->right();
ASSERT(ToRegister(instr->result()).is(rax));
ASSERT(ToRegister(instr->left()).is(rax));
ASSERT(!ToRegister(instr->right()).is(rax));
ASSERT(!ToRegister(instr->right()).is(rdx));
Register left_reg = rax;
Register dividend = ToRegister(instr->left());
Register divisor = ToRegister(instr->right());
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.
Register right_reg = ToRegister(right);
if (instr->hydrogen_value()->CheckFlag(HValue::kCanBeDivByZero)) {
__ testl(right_reg, right_reg);
HBinaryOperation* hdiv = instr->hydrogen();
if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
__ testl(divisor, divisor);
DeoptimizeIf(zero, instr->environment());
}
// Check for (0 / -x) that will produce negative zero.
if (instr->hydrogen_value()->CheckFlag(HValue::kBailoutOnMinusZero)) {
Label left_not_zero;
__ testl(left_reg, left_reg);
__ j(not_zero, &left_not_zero, Label::kNear);
__ testl(right_reg, right_reg);
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(&left_not_zero);
__ bind(&dividend_not_zero);
}
// Check for (kMinInt / -1).
if (instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)) {
Label left_not_min_int;
__ cmpl(left_reg, Immediate(kMinInt));
__ j(not_zero, &left_not_min_int, Label::kNear);
__ cmpl(right_reg, Immediate(-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(&left_not_min_int);
__ bind(&dividend_not_min_int);
}
// Sign extend to rdx.
// Sign extend to rdx (= remainder).
__ cdq();
__ idivl(right_reg);
__ idivl(divisor);
if (instr->is_flooring()) {
Label done;
__ testl(rdx, rdx);
__ testl(remainder, remainder);
__ j(zero, &done, Label::kNear);
__ xorl(rdx, right_reg);
__ sarl(rdx, Immediate(31));
__ addl(rax, rdx);
__ xorl(remainder, divisor);
__ sarl(remainder, Immediate(31));
__ addl(result, remainder);
__ bind(&done);
} else if (!instr->hydrogen()->CheckFlag(
HInstruction::kAllUsesTruncatingToInt32)) {
// Deoptimize if remainder is not 0.
__ testl(rdx, rdx);
__ testl(remainder, remainder);
DeoptimizeIf(not_zero, instr->environment());
}
}

View File

@ -1242,24 +1242,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));
bool can_deopt =
(instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
instr->left()->RangeCanInclude(0) && divisor < 0) ||
(instr->CheckFlag(HValue::kCanOverflow) &&
instr->left()->RangeCanInclude(kMinInt) && divisor == -1) ||
(!instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
divisor != 1 && divisor != -1);
return can_deopt ? AssignEnvironment(result) : result;
}
LInstruction* LChunkBuilder::DoDivI(HBinaryOperation* 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()) LDivI(dividend, divisor, temp), rax);
return AssignEnvironment(result);
}
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
if (instr->representation().IsSmiOrInteger32()) {
ASSERT(instr->left()->representation().Equals(instr->representation()));
ASSERT(instr->right()->representation().Equals(instr->representation()));
if (instr->RightIsPowerOf2()) {
ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
LOperand* value = UseRegister(instr->left());
LDivI* div =
new(zone()) LDivI(value, UseOrConstant(instr->right()), NULL);
return AssignEnvironment(DefineAsRegister(div));
}
// The temporary operand is necessary to ensure that right is not allocated
// into rdx.
LOperand* temp = FixedTemp(rdx);
LOperand* dividend = UseFixed(instr->left(), rax);
LOperand* divisor = UseRegister(instr->right());
LDivI* result = new(zone()) LDivI(dividend, divisor, temp);
return AssignEnvironment(DefineFixed(result, rax));
return instr->RightIsPowerOf2() ? DoDivByPowerOf2I(instr) : DoDivI(instr);
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::DIV, instr);
} else {
@ -1268,75 +1285,79 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
}
LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
HValue* right = instr->right();
if (!right->IsConstant()) {
ASSERT(right->representation().IsInteger32());
// The temporary operand is necessary to ensure that right is not allocated
// into rdx.
LOperand* temp = FixedTemp(rdx);
LOperand* dividend = UseFixed(instr->left(), rax);
LOperand* divisor = UseRegister(instr->right());
LDivI* flooring_div = new(zone()) LDivI(dividend, divisor, temp);
return AssignEnvironment(DefineFixed(flooring_div, rax));
}
LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
LOperand* dividend = UseRegisterAtStart(instr->left());
int32_t divisor = instr->right()->GetInteger32Constant();
LInstruction* result =
DefineSameAsFirst(new(zone()) LFlooringDivByPowerOf2I(dividend, divisor));
bool can_deopt =
(instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
(instr->left()->RangeCanInclude(kMinInt) && divisor == -1);
return can_deopt ? AssignEnvironment(result) : result;
}
ASSERT(right->IsConstant() && HConstant::cast(right)->HasInteger32Value());
LOperand* divisor = chunk_->DefineConstantOperand(HConstant::cast(right));
int32_t divisor_si = HConstant::cast(right)->Integer32Value();
if (divisor_si == 0) {
LOperand* dividend = UseRegister(instr->left());
return AssignEnvironment(DefineAsRegister(
new(zone()) LMathFloorOfDiv(dividend, divisor, NULL)));
} else if (IsPowerOf2(abs(divisor_si))) {
LOperand* dividend = UseRegisterAtStart(instr->left());
LInstruction* result = DefineAsRegister(
new(zone()) LMathFloorOfDiv(dividend, divisor, NULL));
return divisor_si < 0 ? AssignEnvironment(result) : result;
LInstruction* LChunkBuilder::DoFlooringDivByConstI(HMathFloorOfDiv* instr) {
LOperand* dividend = UseRegisterAtStart(instr->left());
int32_t divisor = instr->right()->GetInteger32Constant();
LOperand* temp = TempRegister();
LInstruction* result =
DefineAsRegister(
new(zone()) LFlooringDivByConstI(dividend, divisor, temp));
bool can_deopt = divisor <= 0;
return can_deopt ? AssignEnvironment(result) : result;
}
LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
if (instr->RightIsPowerOf2()) {
return DoFlooringDivByPowerOf2I(instr);
} else if (instr->right()->IsConstant()) {
return DoFlooringDivByConstI(instr);
} else {
// use two r64
LOperand* dividend = UseRegisterAtStart(instr->left());
LOperand* temp = TempRegister();
LInstruction* result = DefineAsRegister(
new(zone()) LMathFloorOfDiv(dividend, divisor, temp));
return divisor_si < 0 ? AssignEnvironment(result) : result;
return DoDivI(instr);
}
}
LInstruction* LChunkBuilder::DoModByPowerOf2I(HMod* instr) {
ASSERT(instr->representation().IsSmiOrInteger32());
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 =
DefineSameAsFirst(new(zone()) LModByPowerOf2I(dividend, divisor));
bool can_deopt =
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()));
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()) LModI(dividend, divisor, temp), rdx);
bool can_deopt = (instr->right()->CanBeZero() ||
(instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
instr->left()->RangeCanInclude(kMinInt) &&
instr->right()->RangeCanInclude(-1)) ||
(instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
instr->left()->CanBeNegative() &&
instr->CanBeZero()));
return can_deopt ? AssignEnvironment(result) : result;
}
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
HValue* left = instr->left();
HValue* right = instr->right();
if (instr->representation().IsSmiOrInteger32()) {
ASSERT(left->representation().Equals(instr->representation()));
ASSERT(right->representation().Equals(instr->representation()));
if (instr->RightIsPowerOf2()) {
ASSERT(!right->CanBeZero());
LModI* mod = new(zone()) LModI(UseRegisterAtStart(left),
UseOrConstant(right),
NULL);
LInstruction* result = DefineSameAsFirst(mod);
return (left->CanBeNegative() &&
instr->CheckFlag(HValue::kBailoutOnMinusZero))
? AssignEnvironment(result)
: result;
} else {
// The temporary operand is necessary to ensure that right is not
// allocated into edx.
LModI* mod = new(zone()) LModI(UseFixed(left, rax),
UseRegister(right),
FixedTemp(rdx));
LInstruction* result = DefineFixed(mod, rdx);
return (right->CanBeZero() ||
(left->RangeCanInclude(kMinInt) &&
right->RangeCanInclude(-1) &&
instr->CheckFlag(HValue::kBailoutOnMinusZero)) ||
(left->CanBeNegative() &&
instr->CanBeZero() &&
instr->CheckFlag(HValue::kBailoutOnMinusZero)))
? AssignEnvironment(result)
: result;
}
return instr->RightIsPowerOf2() ? DoModByPowerOf2I(instr) : DoModI(instr);
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::MOD, instr);
} else {

View File

@ -85,12 +85,15 @@ class LCodeGen;
V(DebugBreak) \
V(DeclareGlobals) \
V(Deoptimize) \
V(DivByPowerOf2I) \
V(DivI) \
V(DoubleToI) \
V(DoubleToSmi) \
V(Drop) \
V(DummyUse) \
V(Dummy) \
V(FlooringDivByConstI) \
V(FlooringDivByPowerOf2I) \
V(ForInCacheArray) \
V(ForInPrepareMap) \
V(FunctionLiteral) \
@ -127,12 +130,12 @@ class LCodeGen;
V(MathClz32) \
V(MathExp) \
V(MathFloor) \
V(MathFloorOfDiv) \
V(MathLog) \
V(MathMinMax) \
V(MathPowHalf) \
V(MathRound) \
V(MathSqrt) \
V(ModByPowerOf2I) \
V(ModI) \
V(MulI) \
V(NumberTagD) \
@ -615,6 +618,24 @@ class LArgumentsElements V8_FINAL : public LTemplateInstruction<1, 0, 0> {
};
class LModByPowerOf2I V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
LModByPowerOf2I(LOperand* dividend, int32_t divisor) {
inputs_[0] = dividend;
divisor_ = divisor;
}
LOperand* dividend() { return inputs_[0]; }
int32_t divisor() const { return divisor_; }
DECLARE_CONCRETE_INSTRUCTION(ModByPowerOf2I, "mod-by-power-of-2-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) {
@ -632,6 +653,24 @@ class LModI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
};
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 LDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
public:
LDivI(LOperand* left, LOperand* right, LOperand* temp) {
@ -647,26 +686,46 @@ class LDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
bool is_flooring() { return hydrogen_value()->IsMathFloorOfDiv(); }
DECLARE_CONCRETE_INSTRUCTION(DivI, "div-i")
DECLARE_HYDROGEN_ACCESSOR(Div)
DECLARE_HYDROGEN_ACCESSOR(BinaryOperation)
};
class LMathFloorOfDiv V8_FINAL : public LTemplateInstruction<1, 2, 1> {
class LFlooringDivByPowerOf2I V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
LMathFloorOfDiv(LOperand* left,
LOperand* right,
LOperand* temp = NULL) {
inputs_[0] = left;
inputs_[1] = right;
LFlooringDivByPowerOf2I(LOperand* dividend, int32_t divisor) {
inputs_[0] = dividend;
divisor_ = divisor;
}
LOperand* dividend() { return inputs_[0]; }
int32_t divisor() const { return divisor_; }
DECLARE_CONCRETE_INSTRUCTION(FlooringDivByPowerOf2I,
"flooring-div-by-power-of-2-i")
DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
private:
int32_t divisor_;
};
class LFlooringDivByConstI V8_FINAL : public LTemplateInstruction<1, 1, 1> {
public:
LFlooringDivByConstI(LOperand* dividend, int32_t divisor, LOperand* temp) {
inputs_[0] = dividend;
divisor_ = divisor;
temps_[0] = temp;
}
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
LOperand* dividend() { return inputs_[0]; }
int32_t divisor() const { return divisor_; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv, "math-floor-of-div")
DECLARE_CONCRETE_INSTRUCTION(FlooringDivByConstI, "flooring-div-by-const-i")
DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
private:
int32_t divisor_;
};
@ -2545,6 +2604,12 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
LInstruction* DoMathSqrt(HUnaryMathOperation* instr);
LInstruction* DoMathPowHalf(HUnaryMathOperation* instr);
LInstruction* DoMathClz32(HUnaryMathOperation* instr);
LInstruction* DoDivByPowerOf2I(HDiv* instr);
LInstruction* DoDivI(HBinaryOperation* instr);
LInstruction* DoModByPowerOf2I(HMod* instr);
LInstruction* DoModI(HMod* instr);
LInstruction* DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr);
LInstruction* DoFlooringDivByConstI(HMathFloorOfDiv* instr);
private:
enum Status {