Index: src/mips/lithium-codegen-mips.cc |
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc |
index 74b53155d3c4be94c713d172fc9bdac3ed57bec5..c2075a4e680faa9dbcc9f5b9c41e9093020435e9 100644 |
--- a/src/mips/lithium-codegen-mips.cc |
+++ b/src/mips/lithium-codegen-mips.cc |
@@ -1060,68 +1060,75 @@ 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()) { |
- const Register left_reg = ToRegister(instr->left()); |
- const Register result_reg = ToRegister(instr->result()); |
+ int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1); |
+ Label dividend_is_not_negative, done; |
+ if (hmod->left()->CanBeNegative()) { |
+ __ Branch(÷nd_is_not_negative, ge, dividend, Operand(zero_reg)); |
// 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()) { |
- __ Branch(left_reg.is(result_reg) ? PROTECT : USE_DELAY_SLOT, |
- &left_is_not_negative, ge, left_reg, Operand(zero_reg)); |
- __ subu(result_reg, zero_reg, left_reg); |
- __ And(result_reg, result_reg, divisor - 1); |
- if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { |
- DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg)); |
- } |
- __ Branch(USE_DELAY_SLOT, &done); |
- __ subu(result_reg, zero_reg, result_reg); |
+ __ subu(dividend, zero_reg, dividend); |
+ __ And(dividend, dividend, Operand(mask)); |
+ if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { |
+ DeoptimizeIf(eq, instr->environment(), dividend, Operand(zero_reg)); |
} |
+ __ Branch(USE_DELAY_SLOT, &done); |
+ __ subu(dividend, zero_reg, dividend); |
+ } |
- __ bind(&left_is_not_negative); |
- __ And(result_reg, left_reg, divisor - 1); |
- __ bind(&done); |
- } else { |
- const Register scratch = scratch0(); |
- const Register left_reg = ToRegister(instr->left()); |
- const Register result_reg = ToRegister(instr->result()); |
+ __ bind(÷nd_is_not_negative); |
+ __ And(dividend, dividend, Operand(mask)); |
+ __ bind(&done); |
+} |
- // div runs in the background while we check for special cases. |
- Register right_reg = EmitLoadRegister(instr->right(), scratch); |
- __ div(left_reg, right_reg); |
- Label done; |
- // Check for x % 0, we have to deopt in this case because we can't return a |
- // NaN. |
- if (right->CanBeZero()) { |
- DeoptimizeIf(eq, instr->environment(), right_reg, Operand(zero_reg)); |
- } |
+void LCodeGen::DoModI(LModI* instr) { |
+ HMod* hmod = instr->hydrogen(); |
+ HValue* left = hmod->left(); |
+ HValue* right = hmod->right(); |
+ const Register left_reg = ToRegister(instr->left()); |
+ const Register right_reg = ToRegister(instr->right()); |
+ const Register result_reg = ToRegister(instr->result()); |
- // Check for kMinInt % -1, we have to deopt if we care about -0, because we |
- // can't return that. |
- if (left->RangeCanInclude(kMinInt) && right->RangeCanInclude(-1)) { |
- Label left_not_min_int; |
- __ Branch(&left_not_min_int, ne, left_reg, Operand(kMinInt)); |
- // TODO(svenpanne) Don't deopt when we don't care about -0. |
- DeoptimizeIf(eq, instr->environment(), right_reg, Operand(-1)); |
- __ bind(&left_not_min_int); |
- } |
+ // div runs in the background while we check for special cases. |
+ __ div(left_reg, right_reg); |
- // TODO(svenpanne) Only emit the test/deopt if we have to. |
- __ Branch(USE_DELAY_SLOT, &done, ge, left_reg, Operand(zero_reg)); |
- __ mfhi(result_reg); |
+ Label done; |
+ // Check for x % 0, we have to deopt in this case because we can't return a |
+ // NaN. |
+ if (right->CanBeZero()) { |
+ DeoptimizeIf(eq, instr->environment(), right_reg, Operand(zero_reg)); |
+ } |
- if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { |
- DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg)); |
- } |
- __ bind(&done); |
+ // Check for kMinInt % -1, we have to deopt if we care about -0, because we |
+ // can't return that. |
+ if (left->RangeCanInclude(kMinInt) && right->RangeCanInclude(-1)) { |
+ Label left_not_min_int; |
+ __ Branch(&left_not_min_int, ne, left_reg, Operand(kMinInt)); |
+ // TODO(svenpanne) Don't deopt when we don't care about -0. |
+ DeoptimizeIf(eq, instr->environment(), right_reg, Operand(-1)); |
+ __ bind(&left_not_min_int); |
+ } |
+ |
+ // TODO(svenpanne) Only emit the test/deopt if we have to. |
+ __ Branch(USE_DELAY_SLOT, &done, ge, left_reg, Operand(zero_reg)); |
+ __ mfhi(result_reg); |
+ |
+ if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { |
+ DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg)); |
} |
+ __ bind(&done); |
} |
@@ -1277,67 +1284,74 @@ void LCodeGen::DoMultiplyAddD(LMultiplyAddD* instr) { |
} |
+void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) { |
+ Register left = ToRegister(instr->dividend()); |
+ Register remainder = ToRegister(instr->temp()); |
+ Register scratch = scratch0(); |
+ Register result = ToRegister(instr->result()); |
+ |
+ ASSERT(instr->divisor()->IsConstantOperand()); |
+ Label done; |
+ int32_t divisor = ToInteger32(LConstantOperand::cast(instr->divisor())); |
+ if (divisor < 0) { |
+ DeoptimizeIf(eq, instr->environment(), left, Operand(zero_reg)); |
+ } |
+ EmitSignedIntegerDivisionByConstant(result, |
+ left, |
+ divisor, |
+ remainder, |
+ scratch, |
+ instr->environment()); |
+ // We performed a truncating division. Correct the result if necessary. |
+ __ Branch(&done, eq, remainder, Operand(zero_reg), USE_DELAY_SLOT); |
+ __ Xor(scratch , remainder, Operand(divisor)); |
+ __ Branch(&done, ge, scratch, Operand(zero_reg)); |
+ __ Subu(result, result, Operand(1)); |
+ __ bind(&done); |
+} |
+ |
+ |
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(); |
- if (instr->right()->IsConstantOperand()) { |
- Label done; |
- int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right())); |
- if (divisor < 0) { |
- DeoptimizeIf(eq, instr->environment(), left, Operand(zero_reg)); |
- } |
- EmitSignedIntegerDivisionByConstant(result, |
- left, |
- divisor, |
- remainder, |
- scratch, |
- instr->environment()); |
- // We performed a truncating division. Correct the result if necessary. |
- __ Branch(&done, eq, remainder, Operand(zero_reg), USE_DELAY_SLOT); |
- __ Xor(scratch , remainder, Operand(divisor)); |
- __ Branch(&done, ge, scratch, Operand(zero_reg)); |
- __ Subu(result, result, Operand(1)); |
- __ bind(&done); |
- } else { |
- Label done; |
- const Register right = ToRegister(instr->right()); |
+ 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); |
+ // 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 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 (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); |
- } |
+ // 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); |
+ __ 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); |
- } |
+ // 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); |
} |