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