[TurboFan] Loop variable analysis requires more sensitivity

Loop variable analysis doesn't recognize that the initial type of the
loop variable phi combined with the increment type may produce a NaN
result through the addition of two infinities of differing sign.

This leads to unreachable code and a SIGINT crash.

The fix is to consider this case before typing the loop variable phi,
falling back to more conservative typing if discovered.

R=neis@chromium.org

Bug: chromium:1028863
Change-Id: Ic4b5189c4c50c5bbe29e46050de630fd0673de9f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1946352
Commit-Queue: Michael Stanton <mvstanton@chromium.org>
Reviewed-by: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65291}
diff --git a/src/compiler/graph-reducer.cc b/src/compiler/graph-reducer.cc
index 9a0dea6..91b4b51 100644
--- a/src/compiler/graph-reducer.cc
+++ b/src/compiler/graph-reducer.cc
@@ -94,7 +94,8 @@
         // all the other reducers for this node, as now there may be more
         // opportunities for reduction.
         if (FLAG_trace_turbo_reduction) {
-          StdoutStream{} << "- In-place update of " << *node << " by reducer "
+          AllowHandleDereference allow_deref;
+          StdoutStream{} << "- In-place update of #" << *node << " by reducer "
                          << (*i)->reducer_name() << std::endl;
         }
         skip = i;
@@ -103,7 +104,8 @@
       } else {
         // {node} was replaced by another node.
         if (FLAG_trace_turbo_reduction) {
-          StdoutStream{} << "- Replacement of " << *node << " with "
+          AllowHandleDereference allow_deref;
+          StdoutStream{} << "- Replacement of #" << *node << " with #"
                          << *(reduction.replacement()) << " by reducer "
                          << (*i)->reducer_name() << std::endl;
         }
diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc
index b3d7d49..7e0f81d 100644
--- a/src/compiler/typer.cc
+++ b/src/compiler/typer.cc
@@ -847,13 +847,30 @@
   DCHECK_EQ(IrOpcode::kLoop, NodeProperties::GetControlInput(node)->opcode());
   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 increment_type = Operand(node, 2);
 
+  const bool both_types_integer = initial_type.Is(typer_->cache_->kInteger) &&
+                                  increment_type.Is(typer_->cache_->kInteger);
+  bool maybe_nan = false;
+  // The addition or subtraction could still produce a NaN, if the integer
+  // ranges touch infinity.
+  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
   // do not apply and we cannot do anything).
-  if (!initial_type.Is(typer_->cache_->kInteger) ||
-      !increment_type.Is(typer_->cache_->kInteger)) {
+  if (!both_types_integer || maybe_nan) {
     // Fallback to normal phi typing, but ensure monotonicity.
     // (Unfortunately, without baking in the previous type, monotonicity might
     // be violated because we might not yet have retyped the incrementing
@@ -874,12 +891,6 @@
   }
 
   // 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 max = V8_INFINITY;
 
diff --git a/test/mjsunit/regress/regress-crbug-1028863.js b/test/mjsunit/regress/regress-crbug-1028863.js
new file mode 100644
index 0000000..d210663
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-1028863.js
@@ -0,0 +1,24 @@
+// Copyright 2019 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 write(begin, end, step) {
+  for (var i = begin; i >= end; i += step) {
+    step = end - begin;
+    begin >>>= 805306382;
+  }
+}
+
+function bar() {
+  for (let i = 0; i < 10000; i++) {
+    write(Infinity, 1, 1);
+  }
+}
+
+%PrepareFunctionForOptimization(write);
+%PrepareFunctionForOptimization(bar);
+bar();
+%OptimizeFunctionOnNextCall(bar);
+bar();