Commit 15d56ffe authored by plind44@gmail.com's avatar plind44@gmail.com

MIPS: Improve integer multiplication.

Port r16576 (8ce78a4)

TEST=test/mjsunit/lithium/MulI.js
BUG=
R=plind44@gmail.com

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

Patch from Balazs Kilvady <kilvadyb@homejinni.com>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16997 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 112b59ef
...@@ -1403,11 +1403,11 @@ void LCodeGen::DoMulI(LMulI* instr) { ...@@ -1403,11 +1403,11 @@ void LCodeGen::DoMulI(LMulI* instr) {
Register left = ToRegister(instr->left()); Register left = ToRegister(instr->left());
LOperand* right_op = instr->right(); LOperand* right_op = instr->right();
bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
bool bailout_on_minus_zero = bool bailout_on_minus_zero =
instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero); instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
bool overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
if (right_op->IsConstantOperand() && !can_overflow) { if (right_op->IsConstantOperand()) {
int32_t constant = ToInteger32(LConstantOperand::cast(right_op)); int32_t constant = ToInteger32(LConstantOperand::cast(right_op));
if (bailout_on_minus_zero && (constant < 0)) { if (bailout_on_minus_zero && (constant < 0)) {
...@@ -1418,7 +1418,12 @@ void LCodeGen::DoMulI(LMulI* instr) { ...@@ -1418,7 +1418,12 @@ void LCodeGen::DoMulI(LMulI* instr) {
switch (constant) { switch (constant) {
case -1: case -1:
__ Subu(result, zero_reg, left); if (overflow) {
__ SubuAndCheckForOverflow(result, zero_reg, left, scratch);
DeoptimizeIf(lt, instr->environment(), scratch, Operand(zero_reg));
} else {
__ Subu(result, zero_reg, left);
}
break; break;
case 0: case 0:
if (bailout_on_minus_zero) { if (bailout_on_minus_zero) {
...@@ -1439,27 +1444,23 @@ void LCodeGen::DoMulI(LMulI* instr) { ...@@ -1439,27 +1444,23 @@ void LCodeGen::DoMulI(LMulI* instr) {
int32_t mask = constant >> 31; int32_t mask = constant >> 31;
uint32_t constant_abs = (constant + mask) ^ mask; uint32_t constant_abs = (constant + mask) ^ mask;
if (IsPowerOf2(constant_abs) || if (IsPowerOf2(constant_abs)) {
IsPowerOf2(constant_abs - 1) || int32_t shift = WhichPowerOf2(constant_abs);
IsPowerOf2(constant_abs + 1)) { __ sll(result, left, shift);
if (IsPowerOf2(constant_abs)) { // Correct the sign of the result if the constant is negative.
int32_t shift = WhichPowerOf2(constant_abs); if (constant < 0) __ Subu(result, zero_reg, result);
__ sll(result, left, shift); } else if (IsPowerOf2(constant_abs - 1)) {
} else if (IsPowerOf2(constant_abs - 1)) { int32_t shift = WhichPowerOf2(constant_abs - 1);
int32_t shift = WhichPowerOf2(constant_abs - 1); __ sll(scratch, left, shift);
__ sll(scratch, left, shift); __ Addu(result, scratch, left);
__ Addu(result, scratch, left); // Correct the sign of the result if the constant is negative.
} else if (IsPowerOf2(constant_abs + 1)) { if (constant < 0) __ Subu(result, zero_reg, result);
int32_t shift = WhichPowerOf2(constant_abs + 1); } else if (IsPowerOf2(constant_abs + 1)) {
__ sll(scratch, left, shift); int32_t shift = WhichPowerOf2(constant_abs + 1);
__ Subu(result, scratch, left); __ sll(scratch, left, shift);
} __ Subu(result, scratch, left);
// Correct the sign of the result if the constant is negative.
// Correct the sign of the result is the constant is negative. if (constant < 0) __ Subu(result, zero_reg, result);
if (constant < 0) {
__ Subu(result, zero_reg, result);
}
} else { } else {
// Generate standard code. // Generate standard code.
__ li(at, constant); __ li(at, constant);
...@@ -1468,12 +1469,10 @@ void LCodeGen::DoMulI(LMulI* instr) { ...@@ -1468,12 +1469,10 @@ void LCodeGen::DoMulI(LMulI* instr) {
} }
} else { } else {
Register right = EmitLoadRegister(right_op, scratch); ASSERT(right_op->IsRegister());
if (bailout_on_minus_zero) { Register right = ToRegister(right_op);
__ Or(ToRegister(instr->temp()), left, right);
}
if (can_overflow) { if (overflow) {
// hi:lo = left * right. // hi:lo = left * right.
if (instr->hydrogen()->representation().IsSmi()) { if (instr->hydrogen()->representation().IsSmi()) {
__ SmiUntag(result, left); __ SmiUntag(result, left);
...@@ -1497,12 +1496,13 @@ void LCodeGen::DoMulI(LMulI* instr) { ...@@ -1497,12 +1496,13 @@ void LCodeGen::DoMulI(LMulI* instr) {
} }
if (bailout_on_minus_zero) { if (bailout_on_minus_zero) {
// Bail out if the result is supposed to be negative zero.
Label done; Label done;
__ Branch(&done, ne, result, Operand(zero_reg)); __ Xor(at, left, right);
DeoptimizeIf(lt, __ Branch(&done, ge, at, Operand(zero_reg));
// Bail out if the result is minus zero.
DeoptimizeIf(eq,
instr->environment(), instr->environment(),
ToRegister(instr->temp()), result,
Operand(zero_reg)); Operand(zero_reg));
__ bind(&done); __ bind(&done);
} }
......
...@@ -1469,20 +1469,39 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) { ...@@ -1469,20 +1469,39 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) {
if (instr->representation().IsSmiOrInteger32()) { if (instr->representation().IsSmiOrInteger32()) {
ASSERT(instr->left()->representation().Equals(instr->representation())); ASSERT(instr->left()->representation().Equals(instr->representation()));
ASSERT(instr->right()->representation().Equals(instr->representation())); ASSERT(instr->right()->representation().Equals(instr->representation()));
LOperand* left; HValue* left = instr->BetterLeftOperand();
LOperand* right = UseOrConstant(instr->BetterRightOperand()); HValue* right = instr->BetterRightOperand();
LOperand* temp = NULL; LOperand* left_op;
if (instr->CheckFlag(HValue::kBailoutOnMinusZero) && LOperand* right_op;
(instr->CheckFlag(HValue::kCanOverflow) || bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
!right->IsConstantOperand())) { bool bailout_on_minus_zero = instr->CheckFlag(HValue::kBailoutOnMinusZero);
left = UseRegister(instr->BetterLeftOperand());
temp = TempRegister(); if (right->IsConstant()) {
HConstant* constant = HConstant::cast(right);
int32_t constant_value = constant->Integer32Value();
// Constants -1, 0 and 1 can be optimized if the result can overflow.
// For other constants, it can be optimized only without overflow.
if (!can_overflow || ((constant_value >= -1) && (constant_value <= 1))) {
left_op = UseRegisterAtStart(left);
right_op = UseConstant(right);
} else {
if (bailout_on_minus_zero) {
left_op = UseRegister(left);
} else {
left_op = UseRegisterAtStart(left);
}
right_op = UseRegister(right);
}
} else { } else {
left = UseRegisterAtStart(instr->BetterLeftOperand()); if (bailout_on_minus_zero) {
left_op = UseRegister(left);
} else {
left_op = UseRegisterAtStart(left);
}
right_op = UseRegister(right);
} }
LMulI* mul = new(zone()) LMulI(left, right, temp); LMulI* mul = new(zone()) LMulI(left_op, right_op);
if (instr->CheckFlag(HValue::kCanOverflow) || if (can_overflow || bailout_on_minus_zero) {
instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
AssignEnvironment(mul); AssignEnvironment(mul);
} }
return DefineAsRegister(mul); return DefineAsRegister(mul);
......
...@@ -688,17 +688,15 @@ class LMathFloorOfDiv V8_FINAL : public LTemplateInstruction<1, 2, 1> { ...@@ -688,17 +688,15 @@ class LMathFloorOfDiv V8_FINAL : public LTemplateInstruction<1, 2, 1> {
}; };
class LMulI V8_FINAL : public LTemplateInstruction<1, 2, 1> { class LMulI V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public: public:
LMulI(LOperand* left, LOperand* right, LOperand* temp) { LMulI(LOperand* left, LOperand* right) {
inputs_[0] = left; inputs_[0] = left;
inputs_[1] = right; inputs_[1] = right;
temps_[0] = temp;
} }
LOperand* left() { return inputs_[0]; } LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; } LOperand* right() { return inputs_[1]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(MulI, "mul-i") DECLARE_CONCRETE_INSTRUCTION(MulI, "mul-i")
DECLARE_HYDROGEN_ACCESSOR(Mul) DECLARE_HYDROGEN_ACCESSOR(Mul)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment