Index: src/mips/lithium-codegen-mips.cc |
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc |
index 82a340c794895679dc2ad3778f61bba4c4c2d35a..76b9663b3b826f5de1ebf5b8c299aa824122f190 100644 |
--- a/src/mips/lithium-codegen-mips.cc |
+++ b/src/mips/lithium-codegen-mips.cc |
@@ -1132,59 +1132,74 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { |
void LCodeGen::DoModI(LModI* instr) { |
- Register scratch = scratch0(); |
- const Register left = ToRegister(instr->left()); |
- const Register result = ToRegister(instr->result()); |
+ HMod* hmod = instr->hydrogen(); |
+ HValue* left = hmod->left(); |
+ HValue* right = hmod->right(); |
+ if (hmod->HasPowerOf2Divisor()) { |
+ const Register scratch = scratch0(); |
+ const Register left_reg = ToRegister(instr->left()); |
+ ASSERT(!left_reg.is(scratch)); |
+ const Register result_reg = ToRegister(instr->result()); |
+ |
+ // Note: The code below even works when right contains kMinInt. |
+ int32_t divisor = Abs(right->GetInteger32Constant()); |
+ |
+ __ mov(scratch, left_reg); |
+ |
+ Label left_is_not_negative, done; |
+ if (left->CanBeNegative()) { |
+ __ Branch(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); |
+ } |
- Label done; |
+ __ bind(&left_is_not_negative); |
+ __ And(result_reg, scratch, divisor - 1); |
+ __ bind(&done); |
- if (instr->hydrogen()->HasPowerOf2Divisor()) { |
- Register scratch = scratch0(); |
- ASSERT(!left.is(scratch)); |
- __ mov(scratch, left); |
- int32_t p2constant = HConstant::cast( |
- instr->hydrogen()->right())->Integer32Value(); |
- ASSERT(p2constant != 0); |
- // Result always takes the sign of the dividend (left). |
- p2constant = abs(p2constant); |
- |
- Label positive_dividend; |
- __ Branch(USE_DELAY_SLOT, &positive_dividend, ge, left, Operand(zero_reg)); |
- __ subu(result, zero_reg, left); |
- __ And(result, result, p2constant - 1); |
- if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
- DeoptimizeIf(eq, instr->environment(), result, Operand(zero_reg)); |
- } |
- __ Branch(USE_DELAY_SLOT, &done); |
- __ subu(result, zero_reg, result); |
- __ bind(&positive_dividend); |
- __ And(result, scratch, p2constant - 1); |
} else { |
+ // TODO(svenpanne) Add right->has_fixed_right_arg() case. |
+ |
+ const Register scratch = scratch0(); |
+ const Register left_reg = ToRegister(instr->left()); |
+ const Register result_reg = ToRegister(instr->result()); |
+ |
// div runs in the background while we check for special cases. |
- Register right = EmitLoadRegister(instr->right(), scratch); |
- __ div(left, right); |
+ Register right_reg = EmitLoadRegister(instr->right(), scratch); |
+ __ div(left_reg, right_reg); |
- // Check for x % 0. |
- if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) { |
- DeoptimizeIf(eq, instr->environment(), right, Operand(zero_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)); |
} |
- // Check for (kMinInt % -1). |
- if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { |
+ // 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, Operand(kMinInt)); |
- DeoptimizeIf(eq, instr->environment(), right, Operand(-1)); |
+ __ 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); |
} |
- __ Branch(USE_DELAY_SLOT, &done, ge, left, Operand(zero_reg)); |
- __ mfhi(result); |
+ // 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 (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
- DeoptimizeIf(eq, instr->environment(), result, Operand(zero_reg)); |
+ if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { |
+ DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg)); |
} |
+ __ bind(&done); |
} |
- __ bind(&done); |
} |