From d9946d78bbf75858618b13b2839b535c123df1ec Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Wed, 10 Dec 2025 13:46:49 +0100 Subject: [PATCH 1/2] 8373420: C2: Add true/false_proj*() methods for IfNode as a replacement for proj_out*(true/false) --- src/hotspot/share/opto/castnode.cpp | 6 +++--- src/hotspot/share/opto/castnode.hpp | 2 +- src/hotspot/share/opto/cfgnode.hpp | 22 ++++++++++++++++++++-- src/hotspot/share/opto/ifnode.cpp | 16 +++++++++------- src/hotspot/share/opto/loopTransform.cpp | 18 ++++++++---------- src/hotspot/share/opto/loopUnswitch.cpp | 2 +- src/hotspot/share/opto/loopnode.cpp | 17 ++++++++--------- src/hotspot/share/opto/loopnode.hpp | 2 +- src/hotspot/share/opto/loopopts.cpp | 16 ++++++++-------- src/hotspot/share/opto/macro.cpp | 4 ++-- src/hotspot/share/opto/stringopts.cpp | 2 +- 11 files changed, 62 insertions(+), 45 deletions(-) diff --git a/src/hotspot/share/opto/castnode.cpp b/src/hotspot/share/opto/castnode.cpp index 6d899c1f95025..35ac043b98b58 100644 --- a/src/hotspot/share/opto/castnode.cpp +++ b/src/hotspot/share/opto/castnode.cpp @@ -325,7 +325,7 @@ const Type* CastLLNode::Value(PhaseGVN* phase) const { return widen_type(phase, res, T_LONG); } -bool CastLLNode::is_inner_loop_backedge(ProjNode* proj) { +bool CastLLNode::is_inner_loop_backedge(IfProjNode* proj) { if (proj != nullptr) { Node* ctrl_use = proj->unique_ctrl_out_or_null(); if (ctrl_use != nullptr && ctrl_use->Opcode() == Op_Loop && @@ -344,8 +344,8 @@ bool CastLLNode::cmp_used_at_inner_loop_exit_test(CmpNode* cmp) { for (DUIterator_Fast jmax, j = bol->fast_outs(jmax); j < jmax; j++) { Node* iff = bol->fast_out(j); if (iff->Opcode() == Op_If) { - ProjNode* true_proj = iff->as_If()->proj_out_or_null(true); - ProjNode* false_proj = iff->as_If()->proj_out_or_null(false); + IfTrueNode* true_proj = iff->as_If()->true_proj_or_null(); + IfFalseNode* false_proj = iff->as_If()->false_proj_or_null(); if (is_inner_loop_backedge(true_proj) || is_inner_loop_backedge(false_proj)) { return true; } diff --git a/src/hotspot/share/opto/castnode.hpp b/src/hotspot/share/opto/castnode.hpp index 3c6ade64aa85c..cc53b4bf72727 100644 --- a/src/hotspot/share/opto/castnode.hpp +++ b/src/hotspot/share/opto/castnode.hpp @@ -139,7 +139,7 @@ class CastLLNode: public ConstraintCastNode { virtual const Type* Value(PhaseGVN* phase) const; - static bool is_inner_loop_backedge(ProjNode* proj); + static bool is_inner_loop_backedge(IfProjNode* proj); static bool cmp_used_at_inner_loop_exit_test(CmpNode* cmp); bool used_at_inner_loop_exit_test() const; diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp index bc0b38e2f97ad..828e792a155df 100644 --- a/src/hotspot/share/opto/cfgnode.hpp +++ b/src/hotspot/share/opto/cfgnode.hpp @@ -351,7 +351,7 @@ class IfNode : public MultiBranchNode { static bool is_dominator_unc(CallStaticJavaNode* dom_unc, CallStaticJavaNode* unc); protected: - ProjNode* range_check_trap_proj(int& flip, Node*& l, Node*& r); + IfProjNode* range_check_trap_proj(int& flip, Node*& l, Node*& r) const; Node* Ideal_common(PhaseGVN *phase, bool can_reshape); Node* search_identical(int dist, PhaseIterGVN* igvn); @@ -430,6 +430,24 @@ class IfNode : public MultiBranchNode { static IfNode* make_with_same_profile(IfNode* if_node_profile, Node* ctrl, Node* bol); + IfTrueNode* true_proj() const { + return proj_out(true)->as_IfTrue(); + } + + IfTrueNode* true_proj_or_null() const { + ProjNode* true_proj = proj_out_or_null(true); + return true_proj == nullptr ? nullptr : true_proj->as_IfTrue(); + } + + IfFalseNode* false_proj() const { + return proj_out(false)->as_IfFalse(); + } + + IfFalseNode* false_proj_or_null() const { + ProjNode* false_proj = proj_out_or_null(false); + return false_proj == nullptr ? nullptr : false_proj->as_IfFalse(); + } + virtual int Opcode() const; virtual bool pinned() const { return true; } virtual const Type *bottom_type() const { return TypeTuple::IFBOTH; } @@ -520,7 +538,7 @@ class ParsePredicateNode : public IfNode { // Return the uncommon trap If projection of this Parse Predicate. ParsePredicateUncommonProj* uncommon_proj() const { - return proj_out(0)->as_IfFalse(); + return false_proj(); } Node* uncommon_trap() const; diff --git a/src/hotspot/share/opto/ifnode.cpp b/src/hotspot/share/opto/ifnode.cpp index 83e975b95a26e..763888b65b24c 100644 --- a/src/hotspot/share/opto/ifnode.cpp +++ b/src/hotspot/share/opto/ifnode.cpp @@ -487,7 +487,7 @@ IfNode* IfNode::make_with_same_profile(IfNode* if_node_profile, Node* ctrl, Node // if this IfNode follows a range check pattern return the projection // for the failed path -ProjNode* IfNode::range_check_trap_proj(int& flip_test, Node*& l, Node*& r) { +IfProjNode* IfNode::range_check_trap_proj(int& flip_test, Node*& l, Node*& r) const { if (outcnt() != 2) { return nullptr; } @@ -515,8 +515,10 @@ ProjNode* IfNode::range_check_trap_proj(int& flip_test, Node*& l, Node*& r) { // Flip 1: If (Bool[<] CmpU(l, LoadRange)) ... // Flip 2: If (Bool[<=] CmpU(LoadRange, l)) ... - ProjNode* iftrap = proj_out_or_null(flip_test == 2 ? true : false); - return iftrap; + if (flip_test == 2) { + return true_proj_or_null(); + } + return false_proj_or_null(); } @@ -528,7 +530,7 @@ int RangeCheckNode::is_range_check(Node* &range, Node* &index, jint &offset) { int flip_test = 0; Node* l = nullptr; Node* r = nullptr; - ProjNode* iftrap = range_check_trap_proj(flip_test, l, r); + IfProjNode* iftrap = range_check_trap_proj(flip_test, l, r); if (iftrap == nullptr) { return 0; @@ -1875,8 +1877,8 @@ static IfNode* idealize_test(PhaseGVN* phase, IfNode* iff) { assert(iff->in(0) != nullptr, "If must be live"); if (iff->outcnt() != 2) return nullptr; // Malformed projections. - Node* old_if_f = iff->proj_out(false); - Node* old_if_t = iff->proj_out(true); + IfFalseNode* old_if_f = iff->false_proj(); + IfTrueNode* old_if_t = iff->true_proj(); // CountedLoopEnds want the back-control test to be TRUE, regardless of // whether they are testing a 'gt' or 'lt' condition. The 'gt' condition @@ -2192,7 +2194,7 @@ void ParsePredicateNode::mark_useless(PhaseIterGVN& igvn) { } Node* ParsePredicateNode::uncommon_trap() const { - ParsePredicateUncommonProj* uncommon_proj = proj_out(0)->as_IfFalse(); + ParsePredicateUncommonProj* uncommon_proj = false_proj(); Node* uct_region_or_call = uncommon_proj->unique_ctrl_out(); assert(uct_region_or_call->is_Region() || uct_region_or_call->is_Call(), "must be a region or call uct"); return uct_region_or_call; diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index 5c65103677b2a..4a3debb560fe0 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -87,7 +87,7 @@ void IdealLoopTree::record_for_igvn() { Node* outer_safepoint = l->outer_safepoint(); assert(outer_safepoint != nullptr, "missing piece of strip mined loop"); _phase->_igvn._worklist.push(outer_safepoint); - Node* cle_out = _head->as_CountedLoop()->loopexit()->proj_out(false); + IfFalseNode* cle_out = _head->as_CountedLoop()->loopexit()->false_proj(); assert(cle_out != nullptr, "missing piece of strip mined loop"); _phase->_igvn._worklist.push(cle_out); } @@ -1464,9 +1464,8 @@ void PhaseIdealLoop::insert_pre_post_loops(IdealLoopTree *loop, Node_List &old_n pre_end->_prob = PROB_FAIR; // Find the pre-loop normal exit. - Node* pre_exit = pre_end->proj_out(false); - assert(pre_exit->Opcode() == Op_IfFalse, ""); - IfFalseNode *new_pre_exit = new IfFalseNode(pre_end); + IfFalseNode* pre_exit = pre_end->false_proj(); + IfFalseNode* new_pre_exit = new IfFalseNode(pre_end); _igvn.register_new_node_with_optimizer(new_pre_exit); set_idom(new_pre_exit, pre_end, dd_main_head); set_loop(new_pre_exit, outer_loop->_parent); @@ -1707,8 +1706,7 @@ Node *PhaseIdealLoop::insert_post_loop(IdealLoopTree* loop, Node_List& old_new, //------------------------------ // Step A: Create a new post-Loop. - Node* main_exit = outer_main_end->proj_out(false); - assert(main_exit->Opcode() == Op_IfFalse, ""); + IfFalseNode* main_exit = outer_main_end->false_proj(); int dd_main_exit = dom_depth(main_exit); // Step A1: Clone the loop body of main. The clone becomes the post-loop. @@ -1721,7 +1719,7 @@ Node *PhaseIdealLoop::insert_post_loop(IdealLoopTree* loop, Node_List& old_new, post_head->set_post_loop(main_head); // clone_loop() above changes the exit projection - main_exit = outer_main_end->proj_out(false); + main_exit = outer_main_end->false_proj(); // Reduce the post-loop trip count. CountedLoopEndNode* post_end = old_new[main_end->_idx]->as_CountedLoopEnd(); @@ -1786,7 +1784,7 @@ Node *PhaseIdealLoop::insert_post_loop(IdealLoopTree* loop, Node_List& old_new, // right after the execution of the inner CountedLoop. // We have to make sure that such stores in the post loop have the right memory inputs from the main loop // The moved store node is always attached right after the inner loop exit, and just before the safepoint - const Node* if_false = main_end->proj_out(false); + const IfFalseNode* if_false = main_end->false_proj(); for (DUIterator j = if_false->outs(); if_false->has_out(j); j++) { Node* store = if_false->out(j); if (store->is_Store()) { @@ -3944,7 +3942,7 @@ bool PhaseIdealLoop::intrinsify_fill(IdealLoopTree* lpt) { return false; } - Node* exit = head->loopexit()->proj_out_or_null(0); + IfFalseNode* exit = head->loopexit()->false_proj_or_null(); if (exit == nullptr) { return false; } @@ -3988,7 +3986,7 @@ bool PhaseIdealLoop::intrinsify_fill(IdealLoopTree* lpt) { // If the store is on the backedge, it is not executed in the last // iteration, and we must subtract 1 from the len. - Node* backedge = head->loopexit()->proj_out(1); + IfTrueNode* backedge = head->loopexit()->true_proj(); if (store->in(0) == backedge) { len = new SubINode(len, _igvn.intcon(1)); _igvn.register_new_node_with_optimizer(len); diff --git a/src/hotspot/share/opto/loopUnswitch.cpp b/src/hotspot/share/opto/loopUnswitch.cpp index 287f8354dc1b9..cc83bdda561d0 100644 --- a/src/hotspot/share/opto/loopUnswitch.cpp +++ b/src/hotspot/share/opto/loopUnswitch.cpp @@ -488,7 +488,7 @@ IfTrueNode* PhaseIdealLoop::create_new_if_for_multiversion(IfTrueNode* multivers IfNode* multiversion_if = multiversioning_fast_proj->in(0)->as_If(); Node* entry = multiversion_if->in(0); OpaqueMultiversioningNode* opaque = multiversion_if->in(1)->as_OpaqueMultiversioning(); - IfFalseNode* multiversion_slow_proj = multiversion_if->proj_out(0)->as_IfFalse(); + IfFalseNode* multiversion_slow_proj = multiversion_if->false_proj(); Node* slow_path = multiversion_slow_proj->unique_ctrl_out(); // The slow_loop may still be delayed, and waiting for runtime-checks to be added to the diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 03cc5cbcff662..1dda44a3bbf8c 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -79,11 +79,10 @@ bool LoopNode::is_valid_counted_loop(BasicType bt) const { BaseCountedLoopNode* l = as_BaseCountedLoop(); BaseCountedLoopEndNode* le = l->loopexit_or_null(); if (le != nullptr && - le->proj_out_or_null(1 /* true */) == l->in(LoopNode::LoopBackControl)) { + le->true_proj_or_null() == l->in(LoopNode::LoopBackControl)) { Node* phi = l->phi(); - Node* exit = le->proj_out_or_null(0 /* false */); - if (exit != nullptr && exit->Opcode() == Op_IfFalse && - phi != nullptr && phi->is_Phi() && + IfFalseNode* exit = le->false_proj_or_null(); + if (exit != nullptr && phi != nullptr && phi->is_Phi() && phi->in(LoopNode::LoopBackControl) == l->incr() && le->loopnode() == l && le->stride_is_con()) { return true; @@ -942,7 +941,7 @@ bool PhaseIdealLoop::create_loop_nest(IdealLoopTree* loop, Node_List &old_new) { safepoint = find_safepoint(back_control, x, loop); } - Node* exit_branch = exit_test->proj_out(false); + IfFalseNode* exit_branch = exit_test->false_proj(); Node* entry_control = head->in(LoopNode::EntryControl); // Clone the control flow of the loop to build an outer loop @@ -3087,7 +3086,7 @@ IfFalseNode* OuterStripMinedLoopNode::outer_loop_exit() const { if (le == nullptr) { return nullptr; } - Node* c = le->proj_out_or_null(false); + IfFalseNode* c = le->false_proj_or_null(); if (c == nullptr) { return nullptr; } @@ -3407,7 +3406,7 @@ void OuterStripMinedLoopNode::adjust_strip_mined_loop(PhaseIterGVN* igvn) { return; } - Node* cle_tail = inner_cle->proj_out(true); + IfTrueNode* cle_tail = inner_cle->true_proj(); ResourceMark rm; Node_List old_new; if (cle_tail->outcnt() > 1) { @@ -3549,7 +3548,7 @@ void OuterStripMinedLoopNode::transform_to_counted_loop(PhaseIterGVN* igvn, Phas iloop->replace_node_and_forward_ctrl(outer_le, new_end); } // the backedge of the inner loop must be rewired to the new loop end - Node* backedge = cle->proj_out(true); + IfTrueNode* backedge = cle->true_proj(); igvn->replace_input_of(backedge, 0, new_end); if (iloop != nullptr) { iloop->set_idom(backedge, new_end, iloop->dom_depth(new_end) + 1); @@ -3630,7 +3629,7 @@ const Type* OuterStripMinedLoopEndNode::Value(PhaseGVN* phase) const { bool OuterStripMinedLoopEndNode::is_expanded(PhaseGVN *phase) const { // The outer strip mined loop head only has Phi uses after expansion if (phase->is_IterGVN()) { - Node* backedge = proj_out_or_null(true); + IfTrueNode* backedge = true_proj_or_null(); if (backedge != nullptr) { Node* head = backedge->unique_ctrl_out_or_null(); if (head != nullptr && head->is_OuterStripMinedLoop()) { diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 3b97d76773fa4..ffc283ac94196 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -607,7 +607,7 @@ class OuterStripMinedLoopNode : public LoopNode { virtual SafePointNode* outer_safepoint() const; CountedLoopNode* inner_counted_loop() const { return unique_ctrl_out()->as_CountedLoop(); } CountedLoopEndNode* inner_counted_loop_end() const { return inner_counted_loop()->loopexit(); } - IfFalseNode* inner_loop_exit() const { return inner_counted_loop_end()->proj_out(false)->as_IfFalse(); } + IfFalseNode* inner_loop_exit() const { return inner_counted_loop_end()->false_proj(); } void adjust_strip_mined_loop(PhaseIterGVN* igvn); diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index ee3f138b8afab..773470d92f59c 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -1321,8 +1321,8 @@ bool PhaseIdealLoop::identical_backtoback_ifs(Node *n) { return false; } IfNode* dom_if = dom->as_If(); - Node* proj_true = dom_if->proj_out(1); - Node* proj_false = dom_if->proj_out(0); + IfTrueNode* proj_true = dom_if->true_proj(); + IfFalseNode* proj_false = dom_if->false_proj(); for (uint i = 1; i < region->req(); i++) { if (is_dominator(proj_true, region->in(i))) { @@ -1585,8 +1585,8 @@ bool PhaseIdealLoop::try_merge_identical_ifs(Node* n) { dom_if->in(1)->in(1)->as_SubTypeCheck()->method() != nullptr), "only for subtype checks with profile data attached"); _igvn.replace_input_of(n, 1, dom_if->in(1)); } - ProjNode* dom_proj_true = dom_if->proj_out(1); - ProjNode* dom_proj_false = dom_if->proj_out(0); + IfTrueNode* dom_proj_true = dom_if->true_proj(); + IfFalseNode* dom_proj_false = dom_if->false_proj(); // Now split the IF RegionNode* new_false_region; @@ -1630,10 +1630,10 @@ bool PhaseIdealLoop::try_merge_identical_ifs(Node* n) { // unrelated control dependency. for (uint i = 1; i < new_false_region->req(); i++) { if (is_dominator(dom_proj_true, new_false_region->in(i))) { - dominated_by(dom_proj_true->as_IfProj(), new_false_region->in(i)->in(0)->as_If()); + dominated_by(dom_proj_true, new_false_region->in(i)->in(0)->as_If()); } else { assert(is_dominator(dom_proj_false, new_false_region->in(i)), "bad if"); - dominated_by(dom_proj_false->as_IfProj(), new_false_region->in(i)->in(0)->as_If()); + dominated_by(dom_proj_false, new_false_region->in(i)->in(0)->as_If()); } } return true; @@ -2394,7 +2394,7 @@ void PhaseIdealLoop::clone_outer_loop(LoopNode* head, CloneLoopMode mode, IdealL CountedLoopEndNode* cle = cl->loopexit(); CountedLoopNode* new_cl = old_new[cl->_idx]->as_CountedLoop(); CountedLoopEndNode* new_cle = new_cl->as_CountedLoop()->loopexit_or_null(); - Node* cle_out = cle->proj_out(false); + IfFalseNode* cle_out = cle->false_proj(); Node* new_sfpt = nullptr; Node* new_cle_out = cle_out->clone(); @@ -2691,7 +2691,7 @@ void PhaseIdealLoop::fix_ctrl_uses(const Node_List& body, const IdealLoopTree* l if (use->in(0) == cle) { IfFalseNode* cle_out = use->as_IfFalse(); IfNode* le = cl->outer_loop_end(); - use = le->proj_out(false); + use = le->false_proj(); use_loop = get_loop(use); if (mode == CloneIncludesStripMined) { nnn = old_new[le->_idx]; diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 90602bc2b35da..f88ae74244d70 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -2379,8 +2379,8 @@ void PhaseMacroExpand::expand_subtypecheck_node(SubTypeCheckNode *check) { continue; } - Node* iftrue = iff->as_If()->proj_out(1); - Node* iffalse = iff->as_If()->proj_out(0); + IfTrueNode* iftrue = iff->as_If()->true_proj(); + IfFalseNode* iffalse = iff->as_If()->false_proj(); Node* ctrl = iff->in(0); Node* subklass = nullptr; diff --git a/src/hotspot/share/opto/stringopts.cpp b/src/hotspot/share/opto/stringopts.cpp index 6b98c4ca2b0ee..e499ba932e126 100644 --- a/src/hotspot/share/opto/stringopts.cpp +++ b/src/hotspot/share/opto/stringopts.cpp @@ -255,7 +255,7 @@ void StringConcat::eliminate_unneeded_control() { Compile* C = _stringopts->C; C->gvn_replace_by(n, n->in(0)->in(0)); // get rid of the other projection - C->gvn_replace_by(n->in(0)->as_If()->proj_out(false), C->top()); + C->gvn_replace_by(n->in(0)->as_If()->false_proj(), C->top()); } else if (n->is_Region()) { Node* iff = n->in(1)->in(0); assert(n->req() == 3 && n->in(2)->in(0) == iff, "not a diamond"); From 7951e36dc93775bc0a6a547e4dc5abd93a0cb2da Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Wed, 10 Dec 2025 14:18:13 +0100 Subject: [PATCH 2/2] Fix after merge --- src/hotspot/share/opto/castnode.cpp | 3 +-- src/hotspot/share/opto/castnode.hpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/opto/castnode.cpp b/src/hotspot/share/opto/castnode.cpp index 272c1d4dfc719..998b6a79903ba 100644 --- a/src/hotspot/share/opto/castnode.cpp +++ b/src/hotspot/share/opto/castnode.cpp @@ -313,8 +313,7 @@ void CastIINode::remove_range_check_cast(Compile* C) { } } - -bool CastLLNode::is_inner_loop_backedge(IfProjNode* proj) const { +bool CastLLNode::is_inner_loop_backedge(IfProjNode* proj) { if (proj != nullptr) { Node* ctrl_use = proj->unique_ctrl_out_or_null(); if (ctrl_use != nullptr && ctrl_use->Opcode() == Op_Loop && diff --git a/src/hotspot/share/opto/castnode.hpp b/src/hotspot/share/opto/castnode.hpp index 2ff13e447801f..f22df546f418d 100644 --- a/src/hotspot/share/opto/castnode.hpp +++ b/src/hotspot/share/opto/castnode.hpp @@ -239,7 +239,7 @@ class CastLLNode: public ConstraintCastNode { init_class_id(Class_CastLL); } - static bool is_inner_loop_backedge(ProjNode* proj); + static bool is_inner_loop_backedge(IfProjNode* proj); static bool cmp_used_at_inner_loop_exit_test(CmpNode* cmp); bool used_at_inner_loop_exit_test() const;