ASSERT(instr->right()->representation().Equals(instr->representation()));
LOperand* dividend = UseRegisterAtStart(instr->left());
int32_t divisor = instr->right()->GetInteger32Constant();
- LInstruction* result =
- DefineSameAsFirst(new(zone()) LFlooringDivByPowerOf2I(dividend, divisor));
- bool can_deopt =
- (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
- (instr->left()->RangeCanInclude(kMinInt) && divisor == -1);
- return can_deopt ? AssignEnvironment(result) : result;
+ LInstruction* result = DefineAsRegister(new(zone()) LFlooringDivByPowerOf2I(
+ dividend, divisor));
+ if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
+ (instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
+ result = AssignEnvironment(result);
+ }
+ return result;
}
void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
Register dividend = ToRegister32(instr->dividend());
+ Register result = ToRegister32(instr->result());
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
// can simply do an arithmetic right shift.
if (divisor == 1) return;
int32_t shift = WhichPowerOf2Abs(divisor);
if (divisor > 1) {
- __ Mov(dividend, Operand(dividend, ASR, shift));
+ __ Mov(result, Operand(dividend, ASR, shift));
return;
}
// If the divisor is negative, we have to negate and handle edge cases.
Label not_kmin_int, done;
- __ Negs(dividend, dividend);
+ __ Negs(result, dividend);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
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
// register.
- __ B(vc, ¬_kmin_int);
if (divisor == -1) {
- Deoptimize(instr->environment());
+ DeoptimizeIf(vs, instr->environment());
} else {
- __ Mov(dividend, kMinInt / divisor);
+ __ B(vc, ¬_kmin_int);
+ __ Mov(result, kMinInt / divisor);
__ B(&done);
}
}
__ bind(¬_kmin_int);
- __ Mov(dividend, Operand(dividend, ASR, shift));
+ __ Mov(result, Operand(dividend, ASR, shift));
__ bind(&done);
}
LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
LOperand* dividend = UseRegisterAtStart(instr->left());
int32_t divisor = instr->right()->GetInteger32Constant();
- LInstruction* result =
- DefineSameAsFirst(
- new(zone()) LFlooringDivByPowerOf2I(dividend, divisor));
- bool can_deopt =
- (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
- (instr->left()->RangeCanInclude(kMinInt) && divisor == -1);
- return can_deopt ? AssignEnvironment(result) : result;
+ LInstruction* result = DefineAsRegister(new(zone()) LFlooringDivByPowerOf2I(
+ dividend, divisor));
+ if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
+ (instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
+ result = AssignEnvironment(result);
+ }
+ return result;
}
void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
Register dividend = ToRegister(instr->dividend());
+ Register result = ToRegister(instr->result());
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
// can simply do an arithmetic right shift.
if (divisor == 1) return;
int32_t shift = WhichPowerOf2Abs(divisor);
if (divisor > 1) {
- __ mov(dividend, Operand(dividend, ASR, shift));
+ __ mov(result, Operand(dividend, ASR, shift));
return;
}
// If the divisor is negative, we have to negate and handle edge cases.
- Label not_kmin_int, done;
- __ rsb(dividend, dividend, Operand::Zero(), SetCC);
+ __ rsb(result, dividend, Operand::Zero(), SetCC);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
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
// register.
- __ b(vc, ¬_kmin_int);
if (divisor == -1) {
- DeoptimizeIf(al, instr->environment());
+ DeoptimizeIf(vs, instr->environment());
+ __ mov(result, Operand(dividend, ASR, shift));
} else {
- __ mov(dividend, Operand(kMinInt / divisor));
- __ b(&done);
+ __ mov(result, Operand(kMinInt / divisor), LeaveCC, vs);
+ __ mov(result, Operand(dividend, ASR, shift), LeaveCC, vc);
}
+ } else {
+ __ mov(result, Operand(dividend, ASR, shift));
}
- __ bind(¬_kmin_int);
- __ mov(dividend, Operand(dividend, ASR, shift));
- __ bind(&done);
}
}
-Range* HBinaryOperation::InferRangeForDiv(Zone* zone) {
+Range* HDiv::InferRange(Zone* zone) {
if (representation().IsInteger32()) {
Range* a = left()->range();
Range* b = right()->range();
}
-Range* HDiv::InferRange(Zone* zone) {
- return InferRangeForDiv(zone);
-}
+Range* HMathFloorOfDiv::InferRange(Zone* 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);
+ }
-Range* HMathFloorOfDiv::InferRange(Zone* zone) {
- return InferRangeForDiv(zone);
+ if (!b->CanBeZero()) {
+ ClearFlag(kCanBeDivByZero);
+ }
+ return result;
+ } else {
+ return HValue::InferRange(zone);
+ }
}
kCanOverflow,
kBailoutOnMinusZero,
kCanBeDivByZero,
+ kLeftCanBeMinInt,
kAllowUndefinedAsNaN,
kIsArguments,
kTruncatingToInt32,
// TODO(svenpanne) We should really use the null object pattern here.
bool HasRange() const { return range_ != NULL; }
bool CanBeNegative() const { return !HasRange() || range()->CanBeNegative(); }
- bool RangeCanInclude(int value) const {
- return !HasRange() || range()->Includes(value);
- }
void AddNewRange(Range* r, Zone* zone);
void RemoveLastAddedRange();
void ComputeInitialRange(Zone* zone);
DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation)
- protected:
- Range* InferRangeForDiv(Zone* zone);
-
private:
bool IgnoreObservedOutputRepresentation(Representation current_rep);
SetFlag(kUseGVN);
SetFlag(kCanOverflow);
SetFlag(kCanBeDivByZero);
+ SetFlag(kLeftCanBeMinInt);
SetFlag(kAllowUndefinedAsNaN);
}
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
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
// register.
- __ j(no_overflow, ¬_kmin_int, Label::kNear);
if (divisor == -1) {
- DeoptimizeIf(no_condition, instr->environment());
+ DeoptimizeIf(overflow, instr->environment());
} else {
+ __ j(no_overflow, ¬_kmin_int, Label::kNear);
__ mov(dividend, Immediate(kMinInt / divisor));
__ jmp(&done, Label::kNear);
}
LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
LOperand* dividend = UseRegisterAtStart(instr->left());
int32_t divisor = instr->right()->GetInteger32Constant();
- LInstruction* result =
- DefineSameAsFirst(new(zone()) LFlooringDivByPowerOf2I(dividend, divisor));
- bool can_deopt =
- (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
- (instr->left()->RangeCanInclude(kMinInt) && divisor == -1);
- return can_deopt ? AssignEnvironment(result) : result;
+ LInstruction* result = DefineSameAsFirst(new(zone()) LFlooringDivByPowerOf2I(
+ dividend, divisor));
+ if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
+ (instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
+ result = AssignEnvironment(result);
+ }
+ return result;
}
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
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
// register.
__ j(no_overflow, ¬_kmin_int, Label::kNear);
LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
LOperand* dividend = UseRegisterAtStart(instr->left());
int32_t divisor = instr->right()->GetInteger32Constant();
- LInstruction* result =
- DefineSameAsFirst(new(zone()) LFlooringDivByPowerOf2I(dividend, divisor));
- bool can_deopt =
- (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
- (instr->left()->RangeCanInclude(kMinInt) && divisor == -1);
- return can_deopt ? AssignEnvironment(result) : result;
+ LInstruction* result = DefineSameAsFirst(new(zone()) LFlooringDivByPowerOf2I(
+ dividend, divisor));
+ if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
+ (instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
+ result = AssignEnvironment(result);
+ }
+ return result;
}