https://gcc.gnu.org/g:0025ab8747c66ce47dd6705460d5e1b0b5d37d39
commit r17-3859-g0025ab8747c66ce47dd6705460d5e1b0b5d37d39 Author: Aldy Hernandez <[email protected]> Date: Tue Sep 1 20:17:36 2026 +0000 Add testcases for backward threading to never-executed edges [PR106495] r13-1924-gb9da686470d1c2 avoided threading to probably never executed edges but landed without a testcase. Add two, retroactively. [This is all AI generated. I used it to to go back in time, create testcases from the original preprocessed source code, further reduce it with cvise, and then distill it further to create a minimal reproducer for the concept, not the warning. This allows us to keep a reduction of the original testcase, plus a conceptual tiny testcase to make sure we don't regress going forward.] Both FAIL before r13-1924 and PASS with it. Assisted-by: Claude Fable 5 (Anthropic) gcc/testsuite/ChangeLog: PR tree-optimization/106495 PR tree-optimization/126906 * gcc.dg/tree-ssa/pr106495-1.c: New test. * gcc.dg/tree-ssa/pr106495-2.c: New test. Diff: --- gcc/testsuite/gcc.dg/tree-ssa/pr106495-1.c | 76 ++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/pr106495-2.c | 27 +++++++++++ 2 files changed, 103 insertions(+) diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr106495-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr106495-1.c new file mode 100644 index 000000000000..40a07b48e41a --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr106495-1.c @@ -0,0 +1,76 @@ +/* PR tree-optimization/106495 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -Warray-bounds -fdump-tree-threadfull1-details" } */ + +/* Reduced from PR106495 (attachment 53396, comment #6): the i686 bootstrap + broke with -Werror=array-bounds. The calls to the cold noreturn fancy_abort + clobber memory, so m_vec is reloaded for each access; the backward threader + can then resolve the m_vec == NULL path, where vec_length () is 0 and the + index wraps to 4294967294, and isolate it even though it ends in a probably + never executed edge. Nothing real ever executes the path, but the + materialized dead statements drew a bogus -Warray-bounds warning (ilp32 + only; the threadfull1 scan below discriminates on all targets). + + The PR106495 fix rejects such paths in profitable_path_p: this test FAILs + before that commit and PASSes with it. cvise-reduced from the original .ii + file, and then the AI converted the C++ vec templates to plain C. See + pr106495-2.c for a minimal distillation. */ + +void fancy_abort (const char *, int, const char *) + __attribute__ ((noreturn)) __attribute__ ((cold)); + +typedef int *basic_block; + +unsigned m_num; + +struct vec_embed +{ + int m_pad; + basic_block m_vecdata[]; +}; + +struct vec +{ + struct vec_embed *m_vec; +}; + +static inline unsigned +embed_length (struct vec_embed *v) +{ + return m_num; +} + +static inline basic_block +embed_index (struct vec_embed *v, unsigned ix) +{ + if (!(ix < m_num)) + fancy_abort ("", 9, __FUNCTION__); + return v->m_vecdata[ix]; /* { dg-bogus "above array bounds" } */ +} + +static inline unsigned +vec_length (struct vec *v) +{ + return v->m_vec ? embed_length (v->m_vec) : 0; +} + +static inline basic_block +vec_index (struct vec *v, unsigned ix) +{ + return embed_index (v->m_vec, ix); +} + +void find_edge (basic_block, basic_block); + +struct vec m_path; + +void +profitable_path_p (void) +{ + int len1 = vec_length (&m_path); + unsigned len2 = vec_length (&m_path); + basic_block bb = vec_index (&m_path, len1 - 2); + find_edge (vec_index (&m_path, len2 - 1), bb); +} + +/* { dg-final { scan-tree-dump "path leads to probably never executed edge" "threadfull1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr106495-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr106495-2.c new file mode 100644 index 000000000000..02e7b821de74 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr106495-2.c @@ -0,0 +1,27 @@ +/* PR tree-optimization/106495 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdisable-tree-ethread -fdump-tree-threadfull1-details" } */ + +/* Minimal distillation of pr106495-1.c, pinning the never-executed + taken-edge veto (PR105679, PR106495): a resolvable thread whose + taken edge is probably never executed and whose destination holds + real code (a call to abort, not just __builtin_unreachable) must + not be threaded, lest we isolate never-executed paths that the + late diagnostic passes then warn about. Without the r13-1924 veto + the 3->4 path threads straight into the abort block. + -fdisable-tree-ethread keeps the early threader from resolving the + path before profile estimation makes the edge cold. */ + +void abort (void); +int g; + +void +f (int x) +{ + if (x < 0) + g = 1; + if (x < 0) + abort (); +} + +/* { dg-final { scan-tree-dump "path leads to probably never executed edge" "threadfull1" } } */
