Commit a2e971c5 authored by Georg Neis's avatar Georg Neis Committed by Commit Bot

[turbofan] Fix bug in Typer::TypeInductionVariablePhi

The fix in b8b60750 was insufficient.

The bug is that induction variable typing does not take into account
that the value can become NaN through addition or subtraction of
Infinities. The previous fix incorrectly assumed that this can only
happen when the initial value of the loop variable is an Infinity.

Bug: chromium:1051017
Change-Id: I8c9ffb2925288b80c00e18e7bc22a556bf540733
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2051957
Commit-Queue: Georg Neis <neis@chromium.org>
Reviewed-by: 's avatarMichael Stanton <mvstanton@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66258}
parent fc3ba857
...@@ -847,30 +847,24 @@ Type Typer::Visitor::TypeInductionVariablePhi(Node* node) { ...@@ -847,30 +847,24 @@ Type Typer::Visitor::TypeInductionVariablePhi(Node* node) {
DCHECK_EQ(IrOpcode::kLoop, NodeProperties::GetControlInput(node)->opcode()); DCHECK_EQ(IrOpcode::kLoop, NodeProperties::GetControlInput(node)->opcode());
DCHECK_EQ(2, NodeProperties::GetControlInput(node)->InputCount()); DCHECK_EQ(2, NodeProperties::GetControlInput(node)->InputCount());
auto res = induction_vars_->induction_variables().find(node->id());
DCHECK(res != induction_vars_->induction_variables().end());
InductionVariable* induction_var = res->second;
InductionVariable::ArithmeticType arithmetic_type = induction_var->Type();
Type initial_type = Operand(node, 0); Type initial_type = Operand(node, 0);
Type increment_type = Operand(node, 2); Type increment_type = Operand(node, 2);
const bool both_types_integer = initial_type.Is(typer_->cache_->kInteger) && // If we do not have enough type information for the initial value or
increment_type.Is(typer_->cache_->kInteger); // the increment, just return the initial value's type.
bool maybe_nan = false; if (initial_type.IsNone() ||
// The addition or subtraction could still produce a NaN, if the integer increment_type.Is(typer_->cache_->kSingletonZero)) {
// ranges touch infinity. return initial_type;
if (both_types_integer) {
Type resultant_type =
(arithmetic_type == InductionVariable::ArithmeticType::kAddition)
? typer_->operation_typer()->NumberAdd(initial_type, increment_type)
: typer_->operation_typer()->NumberSubtract(initial_type,
increment_type);
maybe_nan = resultant_type.Maybe(Type::NaN());
} }
// We only handle integer induction variables (otherwise ranges // We only handle integer induction variables (otherwise ranges do not apply
// do not apply and we cannot do anything). // and we cannot do anything). Moreover, we don't support infinities in
if (!both_types_integer || maybe_nan) { // {increment_type} because the induction variable can become NaN through
// addition/subtraction of opposing infinities.
if (!initial_type.Is(typer_->cache_->kInteger) ||
!increment_type.Is(typer_->cache_->kInteger) ||
increment_type.Min() == -V8_INFINITY ||
increment_type.Max() == +V8_INFINITY) {
// Fallback to normal phi typing, but ensure monotonicity. // Fallback to normal phi typing, but ensure monotonicity.
// (Unfortunately, without baking in the previous type, monotonicity might // (Unfortunately, without baking in the previous type, monotonicity might
// be violated because we might not yet have retyped the incrementing // be violated because we might not yet have retyped the incrementing
...@@ -883,14 +877,13 @@ Type Typer::Visitor::TypeInductionVariablePhi(Node* node) { ...@@ -883,14 +877,13 @@ Type Typer::Visitor::TypeInductionVariablePhi(Node* node) {
} }
return type; return type;
} }
// If we do not have enough type information for the initial value or
// the increment, just return the initial value's type.
if (initial_type.IsNone() ||
increment_type.Is(typer_->cache_->kSingletonZero)) {
return initial_type;
}
// Now process the bounds. // Now process the bounds.
auto res = induction_vars_->induction_variables().find(node->id());
DCHECK(res != induction_vars_->induction_variables().end());
InductionVariable* induction_var = res->second;
InductionVariable::ArithmeticType arithmetic_type = induction_var->Type();
double min = -V8_INFINITY; double min = -V8_INFINITY;
double max = V8_INFINITY; double max = V8_INFINITY;
...@@ -946,8 +939,8 @@ Type Typer::Visitor::TypeInductionVariablePhi(Node* node) { ...@@ -946,8 +939,8 @@ Type Typer::Visitor::TypeInductionVariablePhi(Node* node) {
// The lower bound must be at most the initial value's lower bound. // The lower bound must be at most the initial value's lower bound.
min = std::min(min, initial_type.Min()); min = std::min(min, initial_type.Min());
} else { } else {
// Shortcut: If the increment can be both positive and negative, // If the increment can be both positive and negative, the variable can go
// the variable can go arbitrarily far, so just return integer. // arbitrarily far.
return typer_->cache_->kInteger; return typer_->cache_->kInteger;
} }
if (FLAG_trace_turbo_loop) { if (FLAG_trace_turbo_loop) {
......
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
function foo1() {
var x = -Infinity;
var i = 0;
for (; i < 1; i += x) {
if (i == -Infinity) x = +Infinity;
}
return i;
}
%PrepareFunctionForOptimization(foo1);
assertEquals(NaN, foo1());
assertEquals(NaN, foo1());
%OptimizeFunctionOnNextCall(foo1);
assertEquals(NaN, foo1());
function foo2() {
var i = -Infinity;
for (; i <= 42; i += Infinity) { }
return i;
}
%PrepareFunctionForOptimization(foo2);
assertEquals(NaN, foo2());
assertEquals(NaN, foo2());
%OptimizeFunctionOnNextCall(foo2);
assertEquals(NaN, foo2());
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment