On Tue, Feb 24, 2026 at 6:40 AM Andrew Pinski
<[email protected]> wrote:
>
> After outlinining the bbs for function splitting, we move the clobbers that
> were in the
> last bb to be after the newly calling function.
> This allows for stack location sharing and more when the non split out part
> is inlined
> into another function.
>
> This also fixes some of the warnings about dangling-pointers because
> the clobbers are now correctly handled while function splitting.
> The testcases test for the cases where the dangling-pointers pointer
> warnings would show up too.
>
> Note only end of storage clobbers in this case.
>
> Bootstrapped and tested on x86_64-linux-gnu.
>
> PR tree-optimization/110091
>
> gcc/ChangeLog:
>
> * ipa-split.cc (split_function): Find the bb
> which is used for return in the outlined function.
> Move the clobbers that are at the end of that bb
> to be after the new call.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.dg/tree-ssa/pr110091-3.c: New test.
> * gcc.dg/tree-ssa/pr110091-4.c: New test.
>
> Signed-off-by: Andrew Pinski <[email protected]>
> ---
> gcc/ipa-split.cc | 48 ++++++++++++++++++++++
> gcc/testsuite/gcc.dg/tree-ssa/pr110091-3.c | 38 +++++++++++++++++
> gcc/testsuite/gcc.dg/tree-ssa/pr110091-4.c | 34 +++++++++++++++
> 3 files changed, 120 insertions(+)
> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr110091-3.c
> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr110091-4.c
>
> diff --git a/gcc/ipa-split.cc b/gcc/ipa-split.cc
> index 3185830609d..aae4cf9e151 100644
> --- a/gcc/ipa-split.cc
> +++ b/gcc/ipa-split.cc
> @@ -1470,8 +1470,31 @@ split_function (basic_block return_bb, class
> split_point *split_point,
> }
> else
> break;
> +
> + /* Find the old return bb, it might contain some clobbers
> + which we want to copy back after the call. */
> + basic_block old_return = nullptr;
> + if (split_part_return_p)
> + {
> + bool one_return_bb = true;
> + FOR_EACH_EDGE (e, ei, return_bb->preds)
> + if (bitmap_bit_p (split_point->split_bbs, e->src->index))
> + {
> + if (old_return != nullptr)
> + {
> + one_return_bb = false;
> + break;
> + }
> + old_return = e->src;
> + }
> + if (!one_return_bb)
> + old_return = nullptr;
> + }
> +
> call_bb->count = split_point->count;
> e = split_block (split_point->entry_bb, last_stmt);
> + if (old_return == e->src)
> + old_return = e->dest;
> remove_edge (e);
>
> /* Produce the call statement. */
> @@ -1713,6 +1736,31 @@ split_function (basic_block return_bb, class
> split_point *split_point,
> gsi_insert_after (&gsi, ret, GSI_NEW_STMT);
> }
> }
> +
> + /* Move the clobbers from the old return bb to after the call. */
> + if (old_return)
> + {
> + gimple_stmt_iterator ngsi = gsi_last_bb (call_bb);
> + gsi_next (&ngsi);
> + for (gimple_stmt_iterator ogsi = gsi_last_bb (old_return);
> + !gsi_end_p (ogsi); )
> + {
> + gimple *stmt = *ogsi;
> + if (is_gimple_debug (stmt))
> + {
> + gsi_prev (&ogsi);
> + continue;
> + }
> + if (!gimple_clobber_p (stmt, CLOBBER_STORAGE_END))
> + break;
> + gimple_set_vuse (stmt, gimple_vop (cfun));
> + gimple_set_vdef (stmt, gimple_vop (cfun));
I believe this will leak an unreleased SSA name. You might want to use
unlink_stmt_vdef before?
> + gimple_stmt_iterator nogsi = ogsi;
> + gsi_prev (&ogsi);
> + gsi_move_before (&nogsi, &ngsi, GSI_NEW_STMT);
> + update_stmt (stmt);
> + }
> + }
> free_dominance_info (CDI_DOMINATORS);
> free_dominance_info (CDI_POST_DOMINATORS);
> compute_fn_summary (node, true);
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr110091-3.c
> b/gcc/testsuite/gcc.dg/tree-ssa/pr110091-3.c
> new file mode 100644
> index 00000000000..532b138655f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr110091-3.c
> @@ -0,0 +1,38 @@
> +/* { dg-do compile } */
> +/* { dg-options "-Wall -O2 -fdump-tree-optimized -fdump-tree-sink1-details"
> } */
> +/* PR tree-optimization/110091 */
> +/* The clobbers are after the outlined code */
> +
> +struct tEntry
> +{
> + int value;
> +};
> +int *out;
> +
> +extern int otherfunc(struct tEntry *);
> +extern void anotherfunc(int val);
> +
> +void bar()
> +{
> + struct tEntry entry1 = { 0 };
> + struct tEntry entry2 = { 0 };
> +
> + if (otherfunc(&entry2) != 0)
> + return;
> + if (otherfunc(&entry1) != 0)
> + return;
> + if (out)
> + *out = entry2.value; /* { dg-bogus "dangling pointer to" } */
> + anotherfunc(5);
> +}
> +
> +void foo()
> +{
> + bar();
> +}
> +
> +/* There should be 2 CLOBBERs, 1 for each: entry1 and entry2 as they have
> been "sinked". */
> +/* { dg-final { scan-tree-dump-times "CLOBBER\\\(eos\\\)" 2 "optimized" } }
> */
> +/* { dg-final { scan-tree-dump "sinking common stores with same value to
> entry2" "sink1" } } */
> +/* { dg-final { scan-tree-dump "sinking common stores with same value to
> entry1" "sink1" } } */
> +
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr110091-4.c
> b/gcc/testsuite/gcc.dg/tree-ssa/pr110091-4.c
> new file mode 100644
> index 00000000000..e2ce19b0e83
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr110091-4.c
> @@ -0,0 +1,34 @@
> +/* { dg-do compile } */
> +/* { dg-options "-Wall -O2 -fdump-tree-optimized -fdump-tree-sink1-details"
> } */
> +/* PR tree-optimization/110091 */
> +/* The clobbers are after the outlined code */
> +
> +struct tEntry
> +{
> + int value;
> +};
> +int *out;
> +
> +extern int otherfunc(struct tEntry *);
> +extern void anotherfunc(int val);
> +
> +void bar()
> +{
> + struct tEntry entry = { 0 };
> +
> + if (otherfunc(&entry) != 0)
> + return;
> + if (out)
> + *out = entry.value; /* { dg-bogus "dangling pointer to" } */
> + anotherfunc(5);
> +}
> +
> +void foo()
> +{
> + bar();
> +}
> +
> +/* There should be 2 CLOBBERs, 1 for entry as they have been "sinked" and
> one for the inlined version. */
> +/* { dg-final { scan-tree-dump-times "CLOBBER\\\(eos\\\)" 2 "optimized" } }
> */
> +/* { dg-final { scan-tree-dump "sinking common stores with same value to
> entry" "sink1" } } */
> +
> --
> 2.43.0
>