8317349: Randomize order of macro node expansion in C2

Reviewed-by: chagedorn, rcastanedalo, thartmann
This commit is contained in:
Daniel Lundén 2024-02-07 10:01:35 +00:00 committed by Roberto Castañeda Lozano
parent 3bffe223a3
commit 4abb10eb0b
14 changed files with 74 additions and 32 deletions

View File

@ -56,6 +56,9 @@
product(bool, StressIncrementalInlining, false, DIAGNOSTIC, \
"Randomize the incremental inlining decision") \
\
product(bool, StressMacroExpansion, false, DIAGNOSTIC, \
"Randomize macro node expansion order") \
\
product(uint, StressSeed, 0, DIAGNOSTIC, \
"Seed for randomized stress testing (if unset, a random one is " \
"generated). The seed is recorded in the compilation log, if " \

View File

@ -844,7 +844,8 @@ Compile::Compile( ciEnv* ci_env, ciMethod* target, int osr_bci,
// If any phase is randomized for stress testing, seed random number
// generation and log the seed for repeatability.
if (StressLCM || StressGCM || StressIGVN || StressCCP || StressIncrementalInlining) {
if (StressLCM || StressGCM || StressIGVN || StressCCP ||
StressIncrementalInlining || StressMacroExpansion) {
if (FLAG_IS_DEFAULT(StressSeed) || (FLAG_IS_ERGO(StressSeed) && directive->RepeatCompilationOption)) {
_stress_seed = static_cast<uint>(Ticks::now().nanoseconds());
FLAG_SET_ERGO(StressSeed, _stress_seed);
@ -2451,12 +2452,13 @@ void Compile::Optimize() {
{
TracePhase tp("macroExpand", &timers[_t_macroExpand]);
print_method(PHASE_BEFORE_MACRO_EXPANSION, 3);
PhaseMacroExpand mex(igvn);
if (mex.expand_macro_nodes()) {
assert(failing(), "must bail out w/ explicit message");
return;
}
print_method(PHASE_MACRO_EXPANSION, 2);
print_method(PHASE_AFTER_MACRO_EXPANSION, 2);
}
{
@ -5121,6 +5123,16 @@ void CloneMap::dump(node_idx_t key, outputStream* st) const {
}
}
void Compile::shuffle_macro_nodes() {
if (_macro_nodes.length() < 2) {
return;
}
for (uint i = _macro_nodes.length() - 1; i >= 1; i--) {
uint j = C->random() % (i + 1);
swap(_macro_nodes.at(i), _macro_nodes.at(j));
}
}
// Move Allocate nodes to the start of the list
void Compile::sort_macro_nodes() {
int count = macro_count();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -794,6 +794,7 @@ private:
void remove_useless_unstable_if_traps(Unique_Node_List &useful);
void process_for_unstable_if_traps(PhaseIterGVN& igvn);
void shuffle_macro_nodes();
void sort_macro_nodes();
void mark_parse_predicate_nodes_useless(PhaseIterGVN& igvn);

View File

@ -2430,6 +2430,9 @@ void PhaseMacroExpand::eliminate_macro_nodes() {
//------------------------------expand_macro_nodes----------------------
// Returns true if a failure occurred.
bool PhaseMacroExpand::expand_macro_nodes() {
if (StressMacroExpansion) {
C->shuffle_macro_nodes();
}
// Last attempt to eliminate macro nodes.
eliminate_macro_nodes();
if (C->failing()) return true;
@ -2511,6 +2514,9 @@ bool PhaseMacroExpand::expand_macro_nodes() {
}
assert(!success || (C->macro_count() == (old_macro_count - 1)), "elimination must have deleted one node from macro list");
progress = progress || success;
if (success) {
C->print_method(PHASE_AFTER_MACRO_EXPANSION_STEP, 5, n);
}
}
}
@ -2571,6 +2577,7 @@ bool PhaseMacroExpand::expand_macro_nodes() {
}
assert(C->macro_count() == (old_macro_count - 1), "expansion must have deleted one node from macro list");
if (C->failing()) return true;
C->print_method(PHASE_AFTER_MACRO_EXPANSION_STEP, 5, n);
// Clean up the graph so we're less likely to hit the maximum node
// limit
@ -2613,6 +2620,7 @@ bool PhaseMacroExpand::expand_macro_nodes() {
}
assert(C->macro_count() < macro_count, "must have deleted a node from macro list");
if (C->failing()) return true;
C->print_method(PHASE_AFTER_MACRO_EXPANSION_STEP, 5, n);
// Clean up the graph so we're less likely to hit the maximum node
// limit

View File

@ -84,7 +84,9 @@
flags(CCP1, "PhaseCCP 1") \
flags(ITER_GVN2, "Iter GVN 2") \
flags(PHASEIDEALLOOP_ITERATIONS, "PhaseIdealLoop iterations") \
flags(MACRO_EXPANSION, "Macro expand") \
flags(BEFORE_MACRO_EXPANSION , "Before Macro Expansion") \
flags(AFTER_MACRO_EXPANSION_STEP, "After Macro Expansion Step") \
flags(AFTER_MACRO_EXPANSION, "After Macro Expansion") \
flags(BARRIER_EXPANSION, "Barrier expand") \
flags(OPTIMIZE_FINISHED, "Optimize finished") \
flags(BEFORE_MATCHING, "Before matching") \

View File

@ -31,7 +31,7 @@ Ideal graphs are dumped at the following points:
* `N=2`: additionally, after every major phase
* `N=3`: additionally, after every minor phase
* `N=4`: additionally, after every loop optimization
* `N=5`: additionally, after every effective IGVN step (slow)
* `N=5`: additionally, after every effective IGVN and every macro expansion step (slow)
* `N=6`: additionally, after parsing every bytecode (very slow)
By default the JVM expects that it will connect to a visualizer on the local

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 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
@ -24,7 +24,7 @@
/*
* @test
* @key stress randomness
* @bug 8252219 8256535
* @bug 8252219 8256535 8317349
* @requires vm.compiler2.enabled
* @summary Tests that different combinations of stress options and
* -XX:StressSeed=N are accepted.
@ -44,6 +44,10 @@
* compiler.arguments.TestStressOptions
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM -XX:StressSeed=42
* compiler.arguments.TestStressOptions
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+StressMacroExpansion
* compiler.arguments.TestStressOptions
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+StressMacroExpansion -XX:StressSeed=42
* compiler.arguments.TestStressOptions
*/
package compiler.arguments;

View File

@ -70,7 +70,7 @@ public class ProfileAtTypeCheck {
@Test
@IR(phase = { CompilePhase.AFTER_PARSING }, counts = { IRNode.SUBTYPE_CHECK, "1" })
@IR(phase = { CompilePhase.MACRO_EXPANSION }, counts = { IRNode.CMP_P, "2", IRNode.LOAD_KLASS_OR_NKLASS, "2" })
@IR(phase = { CompilePhase.AFTER_MACRO_EXPANSION }, counts = { IRNode.CMP_P, "2", IRNode.LOAD_KLASS_OR_NKLASS, "2" })
public static void test1(Object o) {
dummyA((A)o);
}
@ -103,7 +103,7 @@ public class ProfileAtTypeCheck {
@Test
@IR(phase = { CompilePhase.AFTER_PARSING }, counts = { IRNode.SUBTYPE_CHECK, "1" })
@IR(phase = { CompilePhase.MACRO_EXPANSION }, counts = { IRNode.CMP_P, "2", IRNode.LOAD_KLASS_OR_NKLASS, "1" })
@IR(phase = { CompilePhase.AFTER_MACRO_EXPANSION }, counts = { IRNode.CMP_P, "2", IRNode.LOAD_KLASS_OR_NKLASS, "1" })
public static void test3(Object o) {
if (o instanceof B) {
dummyB((B)o);
@ -121,7 +121,7 @@ public class ProfileAtTypeCheck {
// full subtype check
@Test
@IR(phase = { CompilePhase.AFTER_PARSING }, counts = { IRNode.SUBTYPE_CHECK, "1" })
@IR(phase = { CompilePhase.MACRO_EXPANSION }, counts = { IRNode.CMP_P, "3", IRNode.LOAD_KLASS_OR_NKLASS, "2", IRNode.PARTIAL_SUBTYPE_CHECK, "1" })
@IR(phase = { CompilePhase.AFTER_MACRO_EXPANSION }, counts = { IRNode.CMP_P, "3", IRNode.LOAD_KLASS_OR_NKLASS, "2", IRNode.PARTIAL_SUBTYPE_CHECK, "1" })
public static void test4(Object o) {
dummyI((I)o);
}
@ -138,7 +138,7 @@ public class ProfileAtTypeCheck {
// full subtype check + profile use for success path
@Test
@IR(phase = { CompilePhase.AFTER_PARSING }, counts = { IRNode.SUBTYPE_CHECK, "1" })
@IR(phase = { CompilePhase.MACRO_EXPANSION }, counts = { IRNode.CMP_P, "5", IRNode.LOAD_KLASS_OR_NKLASS, "2", IRNode.PARTIAL_SUBTYPE_CHECK, "1" })
@IR(phase = { CompilePhase.AFTER_MACRO_EXPANSION }, counts = { IRNode.CMP_P, "5", IRNode.LOAD_KLASS_OR_NKLASS, "2", IRNode.PARTIAL_SUBTYPE_CHECK, "1" })
public static void test5(Object o) {
dummyI((I)o);
}
@ -153,7 +153,7 @@ public class ProfileAtTypeCheck {
// Check primary super
@Test
@IR(phase = { CompilePhase.AFTER_PARSING }, counts = { IRNode.SUBTYPE_CHECK, "1" })
@IR(phase = { CompilePhase.MACRO_EXPANSION }, counts = { IRNode.CMP_P, "2", IRNode.LOAD_KLASS_OR_NKLASS, "2" }, failOn = { IRNode.PARTIAL_SUBTYPE_CHECK })
@IR(phase = { CompilePhase.AFTER_MACRO_EXPANSION }, counts = { IRNode.CMP_P, "2", IRNode.LOAD_KLASS_OR_NKLASS, "2" }, failOn = { IRNode.PARTIAL_SUBTYPE_CHECK })
public static void test6(Object o) {
dummyA((A)o);
}
@ -169,7 +169,7 @@ public class ProfileAtTypeCheck {
// full subtype check + profile use for both success and failure paths
@Test
@IR(phase = { CompilePhase.AFTER_PARSING }, counts = { IRNode.SUBTYPE_CHECK, "1" })
@IR(phase = { CompilePhase.MACRO_EXPANSION }, counts = { IRNode.CMP_P, "5", IRNode.LOAD_KLASS_OR_NKLASS, "2", IRNode.PARTIAL_SUBTYPE_CHECK, "1" })
@IR(phase = { CompilePhase.AFTER_MACRO_EXPANSION }, counts = { IRNode.CMP_P, "5", IRNode.LOAD_KLASS_OR_NKLASS, "2", IRNode.PARTIAL_SUBTYPE_CHECK, "1" })
public static boolean test7(Object o) {
return o instanceof I;
}
@ -184,7 +184,7 @@ public class ProfileAtTypeCheck {
// full subtype check + profile use for success path (profile has unrecorded entries)
@Test
@IR(phase = { CompilePhase.AFTER_PARSING }, counts = { IRNode.SUBTYPE_CHECK, "1" })
@IR(phase = { CompilePhase.MACRO_EXPANSION }, counts = { IRNode.CMP_P, "5", IRNode.LOAD_KLASS_OR_NKLASS, "2", IRNode.PARTIAL_SUBTYPE_CHECK, "1" })
@IR(phase = { CompilePhase.AFTER_MACRO_EXPANSION }, counts = { IRNode.CMP_P, "5", IRNode.LOAD_KLASS_OR_NKLASS, "2", IRNode.PARTIAL_SUBTYPE_CHECK, "1" })
public static void test8(Object o) {
dummyI((I)o);
}
@ -394,7 +394,7 @@ public class ProfileAtTypeCheck {
// full subtype check + profile use for success path
@Test
@IR(phase = { CompilePhase.AFTER_PARSING }, counts = { IRNode.SUBTYPE_CHECK, "1" })
@IR(phase = { CompilePhase.MACRO_EXPANSION }, counts = { IRNode.CMP_P, "5", IRNode.LOAD_KLASS_OR_NKLASS, "2", IRNode.PARTIAL_SUBTYPE_CHECK, "1" })
@IR(phase = { CompilePhase.AFTER_MACRO_EXPANSION }, counts = { IRNode.CMP_P, "5", IRNode.LOAD_KLASS_OR_NKLASS, "2", IRNode.PARTIAL_SUBTYPE_CHECK, "1" })
public static void test15(Object o) {
array[0] = o;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 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
@ -39,6 +39,7 @@ import jdk.test.lib.process.ProcessTools;
* @run driver compiler.debug.TestGenerateStressSeed StressGCM
* @run driver compiler.debug.TestGenerateStressSeed StressIGVN
* @run driver compiler.debug.TestGenerateStressSeed StressCCP
* @run driver compiler.debug.TestGenerateStressSeed StressMacroExpansion
*/
public class TestGenerateStressSeed {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 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
@ -30,22 +30,22 @@ import jdk.test.lib.Asserts;
/*
* @test
* @key stress randomness
* @bug 8252219 8256535
* @bug 8252219 8256535 8317349
* @requires vm.debug == true & vm.compiler2.enabled
* @summary Tests that stress compilations with the same seed yield the same
* IGVN and CCP traces.
* IGVN, CCP, and macro expansion traces.
* @library /test/lib /
* @run driver compiler.debug.TestStressIGVNAndCCP
* @run driver compiler.debug.TestStress
*/
public class TestStressIGVNAndCCP {
public class TestStress {
static String phaseTrace(String stressOption, String traceOption,
int stressSeed) throws Exception {
String className = TestStressIGVNAndCCP.class.getName();
String className = TestStress.class.getName();
String[] procArgs = {
"-Xcomp", "-XX:-TieredCompilation", "-XX:-Inline", "-XX:+CICountNative",
"-XX:CompileOnly=" + className + "::sum", "-XX:+" + traceOption,
"-XX:CompileOnly=" + className + "::sum", "-XX:" + traceOption,
"-XX:+" + stressOption, "-XX:StressSeed=" + stressSeed,
className, "10"};
ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(procArgs);
@ -55,11 +55,17 @@ public class TestStressIGVNAndCCP {
}
static String igvnTrace(int stressSeed) throws Exception {
return phaseTrace("StressIGVN", "TraceIterativeGVN", stressSeed);
return phaseTrace("StressIGVN", "+TraceIterativeGVN", stressSeed);
}
static String ccpTrace(int stressSeed) throws Exception {
return phaseTrace("StressCCP", "TracePhaseCCP", stressSeed);
return phaseTrace("StressCCP", "+TracePhaseCCP", stressSeed);
}
static String macroExpansionTrace(int stressSeed) throws Exception {
return phaseTrace("StressMacroExpansion",
"CompileCommand=PrintIdealPhase,*::*,AFTER_MACRO_EXPANSION_STEP",
stressSeed);
}
static void sum(int n) {
@ -75,6 +81,8 @@ public class TestStressIGVNAndCCP {
"got different IGVN traces for the same seed");
Asserts.assertEQ(ccpTrace(s), ccpTrace(s),
"got different CCP traces for the same seed");
Asserts.assertEQ(macroExpansionTrace(s), macroExpansionTrace(s),
"got different macro expansion traces for the same seed");
}
} else if (args.length > 0) {
sum(Integer.parseInt(args[0]));

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@ -95,7 +95,9 @@ public enum CompilePhase {
CCP1("PhaseCCP 1"),
ITER_GVN2("Iter GVN 2"),
PHASEIDEALLOOP_ITERATIONS("PhaseIdealLoop iterations"),
MACRO_EXPANSION("Macro expand"),
BEFORE_MACRO_EXPANSION("Before Macro Expansion"),
AFTER_MACRO_EXPANSION_STEP("After Macro Expansion Step"),
AFTER_MACRO_EXPANSION("After Macro Expansion"),
BARRIER_EXPANSION("Barrier expand"),
OPTIMIZE_FINISHED("Optimize finished"),
PRINT_IDEAL("PrintIdeal"),

View File

@ -2233,7 +2233,7 @@ public class IRNode {
*/
private static void fromMacroToBeforeMatching(String irNodePlaceholder, String regex) {
IR_NODE_MAPPINGS.put(irNodePlaceholder, new SinglePhaseRangeEntry(CompilePhase.PRINT_IDEAL, regex,
CompilePhase.MACRO_EXPANSION,
CompilePhase.AFTER_MACRO_EXPANSION,
CompilePhase.BEFORE_MATCHING));
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 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
@ -298,6 +298,7 @@ public class CtwRunner {
"-XX:+StressGCM",
"-XX:+StressIGVN",
"-XX:+StressCCP",
"-XX:+StressMacroExpansion",
// StressSeed is uint
"-XX:StressSeed=" + Math.abs(rng.nextInt())));

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 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
@ -1095,11 +1095,11 @@ class BadIRNodeForPhase {
@Test
@FailCount(4)
@IR(failOn = IRNode.ALLOC, phase = {CompilePhase.FINAL_CODE, CompilePhase.MACRO_EXPANSION})
@IR(failOn = IRNode.ALLOC, phase = {CompilePhase.FINAL_CODE, CompilePhase.AFTER_MACRO_EXPANSION})
@IR(failOn = IRNode.ALLOC, phase = CompilePhase.PRINT_IDEAL)
@IR(failOn = IRNode.ALLOC, phase = {CompilePhase.ITER_GVN1, CompilePhase.AFTER_PARSING,
CompilePhase.PRINT_OPTO_ASSEMBLY}) // works
@IR(failOn = IRNode.ALLOC_ARRAY, phase = {CompilePhase.FINAL_CODE, CompilePhase.MACRO_EXPANSION})
@IR(failOn = IRNode.ALLOC_ARRAY, phase = {CompilePhase.FINAL_CODE, CompilePhase.AFTER_MACRO_EXPANSION})
@IR(failOn = IRNode.ALLOC_ARRAY, phase = CompilePhase.PRINT_IDEAL)
@IR(failOn = IRNode.ALLOC_ARRAY, phase = {CompilePhase.ITER_GVN1, CompilePhase.AFTER_PARSING,
CompilePhase.PRINT_OPTO_ASSEMBLY}) // works