changeset 57357:1a7175456d29

8235452: Strip mined loop verification fails with assert(is_OuterStripMinedLoop()) failed: invalid node class Summary: Do not try to verify strip mining if the strip mined loop is malformed. Reviewed-by: roland, vlivanov
author thartmann
date Wed, 11 Dec 2019 10:42:44 +0100
parents dcf88e5c8c07
children 6cf6761c444e
files src/hotspot/share/opto/loopPredicate.cpp src/hotspot/share/opto/loopnode.cpp src/hotspot/share/opto/loopnode.hpp test/hotspot/jtreg/compiler/loopstripmining/TestDeadOuterStripMinedLoop.java
diffstat 4 files changed, 108 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/opto/loopPredicate.cpp	Mon Dec 09 16:14:16 2019 +0100
+++ b/src/hotspot/share/opto/loopPredicate.cpp	Wed Dec 11 10:42:44 2019 +0100
@@ -1388,9 +1388,8 @@
     // an early loop exit. Try them with profile data.
     while (if_proj_list.size() > 0) {
       Node* proj = if_proj_list.pop();
-      float f = pf.to(proj);
       if (proj->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none) &&
-          f * loop_trip_cnt >= 1) {
+          pf.to(proj) * loop_trip_cnt >= 1) {
         hoisted = loop_predication_impl_helper(loop, proj->as_Proj(), profile_predicate_proj, cl, zero, invar, Deoptimization::Reason_profile_predicate) | hoisted;
       }
     }
--- a/src/hotspot/share/opto/loopnode.cpp	Mon Dec 09 16:14:16 2019 +0100
+++ b/src/hotspot/share/opto/loopnode.cpp	Wed Dec 11 10:42:44 2019 +0100
@@ -944,8 +944,11 @@
   return RegionNode::Ideal(phase, can_reshape);
 }
 
+#ifdef ASSERT
 void LoopNode::verify_strip_mined(int expect_skeleton) const {
-#ifdef ASSERT
+  if (!is_valid_counted_loop()) {
+    return; // Skip malformed counted loop
+  }
   const OuterStripMinedLoopNode* outer = NULL;
   const CountedLoopNode* inner = NULL;
   if (is_strip_mined()) {
@@ -955,6 +958,7 @@
   } else if (is_OuterStripMinedLoop()) {
     outer = this->as_OuterStripMinedLoop();
     inner = outer->unique_ctrl_out()->as_CountedLoop();
+    assert(inner->is_valid_counted_loop(), "OuterStripMinedLoop should have been removed");
     assert(!is_strip_mined(), "outer loop shouldn't be marked strip mined");
   }
   if (inner != NULL || outer != NULL) {
@@ -1024,8 +1028,8 @@
     assert(sfpt->outcnt() == 1, "no data node");
     assert(outer_tail->outcnt() == 1 || !has_skeleton, "no data node");
   }
+}
 #endif
-}
 
 //=============================================================================
 //------------------------------Ideal------------------------------------------
--- a/src/hotspot/share/opto/loopnode.hpp	Mon Dec 09 16:14:16 2019 +0100
+++ b/src/hotspot/share/opto/loopnode.hpp	Wed Dec 11 10:42:44 2019 +0100
@@ -152,7 +152,7 @@
   virtual void dump_spec(outputStream *st) const;
 #endif
 
-  void verify_strip_mined(int expect_skeleton) const;
+  void verify_strip_mined(int expect_skeleton) const NOT_DEBUG_RETURN;
   virtual LoopNode* skip_strip_mined(int expect_skeleton = 1) { return this; }
   virtual IfTrueNode* outer_loop_tail() const { ShouldNotReachHere(); return NULL; }
   virtual OuterStripMinedLoopEndNode* outer_loop_end() const { ShouldNotReachHere(); return NULL; }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/compiler/loopstripmining/TestDeadOuterStripMinedLoop.java	Wed Dec 11 10:42:44 2019 +0100
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2019, 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
+ * @bug 8235452
+ * @library /test/lib /
+ * @summary Test loop strip mining verification with dying outer loop.
+ * @run main/othervm -Xbatch -XX:-TieredCompilation
+ *                   compiler.loopstripmining.TestDeadOuterStripMinedLoop
+ */
+
+package compiler.loopstripmining;
+
+import jdk.test.lib.Asserts;
+
+public class TestDeadOuterStripMinedLoop {
+
+    public static int test(boolean b) {
+        int res = 5000;
+        for (int i = 0; i < 42; i++) {
+            if (!b) {
+                break;
+            }
+            // Strip mined loop
+            while (--res > 0) {
+                if (res < 1) {
+                    throw new RuntimeException("Should not reach here!");
+                }
+            }
+
+            /*
+            After parsing:
+                Loop:
+                    res--;
+                    if (res <= 0) {
+                        goto End;
+                    }
+                    if (res < 1) {  <- Treated as loop exit check (res <= 0)
+                        UncommonTrap();
+                    }
+                goto Loop;
+                End:
+
+            Loop opts convert this into:
+                // Outer strip mined loop
+                do {
+                    // Strip mined loop
+                    do {
+                        res--;
+                        if (res <= 0) {
+                            goto End;
+                        }
+                    } while (res > 0);  <- Always false due to above res <= 0 check
+                    Safepoint()
+                } while (false);
+                UncommonTrap();
+                End:
+
+            The safepoint path dies, because the exit condition of the strip mined loop is always false:
+                // Strip mined loop
+                do {
+                    res--;
+                    if (res <= 0) {
+                        goto End;
+                    }
+                } while (true);
+                End:
+            */
+        }
+        return res;
+    }
+
+    public static void main(String[] args) {
+        for (int i = 0; i < 100; i++) {
+            Asserts.assertEQ(test(true), -41);
+        }
+        Asserts.assertEQ(test(false), 5000);
+    }
+}