jdk-24/test/hotspot/jtreg/compiler/splitif/TestSplitDivisionThroughPhi.java
Christian Hagedorn 55a97ec879 8336729: C2: Div/Mod nodes without zero check could be split through iv phi of outer loop of long counted loop nest resulting in SIGFPE
Co-authored-by: Emanuel Peter <epeter@openjdk.org>
Reviewed-by: epeter, kvn, thartmann
2024-08-20 15:47:16 +00:00

206 lines
7.6 KiB
Java

/*
* Copyright (c) 2023, 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
* @key stress randomness
* @bug 8299259 8336729
* @requires vm.compiler2.enabled
* @summary Test various cases of divisions/modulo which should not be split through iv phis.
* @run main/othervm -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:LoopUnrollLimit=0 -XX:+StressGCM -XX:StressSeed=884154126
* -XX:CompileCommand=compileonly,compiler.splitif.TestSplitDivisionThroughPhi::*
* compiler.splitif.TestSplitDivisionThroughPhi
*/
/**
* @test
* @key stress randomness
* @bug 8299259 8336729
* @requires vm.compiler2.enabled
* @summary Test various cases of divisions/modulo which should not be split through iv phis.
* @run main/othervm -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:LoopUnrollLimit=0 -XX:+StressGCM
* -XX:CompileCommand=compileonly,compiler.splitif.TestSplitDivisionThroughPhi::*
* compiler.splitif.TestSplitDivisionThroughPhi
*/
/**
* @test
* @key stress randomness
* @bug 8336729
* @requires vm.compiler2.enabled
* @summary Test various cases of divisions/modulo which should not be split through iv phis.
* @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:LoopUnrollLimit=0 -XX:+StressGCM -XX:StressSeed=3434
* -XX:CompileCommand=compileonly,compiler.splitif.TestSplitDivisionThroughPhi::*
* compiler.splitif.TestSplitDivisionThroughPhi
*/
/**
* @test
* @key stress randomness
* @bug 8336729
* @requires vm.compiler2.enabled
* @summary Test various cases of divisions/modulo which should not be split through iv phis.
* @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:LoopUnrollLimit=0 -XX:+StressGCM
* -XX:CompileCommand=compileonly,compiler.splitif.TestSplitDivisionThroughPhi::*
* compiler.splitif.TestSplitDivisionThroughPhi
*/
package compiler.splitif;
public class TestSplitDivisionThroughPhi {
static int iFld;
static long lFld;
static boolean flag;
public static void main(String[] strArr) {
for (int i = 0; i < 5000; i++) {
testPushDivIThruPhi();
testPushDivIThruPhiInChain();
testPushModIThruPhi();
testPushModIThruPhiInChain();
testPushDivLThruPhi();
testPushDivLThruPhiInChain();
testPushModLThruPhi();
testPushModLThruPhiInChain();
testPushDivLThruPhiForOuterLongLoop();
testPushModLThruPhiForOuterLongLoop();
}
}
// Already fixed by JDK-8248552.
static void testPushDivIThruPhi() {
for (int i = 10; i > 1; i -= 2) {
// The Div node is only split in later loop opts phase because the zero divisor check is only removed
// in IGVN after the first loop opts phase.
//
// iv phi i type: [2..10]
// When splitting the DivI through the iv phi, it ends up on the back edge with the trip count decrement
// as input which has type [0..8]. We end up executing a division by zero on the last iteration because
// the DivI it is not pinned to the loop exit test and can freely float above the loop exit check.
iFld = 10 / i;
}
}
// Fixed with JDK-8336729.
static void testPushDivLThruPhiForOuterLongLoop() {
// This loop is first transformed into a LongCountedLoop in the first loop opts phase.
// In the second loop opts phase, the LongCountedLoop is split into an inner and an outer loop. Both get the
// same iv phi type which is [2..10]. Only the inner loop is transformed into a CountedLoopNode while the outer
// loop is still a LoopNode. We run into the same problem as described in testPushDivIThruPhi() when splitting
// the DivL node through the long iv phi of the outer LoopNode.
// The fix for JDK-8299259 only prevents this splitting for CountedLoopNodes. We now extend it to LoopNodes
// in general.
for (long i = 10; i > 1; i -= 2) {
lFld = 10 / i;
}
}
// Same as testPushDivLThruPhiForOuterLongLoop() but for ModL.
static void testPushModLThruPhiForOuterLongLoop() {
for (int i = 10; i > 1; i -= 2) {
iFld = 10 % i;
}
}
// Same as above but with an additional Mul node between the iv phi and the Div node. Both nodes are split through
// the iv phi in one pass of Split If.
static void testPushDivIThruPhiInChain() {
for (int i = 10; i > 1; i -= 2) {
// Empty one iteration loop which is only removed after split if in first loop opts phase. This prevents
// that the Mul node is already split through the iv phi while the Div node cannot be split yet due to
// the zero divisor check which can only be removed in the IGVN after the first loop opts pass.
for (int j = 0; j < 1; j++) {
}
iFld = 10 / (i * 100);
}
}
// Already fixed by JDK-8248552.
static void testPushModIThruPhi() {
for (int i = 10; i > 1; i -= 2) {
iFld = 10 / i;
}
}
// Same as above but with ModI.
static void testPushModIThruPhiInChain() {
for (int i = 10; i > 1; i -= 2) {
for (int j = 0; j < 1; j++) {
}
iFld = 10 / (i * 100);
}
}
// Long cases only trigger since JDK-8256655.
// Same as above but with DivL.
static void testPushDivLThruPhi() {
for (long i = 10; i > 1; i -= 2) {
lFld = 10L / i;
// Loop that is not removed such that we do not transform the outer LongCountedLoop (only done if innermost)
for (int j = 0; j < 10; j++) {
flag = !flag;
}
}
}
// Same as above but with DivL.
static void testPushDivLThruPhiInChain() {
for (long i = 10; i > 1; i -= 2) {
for (int j = 0; j < 1; j++) {
}
lFld = 10L / (i * 100L);
for (int j = 0; j < 10; j++) {
flag = !flag;
}
}
}
// Same as above but with ModL
static void testPushModLThruPhi() {
for (long i = 10; i > 1; i -= 2) {
lFld = 10L % i;
for (int j = 0; j < 10; j++) {
flag = !flag;
}
}
}
// Same as above but with ModL
static void testPushModLThruPhiInChain() {
for (long i = 10; i > 1; i -= 2) {
for (int j = 0; j < 1; j++) {
}
lFld = 10L % (i * 100L);
for (int j = 0; j < 10; j++) {
flag = !flag;
}
}
}
}