From 7e0a4ed6292586772c23292dbdd67ed1db5c12f7 Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Mon, 15 Jan 2024 12:16:10 +0000 Subject: [PATCH] 8323101: C2: assert(n->in(0) == nullptr) failed: divisions with zero check should already have bailed out earlier in split-if Reviewed-by: kvn, thartmann --- src/hotspot/share/opto/loopopts.cpp | 6 +- .../TestSplitDivThroughPhiWithControl.java | 210 ++++++++++++++++++ 2 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/compiler/splitif/TestSplitDivThroughPhiWithControl.java diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index 79ab0de8322..80a3d1a072b 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -287,7 +287,11 @@ bool PhaseIdealLoop::cannot_split_division(const Node* n, const Node* region) co return false; } - assert(n->in(0) == nullptr, "divisions with zero check should already have bailed out earlier in split-if"); + if (n->in(0) != nullptr) { + // Cannot split through phi if Div or Mod node has a control dependency to a zero check. + return true; + } + Node* divisor = n->in(2); return is_divisor_counted_loop_phi(divisor, region) && loop_phi_backedge_type_contains_zero(divisor, zero); diff --git a/test/hotspot/jtreg/compiler/splitif/TestSplitDivThroughPhiWithControl.java b/test/hotspot/jtreg/compiler/splitif/TestSplitDivThroughPhiWithControl.java new file mode 100644 index 00000000000..28e4db334f5 --- /dev/null +++ b/test/hotspot/jtreg/compiler/splitif/TestSplitDivThroughPhiWithControl.java @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2024, 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 id=normal + * @bug 8323101 + * @summary Test split_thru_phi with pinned divisions/modulo that have phi as inputs. + * @run main/othervm -Xbatch + * -XX:CompileCommand=compileonly,compiler.splitif.TestSplitDivThroughPhiWithControl::* + * compiler.splitif.TestSplitDivThroughPhiWithControl + */ + +/* + * @test id=fuzzer + * @bug 8323101 + * @summary Test split_thru_phi with pinned divisions/modulo that have phi as inputs. + * @run main/othervm -Xbatch -XX:PerMethodTrapLimit=0 + * -XX:CompileCommand=compileonly,compiler.splitif.TestSplitDivThroughPhiWithControl::* + * compiler.splitif.TestSplitDivThroughPhiWithControl + */ + +package compiler.splitif; + +public class TestSplitDivThroughPhiWithControl { + static int divisorInt = 34; + static int iFld; + static int x; + static int y; + static long divisorLong = 34L; + static long lFld; + static long lFld2; + static long lFld3; + static boolean flag; + + static int[] iArr = new int[400]; + + public static void main(String[] strArr) { + iArr[0] = 52329; + for (int i = 0; i < 10000; i++) { + flag = i % 3 == 0; // Avoid unstable if trap + divisorInt = i % 2 == 0 ? 0 : 23; // Avoid div by zero trap + divisorLong = divisorInt; // Avoid div by zero trap + try { + testIntDiv(); + } catch (ArithmeticException e) { + // Expected. + } + + try { + testIntMod(); + } catch (ArithmeticException e) { + // Expected. + } + + try { + testLongDiv(); // Currently does not trigger due to JDK-8323652 + } catch (ArithmeticException e) { + // Expected. + } + + try { + testLongMod(); // Currently does not trigger due to JDK-8323652 + } catch (ArithmeticException e) { + // Expected. + } + + testFuzzer(); + } + } + + static void testIntDiv() { + int a; + + for (int j = 0; j < 100; j++) { + y += 5; + int sub = j - 3; // AddI + int div = (sub / divisorInt); // DivI with AddI input + + if (flag) { + a = y; + } else { + a = 2; + } + // Region + + // Use StoreI with AddI input. Store needs to be split through Region in Split-If which is done together + // with AddI. + iFld = sub; + + if (a < 3) { // If that's split in Split-If + // Use of DivI -> after Split-If, DivI gets a Phi input that merges the split AddI nodes. + // -> triggers assert that we should not find pinned div nodes in cannot_split_division(). + x = div; + } + } + } + + // Same as testIntDiv() but with ModI + static void testIntMod() { + int a; + + for (int j = 0; j < 100; j++) { + y += 5; + int sub = j - 3; + int mod = (sub % divisorInt); + + if (flag) { + a = y; + } else { + a = 2; + } + + iFld = sub; + + if (a < 3) { + x = mod; // Only StoreI visited first but not mod since it's an input + } + } + } + + // Same as testIntDiv() but with DivL + static void testLongDiv() { + long a; + + for (int j = 0; j < 100; j++) { + y += 5; + long sub = j - 3; + long div = (sub / divisorLong); + + if (flag) { + a = lFld2; + } else { + a = 2; + } + + lFld = sub; + + if (a < 3) { + lFld3 = div; + } + } + } + + + // Same as testIntDiv() but with ModL + static void testLongMod() { + long a; + + for (long j = 0; j < 100; j++) { + lFld2 += 5; + long sub = j - 3; + long mod = (sub % divisorLong); + + if (flag) { + a = lFld2; + } else { + a = 2; + } + + lFld = sub; + + if (a < 3) { + lFld3 = mod; // Only StoreI visited first but not mod since it's an input + } + } + } + + // Original fuzzer crash + static void testFuzzer() { + int i19, i21 = 4928, i23 = 14; + for (int i = 5; i < 100; i++) { + i19 = i23; + int j = 1; + while (true) { + try { + i21 = (iArr[0] / 34); + i23 = (j % i21); + } catch (ArithmeticException a_e) { + } + iArr = iArr; + iFld = i21; + iArr[1] += 5; + if (j == 1000) { + break; + } + j++; + } + } + } +}