8383767: C2: assert(curr_ctrl->in(0)->Opcode() == Op_If) failed: unexpected node MemBarStoreStore

Reviewed-by: vlivanov, aseoane, dlong
This commit is contained in:
Anton Seoane Ampudia 2026-05-29 16:03:18 +00:00 committed by Vladimir Kozlov
parent 3d78846a25
commit 04effb0a19
2 changed files with 49 additions and 35 deletions

View File

@ -505,19 +505,19 @@ bool ConnectionGraph::can_reduce_phi_check_inputs(PhiNode* ophi) const {
// We can reduce the Cmp if it's a comparison between the Phi and a constant.
// I require the 'other' input to be a constant so that I can move the Cmp
// around safely.
bool ConnectionGraph::can_reduce_cmp(Node* n, Node* cmp) const {
bool ConnectionGraph::can_reduce_cmp(PhiNode* phi, Node* cmp) const {
assert(cmp->Opcode() == Op_CmpP || cmp->Opcode() == Op_CmpN, "not expected node: %s", cmp->Name());
Node* left = cmp->in(1);
Node* right = cmp->in(2);
return (left == n || right == n) &&
return (left == phi || right == phi) &&
(left->is_Con() || right->is_Con()) &&
cmp->outcnt() == 1;
}
// We are going to check if any of the SafePointScalarMerge entries
// in the SafePoint reference the Phi that we are checking.
bool ConnectionGraph::has_been_reduced(PhiNode* n, SafePointNode* sfpt) const {
bool ConnectionGraph::has_been_reduced(PhiNode* phi, SafePointNode* sfpt) const {
JVMState *jvms = sfpt->jvms();
for (uint i = jvms->debug_start(); i < jvms->debug_end(); i++) {
@ -525,7 +525,7 @@ bool ConnectionGraph::has_been_reduced(PhiNode* n, SafePointNode* sfpt) const {
if (sfpt_in->is_SafePointScalarMerge()) {
SafePointScalarMergeNode* smerge = sfpt_in->as_SafePointScalarMerge();
Node* nsr_ptr = sfpt->in(smerge->merge_pointer_idx(jvms));
if (nsr_ptr == n) {
if (nsr_ptr == phi) {
return true;
}
}
@ -542,6 +542,8 @@ bool ConnectionGraph::has_been_reduced(PhiNode* n, SafePointNode* sfpt) const {
// - Phi -> CastPP -> SafePoints
// - Phi -> CastPP -> AddP -> Load
bool ConnectionGraph::can_reduce_check_users(Node* n, uint nesting) const {
assert((n->is_Phi() && nesting == 0) || (n->is_CastPP() && nesting > 0),
"invalid node class %s and nesting %d combination", n->Name(), nesting);
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
Node* use = n->fast_out(i);
@ -582,37 +584,21 @@ bool ConnectionGraph::can_reduce_check_users(Node* n, uint nesting) const {
return false;
}
bool is_trivial_control = use->in(0) == nullptr || use->in(0) == n->in(0);
if (!is_trivial_control) {
// If it's not a trivial control then we check if we can reduce the
// CmpP/N used by the If controlling the cast.
if (use->in(0)->is_IfTrue() || use->in(0)->is_IfFalse()) {
Node* iff = use->in(0)->in(0);
// We may have an OpaqueConstantBool node between If and Bool nodes. But we could also have a sub class of IfNode,
// for example, an OuterStripMinedLoopEnd or a Parse Predicate. Bail out in all these cases.
bool can_reduce = (iff->Opcode() == Op_If) && iff->in(1)->is_Bool() && iff->in(1)->in(1)->is_Cmp();
if (can_reduce) {
Node* iff_cmp = iff->in(1)->in(1);
int opc = iff_cmp->Opcode();
can_reduce = (opc == Op_CmpP || opc == Op_CmpN) && can_reduce_cmp(n, iff_cmp);
}
if (!can_reduce) {
#ifndef PRODUCT
if (TraceReduceAllocationMerges) {
tty->print_cr("Can NOT reduce Phi %d on invocation %d. CastPP %d doesn't have simple control.", n->_idx, _invocation, use->_idx);
n->dump(5);
}
#endif
return false;
}
if (!can_reduce_phi_at_castpp(n->as_Phi(), use->as_CastPP())) {
#ifdef ASSERT
if (TraceReduceAllocationMerges) {
tty->print_cr("Can NOT reduce Phi %d on invocation %d. CastPP %d doesn't have simple control.", n->_idx, _invocation, use->_idx);
n->dump(5);
}
#endif
return false;
}
if (!can_reduce_check_users(use, nesting+1)) {
return false;
}
} else if (use->Opcode() == Op_CmpP || use->Opcode() == Op_CmpN) {
if (!can_reduce_cmp(n, use)) {
if (!can_reduce_cmp(n->as_Phi(), use)) {
NOT_PRODUCT(if (TraceReduceAllocationMerges) tty->print_cr("Can NOT reduce Phi %d on invocation %d. CmpP/N %d isn't reducible.", n->_idx, _invocation, use->_idx);)
return false;
}
@ -625,6 +611,33 @@ bool ConnectionGraph::can_reduce_check_users(Node* n, uint nesting) const {
return true;
}
// Returns true if the CastPP's control is simple enough to reduce the Phi:
// 1) no control,
// 2) control is the same Region as the Phi, or
// 3) an IfTrue/IfFalse coming from an CmpP/N between the phi and a constant.
bool ConnectionGraph::can_reduce_phi_at_castpp(PhiNode* phi, CastPPNode* castpp) const {
if (castpp->in(0) == nullptr || castpp->in(0) == phi->in(0)) {
return true;
}
// If it's not a trivial control then we check if we can reduce the
// CmpP/N used by the If controlling the cast.
if (!(castpp->in(0)->is_IfTrue() || castpp->in(0)->is_IfFalse())) {
return false; // Only If control is considered
} else {
Node* iff = castpp->in(0)->in(0);
// We may have an OpaqueConstantBool node between If and Bool nodes. But we could also have a sub class of IfNode,
// for example, an OuterStripMinedLoopEnd or a Parse Predicate. Bail out in all these cases.
if (iff->Opcode() == Op_If && iff->in(1)->is_Bool() && iff->in(1)->in(1)->is_Cmp()) {
Node* iff_cmp = iff->in(1)->in(1);
int opc = iff_cmp->Opcode();
if ((opc == Op_CmpP || opc == Op_CmpN) && can_reduce_cmp(phi, iff_cmp)) {
return true;
}
}
}
return false;
}
// Returns true if: 1) It's profitable to reduce the merge, and 2) The Phi is
// only used in some certain code shapes. Check comments in
// 'can_reduce_phi_inputs' and 'can_reduce_phi_users' for more
@ -878,9 +891,9 @@ Node* ConnectionGraph::split_castpp_load_through_phi(Node* curr_addp, Node* curr
// \|/
// Phi # "Field" Phi
//
void ConnectionGraph::reduce_phi_on_castpp_field_load(Node* curr_castpp, GrowableArray<Node*> &alloc_worklist) {
Node* ophi = curr_castpp->in(1);
assert(ophi->is_Phi(), "Expected this to be a Phi node.");
void ConnectionGraph::reduce_phi_on_castpp_field_load(CastPPNode* curr_castpp, GrowableArray<Node*> &alloc_worklist) {
PhiNode* ophi = curr_castpp->in(1)->as_Phi();
precond(can_reduce_phi_at_castpp(ophi, curr_castpp));
// Identify which base should be used for AddP->Load later when spliting the
// CastPP->Loads through ophi. Three kind of values may be stored in this
@ -1374,7 +1387,7 @@ void ConnectionGraph::reduce_phi(PhiNode* ophi, GrowableArray<Node*> &alloc_work
// splitting CastPPs we make reference to the inputs of the Cmp that is used
// by the If controlling the CastPP.
for (uint i = 0; i < castpps.size(); i++) {
reduce_phi_on_castpp_field_load(castpps.at(i), alloc_worklist);
reduce_phi_on_castpp_field_load(castpps.at(i)->as_CastPP(), alloc_worklist);
_compile->print_method(PHASE_EA_AFTER_PHI_CASTPP_REDUCTION, 6, castpps.at(i));
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2026, 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
@ -609,14 +609,15 @@ private:
Node* specialize_cmp(Node* base, Node* curr_ctrl);
Node* specialize_castpp(Node* castpp, Node* base, Node* current_control);
bool can_reduce_cmp(Node* n, Node* cmp) const;
bool can_reduce_cmp(PhiNode* n, Node* cmp) const;
bool has_been_reduced(PhiNode* n, SafePointNode* sfpt) const;
bool can_reduce_phi(PhiNode* ophi) const;
bool can_reduce_check_users(Node* n, uint nesting) const;
bool can_reduce_phi_check_inputs(PhiNode* ophi) const;
bool can_reduce_phi_at_castpp(PhiNode* phi, CastPPNode* castpp) const;
void reduce_phi_on_field_access(Node* previous_addp, GrowableArray<Node *> &alloc_worklist);
void reduce_phi_on_castpp_field_load(Node* castpp, GrowableArray<Node*> &alloc_worklist);
void reduce_phi_on_castpp_field_load(CastPPNode* castpp, GrowableArray<Node*> &alloc_worklist);
void reduce_phi_on_cmp(Node* cmp);
bool reduce_phi_on_safepoints(PhiNode* ophi);
bool reduce_phi_on_safepoints_helper(Node* ophi, Node* cast, Node* selector, Unique_Node_List& safepoints);