Blob Blame Raw
# HG changeset patch
# User roland
# Date 1590664914 -7200
#      Thu May 28 13:21:54 2020 +0200
# Node ID 516c889e7582598020e49ed62bcf77871fe315d8
# Parent  b2e6516f67ff98224f14e65beb944ddb04b24548
8245714: "Bad graph detected in build_loop_late" when loads are pinned on loop limit check uncommon branch
Reviewed-by: thartmann

diff --git a/src/hotspot/share/opto/loopPredicate.cpp b/src/hotspot/share/opto/loopPredicate.cpp
--- a/src/hotspot/share/opto/loopPredicate.cpp
+++ b/src/hotspot/share/opto/loopPredicate.cpp
@@ -111,6 +111,9 @@
     CallNode* call = rgn->as_Call();
     IdealLoopTree* loop = get_loop(call);
     rgn = new RegionNode(1);
+    Node* uncommon_proj_orig = uncommon_proj;
+    uncommon_proj = uncommon_proj->clone()->as_Proj();
+    register_control(uncommon_proj, loop, iff);
     rgn->add_req(uncommon_proj);
     register_control(rgn, loop, uncommon_proj);
     _igvn.replace_input_of(call, 0, rgn);
@@ -118,13 +121,9 @@
     if (_idom != NULL) {
       set_idom(call, rgn, dom_depth(rgn));
     }
-    for (DUIterator_Fast imax, i = uncommon_proj->fast_outs(imax); i < imax; i++) {
-      Node* n = uncommon_proj->fast_out(i);
-      if (n->is_Load() || n->is_Store()) {
-        _igvn.replace_input_of(n, 0, rgn);
-        --i; --imax;
-      }
-    }
+    // Move nodes pinned on the projection or whose control is set to
+    // the projection to the region.
+    lazy_replace(uncommon_proj_orig, rgn);
   } else {
     // Find region's edge corresponding to uncommon_proj
     for (; proj_index < rgn->req(); proj_index++)
diff --git a/test/hotspot/jtreg/compiler/loopopts/TestBadControlLoopLimitCheck.java b/test/hotspot/jtreg/compiler/loopopts/TestBadControlLoopLimitCheck.java
new file mode 100644
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/loopopts/TestBadControlLoopLimitCheck.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2020, Red Hat, Inc. 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 8245714
+ * @requires vm.compiler2.enabled
+ * @summary "Bad graph detected in build_loop_late" when loads are pinned on loop limit check uncommon branch
+ *
+ * @run main/othervm -XX:-BackgroundCompilation -XX:ArrayCopyLoadStoreMaxElem=0 TestBadControlLoopLimitCheck
+ */
+
+public class TestBadControlLoopLimitCheck {
+    public static void main(String[] args) {
+        int[] int_array = {0, 0};
+        A[] obj_array = {new A(), new A()};
+        for (int i = 0; i < 20_000; i++) {
+            test1(int_array, 0, 10, false);
+            test_helper(42);
+            test2(obj_array, 0, 10, false);
+        }
+    }
+
+    private static int test1(int[] a, int start, int stop, boolean flag) {
+        int[] b = new int[2]; // non escaping allocation
+        System.arraycopy(a, 0, b, 0, 2); // optimized out
+        int v = 1;
+        int j = 0;
+        for (; j < 10; j++);
+        int inc = test_helper(j); // delay transformation to counted loop
+        // loop limit check here has loads pinned on unc branch
+        for (int i = start; i < stop; i += inc) {
+            v *= 2;
+        }
+        if (flag) {
+            v += b[0] + b[1];
+        }
+        return v;
+    }
+
+    private static int test2(A[] a, int start, int stop, boolean flag) {
+        A[] b = new A[2]; // non escaping allocation
+        System.arraycopy(a, 0, b, 0, 2); // optimized out
+        int v = 1;
+        int j = 0;
+        for (; j < 10; j++);
+        int inc = test_helper(j); // delay transformation to counted loop
+        // loop limit check here has loads pinned on unc branch
+        for (int i = start; i < stop; i += inc) {
+            v *= 2;
+        }
+        if (flag) {
+            v += b[0].f + b[1].f;
+        }
+        return v;
+    }
+
+    static class A {
+        int f;
+    }
+
+    static int test_helper(int j) {
+        return j == 10 ? 10 : 1;
+    }
+}