https://gcc.gnu.org/g:4fe10ce56c7c0fb47adb789ece804463e09a5534
commit r17-1844-g4fe10ce56c7c0fb47adb789ece804463e09a5534 Author: Konstantinos Eleftheriou <[email protected]> Date: Thu Jun 18 09:48:04 2026 +0200 uninit: Relax PHI def predicate by maybe-undef edge conditions When ifcombine has combined the conditions guarding a definition, the guard that distinguishes the defined value from the undefined one can end up on the maybe-undef incoming edge of the merge PHI rather than on the use's control-dependence chain. The definition-predicate superset test in uninit_analysis::is_use_guarded then fails on that conjunct and a bogus -Wmaybe-uninitialized warning is emitted. When the superset test fails, drop from a copy of the definition predicate any conjunct implied by the incoming-edge condition of every maybe-undef operand, and retry. Such a conjunct cannot make the use unsafe: when it is false the maybe-undef edge is not taken either, so no undefined value reaches the PHI. The edge condition is found by walking up single-predecessor forwarder blocks to the controlling conditional. gcc/ChangeLog: * gimple-predicate-analysis.cc (get_pred_info_from_cond_edge): New function. (predicate::init_from_control_deps): Use it. (predicate::drop_conjuncts_implied_by): New method. (uninit_analysis::is_use_guarded): Retry the superset test after relaxing the definition predicate by the maybe-undef edge conditions. * gimple-predicate-analysis.h (class predicate): Declare drop_conjuncts_implied_by. Diff: --- gcc/gimple-predicate-analysis.cc | 96 +++++++++++++++++++++++++++++++++++++--- gcc/gimple-predicate-analysis.h | 2 + 2 files changed, 93 insertions(+), 5 deletions(-) diff --git a/gcc/gimple-predicate-analysis.cc b/gcc/gimple-predicate-analysis.cc index 44ce0765b2d6..2acf1b5d7458 100644 --- a/gcc/gimple-predicate-analysis.cc +++ b/gcc/gimple-predicate-analysis.cc @@ -826,6 +826,42 @@ predicate::superset_of (const predicate &preds) const return true; } +/* Remove from every chain in *THIS any (comparison) conjunct whose domain is + a superset of every predicate in EDGE_CONDS, i.e. a conjunct implied by all + of them. Returns true if any conjunct was removed. */ + +bool +predicate::drop_conjuncts_implied_by (const vec<pred_info> &edge_conds) +{ + if (edge_conds.is_empty ()) + return false; + + bool changed = false; + for (unsigned i = 0; i < m_preds.length (); i++) + { + pred_chain &chain = m_preds[i]; + for (unsigned j = 0; j < chain.length (); ) + { + /* Only reason about comparison conjuncts: subset_of negates the + code for inverted predicates, which is invalid for e.g. the + BIT_AND_EXPR of an "x & mask" predicate. */ + bool implied = TREE_CODE_CLASS (chain[j].cond_code) == tcc_comparison; + for (unsigned k = 0; implied && k < edge_conds.length (); k++) + if (!subset_of (edge_conds[k], chain[j])) + implied = false; + + if (implied) + { + chain.ordered_remove (j); + changed = true; + } + else + j++; + } + } + return changed; +} + /* Create a predicate of the form OP != 0 and push it the work list CHAIN. */ static void @@ -857,6 +893,22 @@ get_pred_info_from_cmp (const gimple *cmp_assign) return pred; } +/* Return a pred_info for the GIMPLE_COND ending E's source block. The true + edge corresponds to the condition holding, so a false edge yields the + inverted predicate. */ + +static pred_info +get_pred_info_from_cond_edge (edge e) +{ + gcond *cond = as_a<gcond *> (*gsi_last_bb (e->src)); + pred_info pred; + pred.pred_lhs = gimple_cond_lhs (cond); + pred.pred_rhs = gimple_cond_rhs (cond); + pred.cond_code = gimple_cond_code (cond); + pred.invert = !!(e->flags & EDGE_FALSE_VALUE); + return pred; +} + /* If PHI is a degenerate phi with all operands having the same value (relop) update *PRED to that value and return true. Otherwise return false. */ @@ -1826,11 +1878,7 @@ predicate::init_from_control_deps (const vec<edge> *dep_chains, /* The true edge corresponds to the uninteresting condition. Add the negated predicate(s) for the edge to record the interesting condition. */ - pred_info one_pred; - one_pred.pred_lhs = gimple_cond_lhs (cond_stmt); - one_pred.pred_rhs = gimple_cond_rhs (cond_stmt); - one_pred.cond_code = gimple_cond_code (cond_stmt); - one_pred.invert = !!(e->flags & EDGE_FALSE_VALUE); + pred_info one_pred = get_pred_info_from_cond_edge (e); t_chain.safe_push (one_pred); @@ -2242,6 +2290,44 @@ uninit_analysis::is_use_guarded (gimple *use_stmt, basic_block use_bb, if (m_phi_def_preds.superset_of (use_preds)) return true; + /* The superset test fails when a guard that distinguishes the defined from + the undefined value sits on the PHI's maybe-undef incoming edge rather + than on the use's control-dependence chain -- e.g. after ifcombine merges + the conditions guarding the definition. A conjunct of the definition + predicate that is implied by the incoming-edge condition of every + maybe-undef operand cannot make the use unsafe: when that conjunct is + false the maybe-undef edge is not taken either, so no undefined value + reaches the PHI. Drop such conjuncts from a copy of the definition + predicate and retry; bail unless every maybe-undef operand arrives on a + simple conditional edge. */ + auto_vec<pred_info, 4> edge_conds; + unsigned nargs = gimple_phi_num_args (phi); + for (unsigned i = 0; i < nargs && i < m_eval.max_phi_args; i++) + { + if (!MASK_TEST_BIT (opnds, i)) + continue; + edge e = gimple_phi_arg_edge (phi, i); + /* Walk up through forwarder blocks to the controlling conditional; a + single-predecessor forwarder preserves the implication. */ + while (single_pred_p (e->src) && single_succ_p (e->src)) + e = single_pred_edge (e->src); + if (EDGE_COUNT (e->src->succs) != 2 + || !safe_dyn_cast <gcond *> (*gsi_last_bb (e->src))) + { + edge_conds.truncate (0); + break; + } + edge_conds.safe_push (get_pred_info_from_cond_edge (e)); + } + + if (!edge_conds.is_empty ()) + { + predicate relaxed (m_phi_def_preds); + if (relaxed.drop_conjuncts_implied_by (edge_conds) + && relaxed.superset_of (use_preds)) + return true; + } + return false; } diff --git a/gcc/gimple-predicate-analysis.h b/gcc/gimple-predicate-analysis.h index e2d2fd25d152..ce3006a20d15 100644 --- a/gcc/gimple-predicate-analysis.h +++ b/gcc/gimple-predicate-analysis.h @@ -91,6 +91,8 @@ class predicate bool superset_of (const predicate &) const; + bool drop_conjuncts_implied_by (const vec<pred_info> &); + private: bool includes (const pred_chain &) const;
