Revision: 7300
Author: [email protected]
Date: Tue Mar 22 03:00:43 2011
Log: 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
http://code.google.com/p/v8/source/detail?r=7300
Modified:
/branches/bleeding_edge/src/arm/lithium-arm.cc
/branches/bleeding_edge/src/arm/lithium-arm.h
/branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
/branches/bleeding_edge/src/arm/macro-assembler-arm.cc
/branches/bleeding_edge/src/arm/macro-assembler-arm.h
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.cc Mon Mar 21 05:25:31 2011
+++ /branches/bleeding_edge/src/arm/lithium-arm.cc Tue Mar 22 03:00:43 2011
@@ -1345,29 +1345,25 @@
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
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->right()->representation().IsInteger32());
- LInstruction* result;
+ LModI* mod;
if (instr->HasPowerOf2Divisor()) {
ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
LOperand* value = UseRegisterAtStart(instr->left());
- LModI* mod = new LModI(value, UseOrConstant(instr->right()));
- result = DefineSameAsFirst(mod);
- result = AssignEnvironment(result);
+ mod = new LModI(value, UseOrConstant(instr->right()));
} else {
- LOperand* value = UseFixed(instr->left(), r0);
- LOperand* divisor = UseFixed(instr->right(), r1);
- result = DefineFixed(new LModI(value, divisor), r0);
- result = AssignEnvironment(AssignPointerMap(result));
+ LOperand* dividend = UseRegister(instr->left());
+ LOperand* divisor = UseRegisterAtStart(instr->right());
+ mod = new LModI(dividend,
+ divisor,
+ TempRegister(),
+ FixedTemp(d1),
+ FixedTemp(d2));
}
- return result;
+ return AssignEnvironment(DefineSameAsFirst(mod));
} else if (instr->representation().IsTagged()) {
return DoArithmeticT(Token::MOD, instr);
} else {
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.h Mon Mar 21 05:25:31 2011
+++ /branches/bleeding_edge/src/arm/lithium-arm.h Tue Mar 22 03:00:43 2011
@@ -523,11 +523,29 @@
};
-class LModI: public LTemplateInstruction<1, 2, 0> {
+class LModI: public LTemplateInstruction<1, 2, 3> {
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_[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")
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Mon Mar 21
09:10:05 2011
+++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Tue Mar 22
03:00:43 2011
@@ -802,7 +802,7 @@
if (divisor < 0) divisor = -divisor;
Label positive_dividend, done;
- __ tst(dividend, Operand(dividend));
+ __ cmp(dividend, Operand(0));
__ b(pl, &positive_dividend);
__ rsb(dividend, dividend, Operand(0));
__ and_(dividend, dividend, Operand(divisor - 1));
@@ -817,55 +817,67 @@
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.
Register left = ToRegister(instr->InputAt(0));
Register right = ToRegister(instr->InputAt(1));
Register result = ToRegister(instr->result());
+
Register scratch = scratch0();
-
- Label deoptimize, done;
+ 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;
+
// Check for x % 0.
if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
- __ tst(right, Operand(right));
- __ b(eq, &deoptimize);
+ __ cmp(right, Operand(0));
+ DeoptimizeIf(eq, instr->environment());
}
- // Check for (0 % -x) that will produce negative zero.
- if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
- Label ok;
- __ tst(left, Operand(left));
- __ b(ne, &ok);
- __ tst(right, Operand(right));
- __ b(pl, &ok);
- __ b(al, &deoptimize);
- __ bind(&ok);
- }
-
- // Try a few common cases before using the stub.
- Label call_stub;
+ // (0 % x) must yield 0 (if x is finite, which is the case here).
+ __ cmp(left, Operand(0));
+ __ b(eq, &done);
+ // Preload right in a vfp register.
+ __ vmov(divisor.low(), right);
+ __ b(lt, &vfp_modulo);
+
+ __ cmp(left, Operand(right));
+ __ 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;
- // 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)
- // left hand side, it is the result. Else try a few subtractions
- // of the left hand side.
+ // left hand side, the left hand side is the result.
+ // Else try a few subtractions of the left hand side.
__ mov(scratch, left);
for (int i = 0; i < kUnfolds; i++) {
// Check if the left hand side is less or equal than the
// the right hand side.
- __ cmp(scratch, right);
+ __ cmp(scratch, Operand(right));
__ mov(result, scratch, LeaveCC, lt);
__ b(lt, &done);
// If not, reduce the left hand side by the right hand
@@ -873,29 +885,45 @@
if (i < kUnfolds - 1) __ sub(scratch, scratch, right);
}
- // Check for power of two on the right hand side.
- __ JumpIfNotPowerOfTwoOrZero(right, scratch, &call_stub);
- // Perform modulo operation (scratch contains right - 1).
- __ and_(result, scratch, Operand(left));
- __ b(&done);
-
- __ bind(&call_stub);
- // Call the stub. The numbers in r0 and r1 have
- // to be tagged to Smis. If that is not possible, deoptimize.
- DeferredModI* deferred = new DeferredModI(this, instr);
- __ TrySmiTag(left, &deoptimize, scratch);
- __ TrySmiTag(right, &deoptimize, scratch);
-
- __ b(al, deferred->entry());
- __ bind(deferred->exit());
-
- // If the result in r0 is a Smi, untag it, else deoptimize.
- __ JumpIfNotSmi(result, &deoptimize);
- __ SmiUntag(result);
-
- __ b(al, &done);
- __ bind(&deoptimize);
- DeoptimizeIf(al, instr->environment());
+ __ bind(&vfp_modulo);
+ // Load the arguments in VFP registers.
+ // The divisor value is preloaded before. Be careful that 'right' is
only live
+ // on entry.
+ __ vmov(dividend.low(), left);
+ // From here on don't use right as it may have been reallocated (for
example
+ // to scratch2).
+ right = no_reg;
+
+ __ vcvt_f64_s32(dividend, dividend.low());
+ __ vcvt_f64_s32(divisor, divisor.low());
+
+ // We do not care about the sign of the divisor.
+ __ vabs(divisor, divisor);
+ // Compute the quotient and round it to a 32bit integer.
+ __ vdiv(quotient, dividend, divisor);
+ __ vcvt_s32_f64(quotient.low(), quotient);
+ __ vcvt_f64_s32(quotient, quotient.low());
+
+ // 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);
+ }
+
__ bind(&done);
}
@@ -919,16 +947,16 @@
// Check for x / 0.
if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
- __ tst(right, right);
+ __ cmp(right, Operand(0));
DeoptimizeIf(eq, instr->environment());
}
// Check for (0 / -x) that will produce negative zero.
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
Label left_not_zero;
- __ tst(left, Operand(left));
+ __ cmp(left, Operand(0));
__ b(ne, &left_not_zero);
- __ tst(right, Operand(right));
+ __ cmp(right, Operand(0));
DeoptimizeIf(mi, instr->environment());
__ bind(&left_not_zero);
}
@@ -1035,7 +1063,7 @@
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
// Bail out if the result is supposed to be negative zero.
Label done;
- __ tst(left, Operand(left));
+ __ cmp(left, Operand(0));
__ b(ne, &done);
if (instr->InputAt(1)->IsConstantOperand()) {
if (ToInteger32(LConstantOperand::cast(instr->InputAt(1))) <= 0) {
@@ -1900,8 +1928,7 @@
InstanceofStub stub(InstanceofStub::kArgsInRegisters);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
- Label true_value, done;
- __ tst(r0, r0);
+ __ cmp(r0, Operand(0));
__ mov(r0, Operand(factory()->false_value()), LeaveCC, ne);
__ mov(r0, Operand(factory()->true_value()), LeaveCC, eq);
}
@@ -1916,7 +1943,7 @@
InstanceofStub stub(InstanceofStub::kArgsInRegisters);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
- __ tst(r0, Operand(r0));
+ __ cmp(r0, Operand(0));
EmitBranch(true_block, false_block, eq);
}
@@ -2406,7 +2433,7 @@
// stack.
Label invoke, loop;
// length is a small non-negative integer, due to the test above.
- __ tst(length, Operand(length));
+ __ cmp(length, Operand(0));
__ b(eq, &invoke);
__ bind(&loop);
__ ldr(scratch, MemOperand(elements, length, LSL, 2));
@@ -2642,14 +2669,16 @@
// Move the result back to general purpose register r0.
__ vmov(result, single_scratch);
- // Test for -0.
- Label done;
- __ cmp(result, Operand(0));
- __ b(ne, &done);
- __ vmov(scratch1, input.high());
- __ tst(scratch1, Operand(HeapNumber::kSignMask));
- DeoptimizeIf(ne, instr->environment());
- __ bind(&done);
+ if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ // Test for -0.
+ Label done;
+ __ cmp(result, Operand(0));
+ __ b(ne, &done);
+ __ vmov(scratch1, input.high());
+ __ tst(scratch1, Operand(HeapNumber::kSignMask));
+ DeoptimizeIf(ne, instr->environment());
+ __ bind(&done);
+ }
}
@@ -2666,14 +2695,16 @@
DeoptimizeIf(ne, instr->environment());
__ vmov(result, double_scratch0().low());
- // Test for -0.
- Label done;
- __ cmp(result, Operand(0));
- __ b(ne, &done);
- __ vmov(scratch1, input.high());
- __ tst(scratch1, Operand(HeapNumber::kSignMask));
- DeoptimizeIf(ne, instr->environment());
- __ bind(&done);
+ if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ // Test for -0.
+ Label done;
+ __ cmp(result, Operand(0));
+ __ b(ne, &done);
+ __ vmov(scratch1, input.high());
+ __ tst(scratch1, Operand(HeapNumber::kSignMask));
+ DeoptimizeIf(ne, instr->environment());
+ __ bind(&done);
+ }
}
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Mon Mar 21
09:10:05 2011
+++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Tue Mar 22
03:00:43 2011
@@ -2487,6 +2487,18 @@
tst(scratch, reg);
b(ne, not_power_of_two_or_zero);
}
+
+
+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,
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.h Fri Mar 18
13:35:07 2011
+++ /branches/bleeding_edge/src/arm/macro-assembler-arm.h Tue Mar 22
03:00:43 2011
@@ -826,6 +826,16 @@
void JumpIfNotPowerOfTwoOrZero(Register reg,
Register scratch,
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
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev