Remove uses of RangeCanInclude() in flooring division by power of 2.

Drive-By-Fix: Improve ARM code generation for flooring division by
power of 2.

BUG=v8:3204
LOG=y
R=svenpanne@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19877 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
bmeurer@chromium.org 2014-03-13 07:58:58 +00:00
parent 078ecbb9c3
commit 929313bd6b
10 changed files with 75 additions and 62 deletions

View File

@ -1749,12 +1749,13 @@ LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
ASSERT(instr->right()->representation().Equals(instr->representation())); ASSERT(instr->right()->representation().Equals(instr->representation()));
LOperand* dividend = UseRegisterAtStart(instr->left()); LOperand* dividend = UseRegisterAtStart(instr->left());
int32_t divisor = instr->right()->GetInteger32Constant(); int32_t divisor = instr->right()->GetInteger32Constant();
LInstruction* result = LInstruction* result = DefineAsRegister(new(zone()) LFlooringDivByPowerOf2I(
DefineSameAsFirst(new(zone()) LFlooringDivByPowerOf2I(dividend, divisor)); dividend, divisor));
bool can_deopt = if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
(instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) || (instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
(instr->left()->RangeCanInclude(kMinInt) && divisor == -1); result = AssignEnvironment(result);
return can_deopt ? AssignEnvironment(result) : result; }
return result;
} }

View File

@ -3839,37 +3839,37 @@ void LCodeGen::DoMathFloor(LMathFloor* instr) {
void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) { void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
Register dividend = ToRegister32(instr->dividend()); Register dividend = ToRegister32(instr->dividend());
Register result = ToRegister32(instr->result());
int32_t divisor = instr->divisor(); int32_t divisor = instr->divisor();
ASSERT(dividend.is(ToRegister32(instr->result())));
// If the divisor is positive, things are easy: There can be no deopts and we // If the divisor is positive, things are easy: There can be no deopts and we
// can simply do an arithmetic right shift. // can simply do an arithmetic right shift.
if (divisor == 1) return; if (divisor == 1) return;
int32_t shift = WhichPowerOf2Abs(divisor); int32_t shift = WhichPowerOf2Abs(divisor);
if (divisor > 1) { if (divisor > 1) {
__ Mov(dividend, Operand(dividend, ASR, shift)); __ Mov(result, Operand(dividend, ASR, shift));
return; return;
} }
// If the divisor is negative, we have to negate and handle edge cases. // If the divisor is negative, we have to negate and handle edge cases.
Label not_kmin_int, done; Label not_kmin_int, done;
__ Negs(dividend, dividend); __ Negs(result, dividend);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(eq, instr->environment()); DeoptimizeIf(eq, instr->environment());
} }
if (instr->hydrogen()->left()->RangeCanInclude(kMinInt)) { if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) {
// Note that we could emit branch-free code, but that would need one more // Note that we could emit branch-free code, but that would need one more
// register. // register.
__ B(vc, &not_kmin_int);
if (divisor == -1) { if (divisor == -1) {
Deoptimize(instr->environment()); DeoptimizeIf(vs, instr->environment());
} else { } else {
__ Mov(dividend, kMinInt / divisor); __ B(vc, &not_kmin_int);
__ Mov(result, kMinInt / divisor);
__ B(&done); __ B(&done);
} }
} }
__ bind(&not_kmin_int); __ bind(&not_kmin_int);
__ Mov(dividend, Operand(dividend, ASR, shift)); __ Mov(result, Operand(dividend, ASR, shift));
__ bind(&done); __ bind(&done);
} }

View File

@ -1316,13 +1316,13 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) { LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
LOperand* dividend = UseRegisterAtStart(instr->left()); LOperand* dividend = UseRegisterAtStart(instr->left());
int32_t divisor = instr->right()->GetInteger32Constant(); int32_t divisor = instr->right()->GetInteger32Constant();
LInstruction* result = LInstruction* result = DefineAsRegister(new(zone()) LFlooringDivByPowerOf2I(
DefineSameAsFirst( dividend, divisor));
new(zone()) LFlooringDivByPowerOf2I(dividend, divisor)); if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
bool can_deopt = (instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
(instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) || result = AssignEnvironment(result);
(instr->left()->RangeCanInclude(kMinInt) && divisor == -1); }
return can_deopt ? AssignEnvironment(result) : result; return result;
} }

View File

@ -1458,38 +1458,36 @@ void LCodeGen::DoMultiplySubD(LMultiplySubD* instr) {
void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) { void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
Register dividend = ToRegister(instr->dividend()); Register dividend = ToRegister(instr->dividend());
Register result = ToRegister(instr->result());
int32_t divisor = instr->divisor(); int32_t divisor = instr->divisor();
ASSERT(dividend.is(ToRegister(instr->result())));
// If the divisor is positive, things are easy: There can be no deopts and we // If the divisor is positive, things are easy: There can be no deopts and we
// can simply do an arithmetic right shift. // can simply do an arithmetic right shift.
if (divisor == 1) return; if (divisor == 1) return;
int32_t shift = WhichPowerOf2Abs(divisor); int32_t shift = WhichPowerOf2Abs(divisor);
if (divisor > 1) { if (divisor > 1) {
__ mov(dividend, Operand(dividend, ASR, shift)); __ mov(result, Operand(dividend, ASR, shift));
return; return;
} }
// If the divisor is negative, we have to negate and handle edge cases. // If the divisor is negative, we have to negate and handle edge cases.
Label not_kmin_int, done; __ rsb(result, dividend, Operand::Zero(), SetCC);
__ rsb(dividend, dividend, Operand::Zero(), SetCC);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(eq, instr->environment()); DeoptimizeIf(eq, instr->environment());
} }
if (instr->hydrogen()->left()->RangeCanInclude(kMinInt)) { if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) {
// Note that we could emit branch-free code, but that would need one more // Note that we could emit branch-free code, but that would need one more
// register. // register.
__ b(vc, &not_kmin_int);
if (divisor == -1) { if (divisor == -1) {
DeoptimizeIf(al, instr->environment()); DeoptimizeIf(vs, instr->environment());
__ mov(result, Operand(dividend, ASR, shift));
} else { } else {
__ mov(dividend, Operand(kMinInt / divisor)); __ mov(result, Operand(kMinInt / divisor), LeaveCC, vs);
__ b(&done); __ mov(result, Operand(dividend, ASR, shift), LeaveCC, vc);
} }
} else {
__ mov(result, Operand(dividend, ASR, shift));
} }
__ bind(&not_kmin_int);
__ mov(dividend, Operand(dividend, ASR, shift));
__ bind(&done);
} }

View File

