Check hash before and after Ideal call and fix phinode

This commit is contained in:
Benoît Maillard 2026-01-14 15:06:19 +01:00
parent 578204f8c4
commit d0e27f15f4
5 changed files with 24 additions and 5 deletions

View File

@ -694,7 +694,9 @@
"Print progress during Iterative Global Value Numbering") \
\
develop(uint, VerifyIterativeGVN, 0, \
"Verify Iterative Global Value Numbering =EDCBA, with:" \
"Verify Iterative Global Value Numbering =FEDCBA, with:" \
" F: verify Node::Ideal does not return nullptr if the node" \
"hash has changed" \
" E: verify node specific invariants" \
" D: verify Node::Identity did not miss opportunities" \
" C: verify Node::Ideal did not miss opportunities" \

View File

@ -2243,7 +2243,7 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) {
PhaseIterGVN* igvn = phase->is_IterGVN();
if (wait_for_cast_input_igvn(igvn)) {
igvn->_worklist.push(this);
return nullptr;
return progress;
}
uncasted = true;
uin = unique_input(phase, true);
@ -2320,6 +2320,7 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) {
PhaseIterGVN* igvn = phase->is_IterGVN();
for (uint i = 1; i < req(); i++) {
set_req_X(i, cast, igvn);
progress = this;
}
uin = cast;
}
@ -2338,7 +2339,7 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) {
#endif
// Identity may not return the expected uin, if it has to wait for the region, in irreducible case
assert(ident == uin || ident->is_top() || must_wait_for_region_in_irreducible_loop(phase), "Identity must clean this up");
return nullptr;
return progress;
}
Node* opt = nullptr;
@ -2529,7 +2530,7 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) {
// Phi references itself through all other inputs then splitting the
// Phi through memory merges would create dead loop at later stage.
if (ii == top) {
return nullptr; // Delay optimization until graph is cleaned.
return progress; // Delay optimization until graph is cleaned.
}
if (ii->is_MergeMem()) {
MergeMemNode* n = ii->as_MergeMem();

View File

@ -2126,9 +2126,15 @@ Node *PhaseIterGVN::transform_old(Node* n) {
DEBUG_ONLY(dead_loop_check(k);)
DEBUG_ONLY(bool is_new = (k->outcnt() == 0);)
C->remove_modified_node(k);
#ifndef PRODUCT
uint hash_before = is_verify_Ideal_return() ? k->hash() : 0;
#endif
Node* i = apply_ideal(k, /*can_reshape=*/true);
assert(i != k || is_new || i->outcnt() > 0, "don't return dead nodes");
#ifndef PRODUCT
if (is_verify_Ideal_return()) {
assert(k->outcnt() == 0 || i != nullptr || hash_before == k->hash(), "hash changed after Ideal returned nullptr for %s", k->Name());
}
verify_step(k);
#endif
@ -2152,9 +2158,15 @@ Node *PhaseIterGVN::transform_old(Node* n) {
// Try idealizing again
DEBUG_ONLY(is_new = (k->outcnt() == 0);)
C->remove_modified_node(k);
#ifndef PRODUCT
uint hash_before = is_verify_Ideal_return() ? k->hash() : 0;
#endif
i = apply_ideal(k, /*can_reshape=*/true);
assert(i != k || is_new || (i->outcnt() > 0), "don't return dead nodes");
#ifndef PRODUCT
if (is_verify_Ideal_return()) {
assert(k->outcnt() == 0 || i != nullptr || hash_before == k->hash(), "hash changed after Ideal returned nullptr for %s", k->Name());
}
verify_step(k);
#endif
DEBUG_ONLY(loop_count++;)

View File

@ -621,6 +621,10 @@ public:
// '-XX:VerifyIterativeGVN=10000'
return ((VerifyIterativeGVN % 100000) / 10000) == 1;
}
static bool is_verify_Ideal_return() {
// '-XX:VerifyIterativeGVN=100000'
return ((VerifyIterativeGVN % 1000000) / 100000) == 1;
}
protected:
// Sub-quadratic implementation of '-XX:VerifyIterativeGVN=1' (Use-Def verification).
julong _verify_counter;

View File

@ -306,7 +306,7 @@ JVMFlag::Error TypeProfileLevelConstraintFunc(uint value, bool verbose) {
}
JVMFlag::Error VerifyIterativeGVNConstraintFunc(uint value, bool verbose) {
const int max_modes = 5;
const int max_modes = 6;
uint original_value = value;
for (int i = 0; i < max_modes; i++) {
if (value % 10 > 1) {