https://gcc.gnu.org/g:f035e26ef7eee00fd0028531b087e4d2b72c6695
commit r17-5462-gf035e26ef7eee00fd0028531b087e4d2b72c6695 Author: Richard Biener <[email protected]> Date: Wed Oct 21 15:40:53 2026 +0200 tree-optimization/128054 - isolate path issue with multiple UBs The isolate path iteration scheme attempts to isolate a path exactly once, applying all transforms so the earliest will survive. But it fails to associate later UBs to the correctly isolated path due to the way it iterates over PHIs and arguments. The following changes the NULL dereference discovery to iterate over incoming edges (paths) so we clearly deal with UBs on the same path. PR tree-optimization/128054 * gimple-ssa-isolate-paths.cc (find_implicit_erroneous_behavior): Iterate over edges and then PHIs for NULL dereference discovery. Duplicate each path exactly once and apply all transforms for UB on that edge to that duplicate. * gcc.dg/torture/pr128054.c: New testcase. Diff: --- gcc/gimple-ssa-isolate-paths.cc | 68 ++++++++++++++------------------- gcc/testsuite/gcc.dg/torture/pr128054.c | 29 ++++++++++++++ 2 files changed, 58 insertions(+), 39 deletions(-) diff --git a/gcc/gimple-ssa-isolate-paths.cc b/gcc/gimple-ssa-isolate-paths.cc index ceef422495c7..6068418ce3b7 100644 --- a/gcc/gimple-ssa-isolate-paths.cc +++ b/gcc/gimple-ssa-isolate-paths.cc @@ -710,7 +710,6 @@ find_implicit_erroneous_behavior (void) if (has_abnormal_or_eh_outgoing_edge_p (bb)) continue; - /* If BB has an edge to itself, then duplication of BB below could result in reallocation of BB's PHI nodes. If that happens then the loop below over the PHIs would use the old PHI and @@ -724,74 +723,65 @@ find_implicit_erroneous_behavior (void) is then dereferenced within BB. This is somewhat overly conservative, but probably catches most of the interesting cases. */ - basic_block duplicate = NULL; - for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si)) + edge e; + for (edge_iterator ei = ei_start (bb->preds); (e = ei_safe_edge (ei));) { - gphi *phi = si.phi (); - tree lhs = gimple_phi_result (phi); - - /* PHI produces a pointer result. See if any of the PHI's - arguments are NULL. - - When we remove an edge, we want to reprocess the current - index since the argument at that index will have been - removed, hence the ugly way we update I for each iteration. */ - for (unsigned i = 0, next_i = 0; - i < gimple_phi_num_args (phi); i = next_i) + auto_vec <std::pair<gimple *, tree>, 4> uses_in_bb; + for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si)) { - tree arg = gimple_phi_arg_def (phi, i); - edge e = gimple_phi_arg_edge (phi, i); - - /* Advance the argument index unless a path involving - the current argument has been isolated. */ - next_i = i + 1; + gphi *phi = si.phi (); + tree lhs = gimple_phi_result (phi); + tree arg = gimple_phi_arg_def_from_edge (phi, e); + /* PHI produces a pointer result. See if any of the PHI's + arguments are NULL. */ if (!integer_zerop (arg)) continue; - location_t phi_arg_loc = gimple_phi_arg_location (phi, i); + location_t phi_arg_loc + = gimple_phi_arg_location_from_edge (phi, e); imm_use_iterator iter; gimple *use_stmt; /* We've got a NULL PHI argument. Now see if the - PHI's result is dereferenced within BB. */ - auto_vec <gimple *, 4> uses_in_bb; + PHI's result is dereferenced within BB. */ FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs) - { - /* We only care about uses in BB. Catching cases in + { + /* We only care about uses in BB. Catching cases in in other blocks would require more complex path isolation code. */ if (gimple_bb (use_stmt) != bb) continue; - location_t loc = gimple_location (use_stmt) - ? gimple_location (use_stmt) - : phi_arg_loc; + location_t loc = (gimple_location (use_stmt) + ? gimple_location (use_stmt) + : phi_arg_loc); if (stmt_uses_name_in_undefined_way (use_stmt, lhs, loc)) { if (!can_duplicate_block_p (bb)) break; - uses_in_bb.safe_push (use_stmt); + uses_in_bb.safe_push (std::make_pair (use_stmt, lhs)); } } - for (gimple *use_stmt : uses_in_bb) - { - duplicate = isolate_path (bb, duplicate, e, - use_stmt, lhs, false); + } + basic_block duplicate = NULL; + for (auto use : uses_in_bb) + { + duplicate = isolate_path (bb, duplicate, e, + use.first, use.second, false); - /* When we remove an incoming edge, we need to - reprocess the Ith element. */ - next_i = i; - cfg_altered = true; - } + cfg_altered = true; } + + if (!duplicate) + ei_next (&ei); } /* Then look for a PHI which have addresses of locals that are then returned. */ - duplicate = NULL; + basic_block duplicate = NULL; for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si)) { gphi *phi = si.phi (); diff --git a/gcc/testsuite/gcc.dg/torture/pr128054.c b/gcc/testsuite/gcc.dg/torture/pr128054.c new file mode 100644 index 000000000000..0570f33eabc0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr128054.c @@ -0,0 +1,29 @@ +/* { dg-do run } */ + +volatile int sel = 1; +int x = 5, y = 42; + +__attribute__((noipa)) void +maybe_exit (int c) +{ + if (c == 42) + __builtin_exit (0); +} + +int main () +{ + int *p1, *p2; + if (sel) + { + p1 = 0; + p2 = &y; + } + else + { + p1 = &x; + p2 = 0; + } + int v = *p2; + maybe_exit (v); + return *p1; +}
