Chromium Code Reviews| Index: src/hydrogen-instructions.cc |
| =================================================================== |
| --- src/hydrogen-instructions.cc (revision 12214) |
| +++ src/hydrogen-instructions.cc (working copy) |
| @@ -315,6 +315,16 @@ |
| } |
| +int HValue::UseCountIgnoringInputsRequiringNone() const { |
| + int count = 0; |
| + for (HUseIterator it(uses()); !it.Done(); it.Advance()) { |
| + Representation req = it.value()->RequiredInputRepresentation(it.index()); |
| + if (!req.IsNone()) count++; |
| + } |
| + return count; |
| +} |
| + |
| + |
| HUseListNode* HValue::RemoveUse(HValue* value, int index) { |
| HUseListNode* previous = NULL; |
| HUseListNode* current = use_list_; |
| @@ -1102,7 +1112,105 @@ |
| } |
| +#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() && |
|
Vyacheslav Egorov (Google)
2012/07/30 12:01:44
I am a little bit uncomfortable that we apply this
Evan Wallace
2012/07/30 16:43:13
These aren't the only conditions that trigger this
Vyacheslav Egorov (Google)
2012/07/30 16:59:26
I don't dispute that it can be truncated to int32.
Evan Wallace
2012/07/30 19:35:43
I did not realize normal double to integer represe
|
| + change->from().IsDouble() && |
| + change->to().IsInteger32()) { |
| + HDiv* div = HDiv::cast(change->value()); |
| + |
| + // We want to be sure that the use count is 1 for div so we can swap it |
| + // out, but there may be other instructions (such as HSimulate) that do |
| + // not need the resulting value and so shouldn't stop this optimization |
| + if (div->UseCountIgnoringInputsRequiringNone() == 1) { |
|
Vyacheslav Egorov (Google)
2012/07/30 12:01:44
I am not sure that your approach to simulates is c
Evan Wallace
2012/07/30 16:43:13
Thanks for pointing this out! I guess I don't unde
Vyacheslav Egorov (Google)
2012/07/30 16:59:26
Simulate is a pseudo-instruction that "simulates"
|
| + 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 |
| + 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(new_div); |
| + 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 +1317,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); |