8259227: C2 crashes with SIGFPE due to a division that floats above its zero check

Reviewed-by: kvn, thartmann
diff --git a/src/hotspot/share/opto/ifnode.cpp b/src/hotspot/share/opto/ifnode.cpp
index 4d1ef3c..3e74127 100644
--- a/src/hotspot/share/opto/ifnode.cpp
+++ b/src/hotspot/share/opto/ifnode.cpp
@@ -1477,14 +1477,16 @@
     // Loop ends when projection has no more uses.
     for (DUIterator_Last jmin, j = ifp->last_outs(jmin); j >= jmin; --j) {
       Node* s = ifp->last_out(j);   // Get child of IfTrue/IfFalse
-      if( !s->depends_only_on_test() ) {
+      if (s->depends_only_on_test() && igvn->no_dependent_zero_check(s)) {
+        // For control producers.
+        // Do not rewire Div and Mod nodes which could have a zero divisor to avoid skipping their zero check.
+        igvn->replace_input_of(s, 0, data_target); // Move child to data-target
+      } else {
         // Find the control input matching this def-use edge.
         // For Regions it may not be in slot 0.
         uint l;
-        for( l = 0; s->in(l) != ifp; l++ ) { }
+        for (l = 0; s->in(l) != ifp; l++) { }
         igvn->replace_input_of(s, l, ctrl_target);
-      } else {                      // Else, for control producers,
-        igvn->replace_input_of(s, 0, data_target); // Move child to data-target
       }
     } // End for each child of a projection
 
diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp
index 5eb5efa..aa89d47 100644
--- a/src/hotspot/share/opto/loopnode.hpp
+++ b/src/hotspot/share/opto/loopnode.hpp
@@ -1451,7 +1451,6 @@
   // Mark an IfNode as being dominated by a prior test,
   // without actually altering the CFG (and hence IDOM info).
   void dominated_by( Node *prevdom, Node *iff, bool flip = false, bool exclude_loop_predicate = false );
-  bool no_dependent_zero_check(Node* n) const;
 
   // Split Node 'n' through merge point
   Node *split_thru_region( Node *n, Node *region );
diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp
index 8c160c0..54d13cb 100644
--- a/src/hotspot/share/opto/loopopts.cpp
+++ b/src/hotspot/share/opto/loopopts.cpp
@@ -283,7 +283,7 @@
   for (DUIterator_Fast imax, i = dp->fast_outs(imax); i < imax; i++) {
     Node* cd = dp->fast_out(i); // Control-dependent node
     // Do not rewire Div and Mod nodes which could have a zero divisor to avoid skipping their zero check.
-    if (cd->depends_only_on_test() && no_dependent_zero_check(cd)) {
+    if (cd->depends_only_on_test() && _igvn.no_dependent_zero_check(cd)) {
       assert(cd->in(0) == dp, "");
       _igvn.replace_input_of(cd, 0, prevdom);
       set_early_ctrl(cd, false);
@@ -302,25 +302,6 @@
   }
 }
 
-// Check if the type of a divisor of a Div or Mod node includes zero.
-bool PhaseIdealLoop::no_dependent_zero_check(Node* n) const {
-  switch (n->Opcode()) {
-    case Op_DivI:
-    case Op_ModI: {
-      // Type of divisor includes 0?
-      const TypeInt* type_divisor = _igvn.type(n->in(2))->is_int();
-      return (type_divisor->_hi < 0 || type_divisor->_lo > 0);
-    }
-    case Op_DivL:
-    case Op_ModL: {
-      // Type of divisor includes 0?
-      const TypeLong* type_divisor = _igvn.type(n->in(2))->is_long();
-      return (type_divisor->_hi < 0 || type_divisor->_lo > 0);
-    }
-  }
-  return true;
-}
-
 //------------------------------has_local_phi_input----------------------------
 // Return TRUE if 'n' has Phi inputs from its local block and no other
 // block-local inputs (all non-local-phi inputs come from earlier blocks)
diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp
index 03e0d3c..d6929ab 100644
--- a/src/hotspot/share/opto/phaseX.cpp
+++ b/src/hotspot/share/opto/phaseX.cpp
@@ -1659,6 +1659,25 @@
   _table.check_no_speculative_types();
 }
 
+// Check if the type of a divisor of a Div or Mod node includes zero.
+bool PhaseIterGVN::no_dependent_zero_check(Node* n) const {
+  switch (n->Opcode()) {
+    case Op_DivI:
+    case Op_ModI: {
+      // Type of divisor includes 0?
+      const TypeInt* type_divisor = type(n->in(2))->is_int();
+      return (type_divisor->_hi < 0 || type_divisor->_lo > 0);
+    }
+    case Op_DivL:
+    case Op_ModL: {
+      // Type of divisor includes 0?
+      const TypeLong* type_divisor = type(n->in(2))->is_long();
+      return (type_divisor->_hi < 0 || type_divisor->_lo > 0);
+    }
+  }
+  return true;
+}
+
 //=============================================================================
 #ifndef PRODUCT
 uint PhaseCCP::_total_invokes   = 0;
diff --git a/src/hotspot/share/opto/phaseX.hpp b/src/hotspot/share/opto/phaseX.hpp
index f197536..49ae866 100644
--- a/src/hotspot/share/opto/phaseX.hpp
+++ b/src/hotspot/share/opto/phaseX.hpp
@@ -546,6 +546,7 @@
   }
 
   bool is_dominator(Node *d, Node *n) { return is_dominator_helper(d, n, false); }
+  bool no_dependent_zero_check(Node* n) const;
 
 #ifndef PRODUCT
 protected:
diff --git a/test/hotspot/jtreg/compiler/loopopts/TestDivZeroDominatedBy.java b/test/hotspot/jtreg/compiler/loopopts/TestDivZeroDominatedBy.java
new file mode 100644
index 0000000..80b5b55
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/loopopts/TestDivZeroDominatedBy.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @key stress randomness
+ * @bug 8259227
+ * @summary Verify that zero check is executed before division/modulo operation.
+ * @requires vm.compiler2.enabled
+ * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=compiler/loopopts/TestDivZeroDominatedBy::test
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM -XX:StressSeed=917280111 compiler.loopopts.TestDivZeroDominatedBy
+ * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=compiler/loopopts/TestDivZeroDominatedBy::test
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM compiler.loopopts.TestDivZeroDominatedBy
+ */
+
+package compiler.loopopts;
+
+public class TestDivZeroDominatedBy {
+
+    public static int iFld = 1;
+    public static int iFld1 = 2;
+    public static int iFld2 = 3;
+    public static int iArrFld[] = new int[10];
+    public static double dFld = 1.0;
+
+    public static void test() {
+        int x = 1;
+        int y = 2;
+        int z = 3;
+
+        iFld = y;
+        iArrFld[5] += iFld1;
+        int i = 1;
+        do {
+            for (int j = 0; j < 10; j++) {
+                iFld2 += iFld2;
+                iFld1 = iFld2;
+                int k = 1;
+                do {
+                    iArrFld[k] = y;
+                    z = iFld2;
+                    dFld = x;
+                    try {
+                        y = iArrFld[k];
+                        iArrFld[8] = 5;
+                        iFld = (100 / z);
+                    } catch (ArithmeticException a_e) {}
+                } while (++k < 2);
+            }
+        } while (++i < 10);
+    }
+
+    public static void main(String[] strArr) {
+        test();
+    }
+}
+
diff --git a/test/hotspot/jtreg/compiler/loopopts/TestDivZeroWithSplitIf.java b/test/hotspot/jtreg/compiler/loopopts/TestDivZeroWithSplitIf.java
index eff1f1c..c842152 100644
--- a/test/hotspot/jtreg/compiler/loopopts/TestDivZeroWithSplitIf.java
+++ b/test/hotspot/jtreg/compiler/loopopts/TestDivZeroWithSplitIf.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,11 +24,14 @@
 
 /*
  * @test
+ * @key stress randomness
  * @bug 8257822
  * @summary Verify that zero check is executed before division/modulo operation.
  * @requires vm.compiler2.enabled
  * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=compiler/loopopts/TestDivZeroWithSplitIf::test
  *                   -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM -XX:StressSeed=873732072 compiler.loopopts.TestDivZeroWithSplitIf
+ * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=compiler/loopopts/TestDivZeroWithSplitIf::test
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM compiler.loopopts.TestDivZeroWithSplitIf
  */
 
 package compiler.loopopts;