Commit 4a2639e7 authored by sgjesse@chromium.org's avatar sgjesse@chromium.org

Improved modulo operation in lithium as well as bailout on -0.

TEST=none
BUG=none

Patch by Rodolph Perfetta from ARM Ltd.

Review URL: http://codereview.chromium.org/6612017


git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7300 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent c316adfc
...@@ -1345,29 +1345,25 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) { ...@@ -1345,29 +1345,25 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
LInstruction* LChunkBuilder::DoMod(HMod* instr) { LInstruction* LChunkBuilder::DoMod(HMod* instr) {
if (instr->representation().IsInteger32()) { if (instr->representation().IsInteger32()) {
// TODO(1042) The fixed register allocation
// is needed because we call GenericBinaryOpStub from
// the generated code, which requires registers r0
// and r1 to be used. We should remove that
// when we provide a native implementation.
ASSERT(instr->left()->representation().IsInteger32()); ASSERT(instr->left()->representation().IsInteger32());
ASSERT(instr->right()->representation().IsInteger32()); ASSERT(instr->right()->representation().IsInteger32());
LInstruction* result; LModI* mod;
if (instr->HasPowerOf2Divisor()) { if (instr->HasPowerOf2Divisor()) {
ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero)); ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
LOperand* value = UseRegisterAtStart(instr->left()); LOperand* value = UseRegisterAtStart(instr->left());
LModI* mod = new LModI(value, UseOrConstant(instr->right())); mod = new LModI(value, UseOrConstant(instr->right()));
result = DefineSameAsFirst(mod);
result = AssignEnvironment(result);
} else { } else {
LOperand* value = UseFixed(instr->left(), r0); LOperand* dividend = UseRegister(instr->left());
LOperand* divisor = UseFixed(instr->right(), r1); LOperand* divisor = UseRegisterAtStart(instr->right());
result = DefineFixed(new LModI(value, divisor), r0); mod = new LModI(dividend,
result = AssignEnvironment(AssignPointerMap(result)); divisor,
TempRegister(),
FixedTemp(d1),
FixedTemp(d2));
} }
return result; return AssignEnvironment(DefineSameAsFirst(mod));
} else if (instr->representation().IsTagged()) { } else if (instr->representation().IsTagged()) {
return DoArithmeticT(Token::MOD, instr); return DoArithmeticT(Token::MOD, instr);
} else { } else {
......
...@@ -523,11 +523,29 @@ class LArgumentsElements: public LTemplateInstruction<1, 0, 0> { ...@@ -523,11 +523,29 @@ class LArgumentsElements: public LTemplateInstruction<1, 0, 0> {
}; };
class LModI: public LTemplateInstruction<1, 2, 0> { class LModI: public LTemplateInstruction<1, 2, 3> {
public: public:
LModI(LOperand* left, LOperand* right) { // Used when the right hand is a constant power of 2.
LModI(LOperand* left,
LOperand* right) {
inputs_[0] = left; inputs_[0] = left;
inputs_[1] = right; inputs_[1] = right;
temps_[0] = NULL;
temps_[1] = NULL;
temps_[2] = NULL;
}
// Used for the standard case.
LModI(LOperand* left,
LOperand* right,
LOperand* temp1,
LOperand* temp2,
LOperand* temp3) {
inputs_[0] = left;
inputs_[1] = right;
temps_[0] = temp1;
temps_[1] = temp2;
temps_[2] = temp3;
} }
DECLARE_CONCRETE_INSTRUCTION(ModI, "mod-i") DECLARE_CONCRETE_INSTRUCTION(ModI, "mod-i")
......
...@@ -802,7 +802,7 @@ void LCodeGen::DoModI(LModI* instr) { ...@@ -802,7 +802,7 @@ void LCodeGen::DoModI(LModI* instr) {
if (divisor < 0) divisor = -divisor; if (divisor < 0) divisor = -divisor;
Label positive_dividend, done; Label positive_dividend, done;
__ tst(dividend, Operand(dividend)); __ cmp(dividend, Operand(0));
__ b(pl, &positive_dividend); __ b(pl, &positive_dividend);
__ rsb(dividend, dividend, Operand(0)); __ rsb(dividend, dividend, Operand(0));
__ and_(dividend, dividend, Operand(divisor - 1)); __ and_(dividend, dividend, Operand(divisor - 1));
...@@ -817,55 +817,67 @@ void LCodeGen::DoModI(LModI* instr) { ...@@ -817,55 +817,67 @@ void LCodeGen::DoModI(LModI* instr) {
return; return;
} }
class DeferredModI: public LDeferredCode {
public:
DeferredModI(LCodeGen* codegen, LModI* instr)
: LDeferredCode(codegen), instr_(instr) { }
virtual void Generate() {
codegen()->DoDeferredBinaryOpStub(instr_, Token::MOD);
}
private:
LModI* instr_;
};
// These registers hold untagged 32 bit values. // These registers hold untagged 32 bit values.
Register left = ToRegister(instr->InputAt(0)); Register left = ToRegister(instr->InputAt(0));
Register right = ToRegister(instr->InputAt(1)); Register right = ToRegister(instr->InputAt(1));
Register result = ToRegister(instr->result()); Register result = ToRegister(instr->result());
Register scratch = scratch0(); Register scratch = scratch0();
Register scratch2 = ToRegister(instr->TempAt(0));
DwVfpRegister dividend = ToDoubleRegister(instr->TempAt(1));
DwVfpRegister divisor = ToDoubleRegister(instr->TempAt(2));
DwVfpRegister quotient = double_scratch0();
ASSERT(result.is(left));
ASSERT(!dividend.is(divisor));
ASSERT(!dividend.is(quotient));
ASSERT(!divisor.is(quotient));
ASSERT(!scratch.is(left));
ASSERT(!scratch.is(right));
ASSERT(!scratch.is(result));
Label done, vfp_modulo, both_positive, right_negative;
Label deoptimize, done;
// Check for x % 0. // Check for x % 0.
if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) { if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
__ tst(right, Operand(right)); __ cmp(right, Operand(0));
__ b(eq, &deoptimize); DeoptimizeIf(eq, instr->environment());
} }
// Check for (0 % -x) that will produce negative zero. // (0 % x) must yield 0 (if x is finite, which is the case here).
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { __ cmp(left, Operand(0));
Label ok; __ b(eq, &done);
__ tst(left, Operand(left)); // Preload right in a vfp register.
__ b(ne, &ok); __ vmov(divisor.low(), right);
__ tst(right, Operand(right)); __ b(lt, &vfp_modulo);
__ b(pl, &ok);
__ b(al, &deoptimize);
__ bind(&ok);
}
// Try a few common cases before using the stub. __ cmp(left, Operand(right));
Label call_stub; __ b(lt, &done);
// Check for (positive) power of two on the right hand side.
__ JumpIfNotPowerOfTwoOrZeroAndNeg(right,
scratch,
&right_negative,
&both_positive);
// Perform modulo operation (scratch contains right - 1).
__ and_(result, scratch, Operand(left));
__ b(&done);
__ bind(&right_negative);
// Negate right. The sign of the divisor does not matter.
__ rsb(right, right, Operand(0));
__ bind(&both_positive);
const int kUnfolds = 3; const int kUnfolds = 3;
// Skip if either side is negative.
__ cmp(left, Operand(0));
__ cmp(right, Operand(0), NegateCondition(mi));
__ b(mi, &call_stub);
// If the right hand side is smaller than the (nonnegative) // If the right hand side is smaller than the (nonnegative)
// left hand side, it is the result. Else try a few subtractions // left hand side, the left hand side is the result.
// of the left hand side. // Else try a few subtractions of the left hand side.
__ mov(scratch, left); __ mov(scratch, left);
for (int i = 0; i < kUnfolds; i++) { for (int i = 0; i < kUnfolds; i++) {
// Check if the left hand side is less or equal than the // Check if the left hand side is less or equal than the
// the right hand side. // the right hand side.
__ cmp(scratch, right); __ cmp(scratch, Operand(right));
__ mov(result, scratch, LeaveCC, lt); __ mov(result, scratch, LeaveCC, lt);
__ b(lt, &done); __ b(lt, &done);
// If not, reduce the left hand side by the right hand // If not, reduce the left hand side by the right hand
...@@ -873,29 +885,45 @@ void LCodeGen::DoModI(LModI* instr) { ...@@ -873,29 +885,45 @@ void LCodeGen::DoModI(LModI* instr) {
if (i < kUnfolds - 1) __ sub(scratch, scratch, right); if (i < kUnfolds - 1) __ sub(scratch, scratch, right);
} }
// Check for power of two on the right hand side. __ bind(&vfp_modulo);
__ JumpIfNotPowerOfTwoOrZero(right, scratch, &call_stub); // Load the arguments in VFP registers.
// Perform modulo operation (scratch contains right - 1). // The divisor value is preloaded before. Be careful that 'right' is only live
__ and_(result, scratch, Operand(left)); // on entry.
__ b(&done); __ vmov(dividend.low(), left);
// From here on don't use right as it may have been reallocated (for example
__ bind(&call_stub); // to scratch2).
// Call the stub. The numbers in r0 and r1 have right = no_reg;
// to be tagged to Smis. If that is not possible, deoptimize.
DeferredModI* deferred = new DeferredModI(this, instr); __ vcvt_f64_s32(dividend, dividend.low());
__ TrySmiTag(left, &deoptimize, scratch); __ vcvt_f64_s32(divisor, divisor.low());
__ TrySmiTag(right, &deoptimize, scratch);
// We do not care about the sign of the divisor.
__ b(al, deferred->entry()); __ vabs(divisor, divisor);
__ bind(deferred->exit()); // Compute the quotient and round it to a 32bit integer.
__ vdiv(quotient, dividend, divisor);
// If the result in r0 is a Smi, untag it, else deoptimize. __ vcvt_s32_f64(quotient.low(), quotient);
__ JumpIfNotSmi(result, &deoptimize); __ vcvt_f64_s32(quotient, quotient.low());
__ SmiUntag(result);
// Compute the remainder in result.
DwVfpRegister double_scratch = dividend;
__ vmul(double_scratch, divisor, quotient);
__ vcvt_s32_f64(double_scratch.low(), double_scratch);
__ vmov(scratch, double_scratch.low());
if (!instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
__ sub(result, left, scratch);
} else {
Label ok;
// Check for -0.
__ sub(scratch2, left, scratch, SetCC);
__ b(ne, &ok);
__ cmp(left, Operand(0));
DeoptimizeIf(mi, instr->environment());
__ bind(&ok);
// Load the result and we are done.
__ mov(result, scratch2);
}
__ b(al, &done);
__ bind(&deoptimize);
DeoptimizeIf(al, instr->environment());
__ bind(&done); __ bind(&done);
} }
...@@ -919,16 +947,16 @@ void LCodeGen::DoDivI(LDivI* instr) { ...@@ -919,16 +947,16 @@ void LCodeGen::DoDivI(LDivI* instr) {
// Check for x / 0. // Check for x / 0.
if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) { if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
__ tst(right, right); __ cmp(right, Operand(0));
DeoptimizeIf(eq, instr->environment()); DeoptimizeIf(eq, instr->environment());
} }
// Check for (0 / -x) that will produce negative zero. // Check for (0 / -x) that will produce negative zero.
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
Label left_not_zero; Label left_not_zero;
__ tst(left, Operand(left)); __ cmp(left, Operand(0));
__ b(ne, &left_not_zero); __ b(ne, &left_not_zero);
__ tst(right, Operand(right)); __ cmp(right, Operand(0));
DeoptimizeIf(mi, instr->environment()); DeoptimizeIf(mi, instr->environment());
__ bind(&left_not_zero); __ bind(&left_not_zero);
} }
...@@ -1035,7 +1063,7 @@ void LCodeGen::DoMulI(LMulI* instr) { ...@@ -1035,7 +1063,7 @@ void LCodeGen::DoMulI(LMulI* instr) {
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
// Bail out if the result is supposed to be negative zero. // Bail out if the result is supposed to be negative zero.
Label done; Label done;
__ tst(left, Operand(left)); __ cmp(left, Operand(0));
__ b(ne, &done); __ b(ne, &done);
if (instr->InputAt(1)->IsConstantOperand()) { if (instr->InputAt(1)->IsConstantOperand()) {
if (ToInteger32(LConstantOperand::cast(instr->InputAt(1))) <= 0) { if (ToInteger32(LConstantOperand::cast(instr->InputAt(1))) <= 0) {
...@@ -1900,8 +1928,7 @@ void LCodeGen::DoInstanceOf(LInstanceOf* instr) { ...@@ -1900,8 +1928,7 @@ void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
InstanceofStub stub(InstanceofStub::kArgsInRegisters); InstanceofStub stub(InstanceofStub::kArgsInRegisters);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
Label true_value, done; __ cmp(r0, Operand(0));
__ tst(r0, r0);
__ mov(r0, Operand(factory()->false_value()), LeaveCC, ne); __ mov(r0, Operand(factory()->false_value()), LeaveCC, ne);
__ mov(r0, Operand(factory()->true_value()), LeaveCC, eq); __ mov(r0, Operand(factory()->true_value()), LeaveCC, eq);
} }
...@@ -1916,7 +1943,7 @@ void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) { ...@@ -1916,7 +1943,7 @@ void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) {
InstanceofStub stub(InstanceofStub::kArgsInRegisters); InstanceofStub stub(InstanceofStub::kArgsInRegisters);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
__ tst(r0, Operand(r0)); __ cmp(r0, Operand(0));
EmitBranch(true_block, false_block, eq); EmitBranch(true_block, false_block, eq);
} }
...@@ -2406,7 +2433,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { ...@@ -2406,7 +2433,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
// stack. // stack.
Label invoke, loop; Label invoke, loop;
// length is a small non-negative integer, due to the test above. // length is a small non-negative integer, due to the test above.
__ tst(length, Operand(length)); __ cmp(length, Operand(0));
__ b(eq, &invoke); __ b(eq, &invoke);
__ bind(&loop); __ bind(&loop);
__ ldr(scratch, MemOperand(elements, length, LSL, 2)); __ ldr(scratch, MemOperand(elements, length, LSL, 2));
...@@ -2642,6 +2669,7 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { ...@@ -2642,6 +2669,7 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
// Move the result back to general purpose register r0. // Move the result back to general purpose register r0.
__ vmov(result, single_scratch); __ vmov(result, single_scratch);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
// Test for -0. // Test for -0.
Label done; Label done;
__ cmp(result, Operand(0)); __ cmp(result, Operand(0));
...@@ -2650,6 +2678,7 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { ...@@ -2650,6 +2678,7 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
__ tst(scratch1, Operand(HeapNumber::kSignMask)); __ tst(scratch1, Operand(HeapNumber::kSignMask));
DeoptimizeIf(ne, instr->environment()); DeoptimizeIf(ne, instr->environment());
__ bind(&done); __ bind(&done);
}
} }
...@@ -2666,6 +2695,7 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { ...@@ -2666,6 +2695,7 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
DeoptimizeIf(ne, instr->environment()); DeoptimizeIf(ne, instr->environment());
__ vmov(result, double_scratch0().low()); __ vmov(result, double_scratch0().low());
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
// Test for -0. // Test for -0.
Label done; Label done;
__ cmp(result, Operand(0)); __ cmp(result, Operand(0));
...@@ -2674,6 +2704,7 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { ...@@ -2674,6 +2704,7 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
__ tst(scratch1, Operand(HeapNumber::kSignMask)); __ tst(scratch1, Operand(HeapNumber::kSignMask));
DeoptimizeIf(ne, instr->environment()); DeoptimizeIf(ne, instr->environment());
__ bind(&done); __ bind(&done);
}
} }
......
...@@ -2489,6 +2489,18 @@ void MacroAssembler::JumpIfNotPowerOfTwoOrZero( ...@@ -2489,6 +2489,18 @@ void MacroAssembler::JumpIfNotPowerOfTwoOrZero(
} }
void MacroAssembler::JumpIfNotPowerOfTwoOrZeroAndNeg(
Register reg,
Register scratch,
Label* zero_and_neg,
Label* not_power_of_two) {
sub(scratch, reg, Operand(1), SetCC);
b(mi, zero_and_neg);
tst(scratch, reg);
b(ne, not_power_of_two);
}
void MacroAssembler::JumpIfNotBothSmi(Register reg1, void MacroAssembler::JumpIfNotBothSmi(Register reg1,
Register reg2, Register reg2,
Label* on_not_both_smi) { Label* on_not_both_smi) {
......
...@@ -826,6 +826,16 @@ class MacroAssembler: public Assembler { ...@@ -826,6 +826,16 @@ class MacroAssembler: public Assembler {
void JumpIfNotPowerOfTwoOrZero(Register reg, void JumpIfNotPowerOfTwoOrZero(Register reg,
Register scratch, Register scratch,
Label* not_power_of_two_or_zero); Label* not_power_of_two_or_zero);
// Check whether the value of reg is a power of two and not zero.
// Control falls through if it is, with scratch containing the mask
// value (reg - 1).
// Otherwise control jumps to the 'zero_and_neg' label if the value of reg is
// zero or negative, or jumps to the 'not_power_of_two' label if the value is
// strictly positive but not a power of two.
void JumpIfNotPowerOfTwoOrZeroAndNeg(Register reg,
Register scratch,
Label* zero_and_neg,
Label* not_power_of_two);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Smi utilities // Smi utilities
......
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