jdk/test/hotspot/jtreg/compiler/loopopts/superword/TestMultiversionRemoveUselessSlowLoop.java
Hamlin Li 2b55979595 8352529: RISC-V: enable loopopts tests
Reviewed-by: fyang, luhenry, rehn
2025-03-21 12:07:33 +00:00

151 lines
6.9 KiB
Java

/*
* Copyright (c) 2025, 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.
*/
package compiler.loopopts.superword;
import compiler.lib.ir_framework.*;
/*
* @test
* @bug 8350756
* @summary Test case where the multiversion fast_loop disappears, and we should
* constant fold the multiversion_if, to remove the slow_loop.
* @library /test/lib /
* @run driver compiler.loopopts.superword.TestMultiversionRemoveUselessSlowLoop
*/
public class TestMultiversionRemoveUselessSlowLoop {
public static void main(String[] args) {
TestFramework framework = new TestFramework(TestMultiversionRemoveUselessSlowLoop.class);
// No traps means we cannot use the predicates version for SuperWord / AutoVectorization,
// and instead use multiversioning directly.
framework.addFlags("-XX:-TieredCompilation", "-XX:PerMethodTrapLimit=0");
framework.setDefaultWarmup(0); // simulates Xcomp
framework.start();
}
public static final int SIZE = 20;
public static final int[] a = new int[SIZE];
public static final int[] b = new int[SIZE];
public static final int SIZE2 = 10_000;
public static final int[] a2 = new int[SIZE2];
public static final int[] b2 = new int[SIZE2];
@Test
@IR(counts = {"pre .* multiversion_fast", "= 2", // regular pre-main-post for both loops
"main .* multiversion_fast", "= 2",
"post .* multiversion_fast", "= 2",
"multiversion_delayed_slow", "= 2", // both have the delayed slow_loop
"multiversion", "= 8", // nothing unexpected
IRNode.OPAQUE_MULTIVERSIONING, "= 2"}, // Both multiversion_if are still here
applyIfPlatform = {"64-bit", "true"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"},
phase = CompilePhase.PHASEIDEALLOOP1)
@IR(counts = {"pre .* multiversion_fast", "= 2",
"main .* multiversion_fast", "= 1", // The first main loop is fully unrolled
"post .* multiversion_fast", "= 3", // the second loop is vectorized, and has a vectorized post loop
"multiversion_delayed_slow", "= 1", // As a consequence of the first main loop being removed, we constant fold the multiversion_if
"multiversion", "= 7", // nothing unexpected
IRNode.OPAQUE_MULTIVERSIONING, "= 1"}, // The multiversion_if of the first loop was constant folded, because the main loop disappeared.
applyIfPlatform = {"64-bit", "true"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"},
phase = CompilePhase.PHASEIDEALLOOP_ITERATIONS)
@IR(counts = {"pre .* multiversion_fast.*", ">= 1", // In some cases, the pre loop of the first loop also disappears because it only has a single iteration
"pre .* multiversion_fast.*", "<= 2", // but not in other cases the pre loop of the first loop remains.
"main .* multiversion_fast", "= 1",
"post .* multiversion_fast", "= 3",
"multiversion_delayed_slow", "= 0", // The second loop's multiversion_if was also not used, so it is constant folded after loop opts.
"multiversion", ">= 5", // nothing unexpected
"multiversion", "<= 6", // nothing unexpected
IRNode.OPAQUE_MULTIVERSIONING, "= 0"}, // After loop-opts, we also constant fold the multiversion_if of the second loop, as it is unused.
applyIfPlatform = {"64-bit", "true"},
applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"},
phase = CompilePhase.PRINT_IDEAL)
public static void testIR() {
// This loop is short, and the multiversion_fast main loop eventuall is fully unrolled.
for (int i = 0; i < SIZE; i++) {
a[i] = b[i];
}
// We take this second loop with a larger limit so that loop opts keeps going once the loop
// above is fully optimized. It also gives us a reference where the main loop of the
// multiverion fast_loop does not disappear.
for (int i = 0; i < SIZE2; i++) {
a2[i] = b2[i];
}
}
static long instanceCount;
static int iFld;
static int iFld1;
// The inner loop is Multiversioned, then PreMainPost and Unroll.
// Eventually, both the fast and slow loops (pre main and post) disappear,
// and leave us with a simple if-diamond using the multiversion_if.
//
// Verification code in PhaseIdealLoop::conditional_move finds this diamond
// and expects a Bool but gets an OpaqueMultiversioning instead.
//
// If we let the multiversion_if constant fold soon after the main fast loop
// disappears, then this issue does not occur any more.
@Test
public static void testCrash() {
boolean b2 = true;
for (int i = 0; i < 1000; i++) {
for (int i21 = 82; i21 > 9; --i21) {
if (b2)
break;
iFld1 = iFld;
b2 = true;
}
instanceCount = iFld1;
}
}
class Unloaded {
static void unloaded() {}
}
static int f;
// The outer loop is eventually Multiversioned, then PreMainPost and Unroll.
// Then the loops disappear during IGVN, and in the next loop-opts phase, the
// OpaqueMultiversioning is marked useless, but then we already run
// PhaseIdealLoop::conditional_move before the next IGVN round, and find a
// useless OpaqueMultiversioning instead of a BoolNode.
@Test
@Arguments(values = { Argument.NUMBER_42 })
static void testCrash2(int y) {
int x = 53446;
for (int i = 12; i < 376; i++) {
if (x != 0) {
// Uncommon trap because the class is not yet loaded.
Unloaded.unloaded();
}
for (int k = 1; k < 4; k++) {
y += 1;
}
x += f;
}
}
}