| Index: src/hydrogen-instructions.cc
|
| ===================================================================
|
| --- src/hydrogen-instructions.cc (revision 12214)
|
| +++ src/hydrogen-instructions.cc (working copy)
|
| @@ -1102,7 +1102,102 @@
|
| }
|
|
|
|
|
| +#if defined(V8_TARGET_ARCH_IA32) || defined(V8_TARGET_ARCH_X64)
|
| +
|
| +// Return an integer value or NULL, which may involve skipping over a
|
| +// representation change
|
| +static HValue* SimplifiedValueForIntDiv(HValue* value) {
|
| + if (value->representation().IsInteger32()) {
|
| + return value;
|
| + } else if (value->IsConstant() &&
|
| + HConstant::cast(value)->HasInteger32Value()) {
|
| + return value;
|
| + } else if (value->IsChange() &&
|
| + HChange::cast(value)->from().IsInteger32()) {
|
| + return HChange::cast(value)->value();
|
| + }
|
| + return NULL;
|
| +}
|
| +
|
| +
|
| +// Insert an integer constant into the graph when given a non-integer constant
|
| +static HValue* EnsureIntegerConstantForIntDiv(HValue* value,
|
| + HInstruction* insertBefore) {
|
| + if (value->IsConstant() && !value->representation().IsInteger32()) {
|
| + ASSERT(HConstant::cast(value)->HasInteger32Value());
|
| + HConstant* constant = HConstant::cast(value)->CopyToRepresentation(
|
| + Representation::Integer32(), insertBefore->block()->zone());
|
| + constant->InsertBefore(insertBefore);
|
| + return constant;
|
| + }
|
| + return value;
|
| +}
|
| +
|
| +
|
| +// Try to replace the division of a non-negative integer by a positive integer
|
| +// that is then truncated to an integer with an integer division instruction.
|
| +// This gives a 2x speedup over using double division. Return NULL on failure.
|
| +static HDiv* MaybeConvertToIntDiv(HChange* change, Zone* zone) {
|
| + if (change->value()->IsDiv() &&
|
| + HDiv::cast(change->value())->UseCount() == 1 &&
|
| + change->from().IsDouble() &&
|
| + change->to().IsInteger32() &&
|
| + change->CheckFlag(HValue::kTruncatingToInt32)) {
|
| + HDiv* div = HDiv::cast(change->value());
|
| + HValue* left = div->left();
|
| + HValue* right = div->right();
|
| + HValue* new_left = SimplifiedValueForIntDiv(left);
|
| + HValue* new_right = SimplifiedValueForIntDiv(right);
|
| +
|
| + // Only apply this optimization if we know it won't hit any special cases
|
| + // that would otherwise cause a deopt in the representation change
|
| + if (new_left != NULL && new_right != NULL &&
|
| + new_left->range()->lower() >= 0 &&
|
| + new_right->range()->lower() > 0) {
|
| + // Change non-integer constants to integer constants
|
| + new_left = EnsureIntegerConstantForIntDiv(new_left, div);
|
| + new_right = EnsureIntegerConstantForIntDiv(new_right, div);
|
| + ASSERT(new_left->representation().IsInteger32());
|
| + ASSERT(new_right->representation().IsInteger32());
|
| +
|
| + // Replace this representation change with an integer division
|
| + HDiv* new_div = new(div->block()->zone()) HDiv(div->context(),
|
| + new_left, new_right);
|
| + new_div->AssumeRepresentation(Representation::Integer32());
|
| + new_div->InsertBefore(div);
|
| + change->DeleteAndReplaceWith(new_div);
|
| +
|
| + // Delete unused instructions
|
| + div->DeleteAndReplaceWith(NULL);
|
| + if (left->HasNoUses()) left->DeleteAndReplaceWith(NULL);
|
| + if (right->HasNoUses()) right->DeleteAndReplaceWith(NULL);
|
| +
|
| + // Tell codegen not to emit code to check for a non-zero remainder.
|
| + // Codegen can't use CheckUsesForFlag(kTruncatingToInt32) because
|
| + // that flag is on the HChange instruction which is now deleted.
|
| + new_div->SetFlag(HValue::kWillTruncateToInt32);
|
| +
|
| + // Make sure all new values have ranges
|
| + if (!new_left->HasRange()) new_left->ComputeInitialRange(zone);
|
| + if (!new_right->HasRange()) new_right->ComputeInitialRange(zone);
|
| + new_div->ComputeInitialRange(zone);
|
| + return new_div;
|
| + }
|
| + }
|
| + return NULL;
|
| +}
|
| +
|
| +#endif
|
| +
|
| +
|
| Range* HChange::InferRange(Zone* zone) {
|
| +#if defined(V8_TARGET_ARCH_IA32) || defined(V8_TARGET_ARCH_X64)
|
| + HDiv* div = MaybeConvertToIntDiv(this, zone);
|
| + if (div != NULL) {
|
| + return div->range();
|
| + }
|
| +#endif
|
| +
|
| Range* input_range = value()->range();
|
| if (from().IsInteger32() &&
|
| to().IsTagged() &&
|
| @@ -1209,11 +1304,23 @@
|
|
|
| if (right()->range()->Includes(-1) && left()->range()->Includes(kMinInt)) {
|
| SetFlag(HValue::kCanOverflow);
|
| + } else {
|
| + ClearFlag(HValue::kCanOverflow);
|
| }
|
|
|
| if (!right()->range()->CanBeZero()) {
|
| ClearFlag(HValue::kCanBeDivByZero);
|
| }
|
| +
|
| + // An exact range can be inferred for division with integer operands
|
| + if (left()->representation().IsInteger32() &&
|
| + right()->representation().IsInteger32() &&
|
| + left()->range()->lower() >= 0 &&
|
| + right()->range()->lower() > 0) {
|
| + Range limits(left()->range()->lower() / right()->range()->upper(),
|
| + left()->range()->upper() / right()->range()->lower());
|
| + result->Intersect(&limits);
|
| + }
|
| return result;
|
| } else {
|
| return HValue::InferRange(zone);
|
|
|