@ -1799,7 +1799,7 @@ Range* HMul::InferRange(Zone* zone) {
} }
Range* HBinaryOperation::InferRangeForDiv(Zone* zone) { Range* HDiv::InferRange(Zone* zone) {
if (representation().IsInteger32()) { if (representation().IsInteger32()) {
Range* a = left()->range(); Range* a = left()->range();
Range* b = right()->range(); Range* b = right()->range();
@ -1821,13 +1821,29 @@ Range* HBinaryOperation::InferRangeForDiv(Zone* zone) {
} }
Range* HDiv::InferRange(Zone* zone) {
return InferRangeForDiv(zone);
}
Range* HMathFloorOfDiv::InferRange(Zone* zone) { Range* HMathFloorOfDiv::InferRange(Zone* zone) {
return InferRangeForDiv(zone); if (representation().IsInteger32()) {
Range* a = left()->range();
Range* b = right()->range();
Range* result = new(zone) Range();
result->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToInt32) &&
(a->CanBeMinusZero() ||
(a->CanBeZero() && b->CanBeNegative())));
if (!a->Includes(kMinInt)) {
ClearFlag(kLeftCanBeMinInt);
}
if (!a->Includes(kMinInt) || !b->Includes(-1)) {
ClearFlag(kCanOverflow);
}
if (!b->CanBeZero()) {
ClearFlag(kCanBeDivByZero);
}
return result;
} else {
return HValue::InferRange(zone);
}
} }

View File

@ -622,6 +622,7 @@ class HValue : public ZoneObject {
kCanOverflow, kCanOverflow,
kBailoutOnMinusZero, kBailoutOnMinusZero,
kCanBeDivByZero, kCanBeDivByZero,
kLeftCanBeMinInt,
kAllowUndefinedAsNaN, kAllowUndefinedAsNaN,
kIsArguments, kIsArguments,
kTruncatingToInt32, kTruncatingToInt32,
@ -855,9 +856,6 @@ class HValue : public ZoneObject {
// TODO(svenpanne) We should really use the null object pattern here. // TODO(svenpanne) We should really use the null object pattern here.
bool HasRange() const { return range_ != NULL; } bool HasRange() const { return range_ != NULL; }
bool CanBeNegative() const { return !HasRange() || range()->CanBeNegative(); } bool CanBeNegative() const { return !HasRange() || range()->CanBeNegative(); }
bool RangeCanInclude(int value) const {
return !HasRange() || range()->Includes(value);
}
void AddNewRange(Range* r, Zone* zone); void AddNewRange(Range* r, Zone* zone);
void RemoveLastAddedRange(); void RemoveLastAddedRange();
void ComputeInitialRange(Zone* zone); void ComputeInitialRange(Zone* zone);
@ -3765,9 +3763,6 @@ class HBinaryOperation : public HTemplateInstruction<3> {
DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation) DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation)
protected:
Range* InferRangeForDiv(Zone* zone);
private: private:
bool IgnoreObservedOutputRepresentation(Representation current_rep); bool IgnoreObservedOutputRepresentation(Representation current_rep);
@ -4109,6 +4104,7 @@ class HMathFloorOfDiv V8_FINAL : public HBinaryOperation {
SetFlag(kUseGVN); SetFlag(kUseGVN);
SetFlag(kCanOverflow); SetFlag(kCanOverflow);
SetFlag(kCanBeDivByZero); SetFlag(kCanBeDivByZero);
SetFlag(kLeftCanBeMinInt);
SetFlag(kAllowUndefinedAsNaN); SetFlag(kAllowUndefinedAsNaN);
} }

View File

@ -1637,13 +1637,13 @@ void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(zero, instr->environment()); DeoptimizeIf(zero, instr->environment());
} }
if (instr->hydrogen()->left()->RangeCanInclude(kMinInt)) { if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) {
// Note that we could emit branch-free code, but that would need one more // Note that we could emit branch-free code, but that would need one more
// register. // register.
__ j(no_overflow, &not_kmin_int, Label::kNear);
if (divisor == -1) { if (divisor == -1) {
DeoptimizeIf(no_condition, instr->environment()); DeoptimizeIf(overflow, instr->environment());
} else { } else {
__ j(no_overflow, &not_kmin_int, Label::kNear);
__ mov(dividend, Immediate(kMinInt / divisor)); __ mov(dividend, Immediate(kMinInt / divisor));
__ jmp(&done, Label::kNear); __ jmp(&done, Label::kNear);
} }

View File

@ -1409,12 +1409,13 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) { LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
LOperand* dividend = UseRegisterAtStart(instr->left()); LOperand* dividend = UseRegisterAtStart(instr->left());
int32_t divisor = instr->right()->GetInteger32Constant(); int32_t divisor = instr->right()->GetInteger32Constant();
LInstruction* result = LInstruction* result = DefineSameAsFirst(new(zone()) LFlooringDivByPowerOf2I(
DefineSameAsFirst(new(zone()) LFlooringDivByPowerOf2I(dividend, divisor)); dividend, divisor));
bool can_deopt = if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
(instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) || (instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
(instr->left()->RangeCanInclude(kMinInt) && divisor == -1); result = AssignEnvironment(result);
return can_deopt ? AssignEnvironment(result) : result; }
return result;
} }

View File

@ -1129,7 +1129,7 @@ void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(zero, instr->environment()); DeoptimizeIf(zero, instr->environment());
} }
if (instr->hydrogen()->left()->RangeCanInclude(kMinInt)) { if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) {
// Note that we could emit branch-free code, but that would need one more // Note that we could emit branch-free code, but that would need one more
// register. // register.
__ j(no_overflow, &not_kmin_int, Label::kNear); __ j(no_overflow, &not_kmin_int, Label::kNear);

View File

@ -1330,12 +1330,13 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) { LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
LOperand* dividend = UseRegisterAtStart(instr->left()); LOperand* dividend = UseRegisterAtStart(instr->left());
int32_t divisor = instr->right()->GetInteger32Constant(); int32_t divisor = instr->right()->GetInteger32Constant();
LInstruction* result = LInstruction* result = DefineSameAsFirst(new(zone()) LFlooringDivByPowerOf2I(
DefineSameAsFirst(new(zone()) LFlooringDivByPowerOf2I(dividend, divisor)); dividend, divisor));
bool can_deopt = if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
(instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) || (instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
(instr->left()->RangeCanInclude(kMinInt) && divisor == -1); result = AssignEnvironment(result);
return can_deopt ? AssignEnvironment(result) : result; }
return result;
} }