[1/2] Add testcases for backward threading to never-executed edges [PR106495]
Commit Message
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
an 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)
OK?
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.
---
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(+)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr106495-1.c
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr106495-2.c
Comments
On 9/2/26 6:07 AM, Aldy Hernandez wrote:
> 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
> an 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)
>
> OK?
>
> 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.
OK for the trunk. For once the verbosity of an LLM is useful :-) I
might disagree with the "must not be threaded", it's more of a we don't
want to thread because it triggers hard to fix diagnostics on a likely
unreachable path, but it's not worth editing.
Jeff
On Wed, Sep 02, 2026 at 06:44:35AM -0600, Jeff Law wrote:
>
>
> On 9/2/26 6:07 AM, Aldy Hernandez wrote:
> > 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
> > an 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)
> >
> > OK?
> >
> > 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.
> OK for the trunk. For once the verbosity of an LLM is useful :-) I might
Heh. I did prune it down a bit before submitting :).
Aldy
new file mode 100644
@@ -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" } } */
new file mode 100644
@@ -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" } } */