8373420: C2: Add true/false_proj*() methods for IfNode as a replacement for proj_out*(true/false)

Reviewed-by: dfenacci, roland, epeter
This commit is contained in:
Christian Hagedorn 2025-12-17 11:17:39 +00:00
parent 9a23f8aa33
commit e4636d69e7
11 changed files with 62 additions and 46 deletions

View File

@ -313,8 +313,7 @@ void CastIINode::remove_range_check_cast(Compile* C) {
}
}
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 &&
@ -333,8 +332,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;
}

View File

@ -239,7 +239,7 @@ public:
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;

View File

@ -354,7 +354,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);
@ -433,6 +433,24 @@ public:
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; }
@ -523,7 +541,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;

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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()) {

View File

@ -607,7 +607,7 @@ public:
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);

View File

@ -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];

View File

@ -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;

View File

@ -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");