On Fri, 7 Aug 2026, [email protected] wrote:

> From: Kyrylo Tkachov <[email protected]>
> 
> verify_partition_mem_exprs checks that no two out-of-SSA partitions carry one
> MEM_EXPR at different addresses.  It ran before the loop that restores the RTL
> of PARM_DECL and RESULT_DECL default definitions, and that loop is what gives
> the partition of such a default definition its decl back:
> 
>   FOR_EACH_SSA_NAME (i, name, cfun)
>     adjust_one_expanded_partition_var (name);   /* Merges in a MEM_EXPR.  */
>   ...
>       if (MEM_P (in))
>       set_mem_attributes (in, var, true);     /* Takes it out again.  */
> 
> Walking the names of a partition attaches the variable of any of them to that
> partition's location, preferring an ignored one.  A partition that holds the
> default definition of a parameter next to names of a store-motion temporary is
> therefore given the temporary as its MEM_EXPR for the span between the two
> loops, and the partition of the temporary itself has it as well:
> 
>   part 20  MEM_EXPR g0_lsm.14  addr (plus (virtual-stack-vars) (const_int 
> -256))
>   part 26  MEM_EXPR g0_lsm.14  addr (reg/v:DI 142)
> 
> The parameter takes its MEM_EXPR back before any statement is expanded, so the
> insn stream is unaffected, but the check in between sees the two and aborts.
> 
> Run the check once the RTL of every partition is final.
> With the out-of-SSA fixes for PR126405 reverted it still fires on all
> three of that PR's tests, the PARM_DECL one included.
> 
> Bootstrapped and tested on aarch64-none-linux-gnu.
> Ok for trunk?

OK.

Thanks,
Richard.

> Thanks,
> Kyrill
> 
> gcc/ChangeLog:
> 
>       PR middle-end/126701
>       * cfgexpand.cc (verify_partition_mem_exprs): Document when it may
>       be called.
>       (pass_expand::execute): Call it after the RTL of PARM_DECL and
>       RESULT_DECL default definitions is restored.
>       * tree-outof-ssa.cc (split_overlapping_partition_decls): Note the
>       variable a partition of a parameter or result default definition
>       ends up with.
> 
> gcc/testsuite/ChangeLog:
> 
>       PR middle-end/126701
>       * gcc.dg/pr126701.c: New test.
> 
> Signed-off-by: Kyrylo Tkachov <[email protected]>
> ---
>  gcc/cfgexpand.cc                | 13 +++++--
>  gcc/testsuite/gcc.dg/pr126701.c | 67 +++++++++++++++++++++++++++++++++
>  gcc/tree-outof-ssa.cc           |  6 ++-
>  3 files changed, 81 insertions(+), 5 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/pr126701.c
> 
> diff --git a/gcc/cfgexpand.cc b/gcc/cfgexpand.cc
> index 0b5bf7cd464..fd3f890620b 100644
> --- a/gcc/cfgexpand.cc
> +++ b/gcc/cfgexpand.cc
> @@ -2467,7 +2467,12 @@ stack_protect_return_slot_p ()
>     MEM_EXPR base and an offset from it, so two stack slots carrying one
>     MEM_EXPR read as a single object, which lets an access to one be 
> redirected
>     to the other.  out-of-SSA keeps them apart, see the comment above
> -   split_overlapping_partition_decls.  */
> +   split_overlapping_partition_decls.
> +
> +   Call this once the RTL of every partition is final.  The partition of a
> +   PARM_DECL or RESULT_DECL default definition is given the MEM_EXPR of any
> +   other variable in it while its names are walked, and only gets the decl
> +   back when its RTL is restored in pass_expand::execute.  */
>  
>  static void
>  verify_partition_mem_exprs (void)
> @@ -7194,9 +7199,6 @@ pass_expand::execute (function *fun)
>        adjust_one_expanded_partition_var (name);
>      }
>  
> -  if (flag_checking)
> -    verify_partition_mem_exprs ();
> -
>    /* Clean up RTL of variables that straddle across multiple
>       partitions, and check that the rtl of any PARM_DECLs that are not
>       cleaned up is that of their default defs.  */
> @@ -7244,6 +7246,9 @@ pass_expand::execute (function *fun)
>       }
>      }
>  
> +  if (flag_checking)
> +    verify_partition_mem_exprs ();
> +
>    /* If this function is `main', emit a call to `__main'
>       to run global initializers, etc.  */
>    if (DECL_NAME (current_function_decl)
> diff --git a/gcc/testsuite/gcc.dg/pr126701.c b/gcc/testsuite/gcc.dg/pr126701.c
> new file mode 100644
> index 00000000000..3f582cce5c3
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/pr126701.c
> @@ -0,0 +1,67 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fchecking" } */
> +
> +/* The partition holding the default definition of A2 also holds names of the
> +   store-motion temporaries of G0.  Walking the names of that partition gives
> +   its RTL the MEM_EXPR of a temporary, which the partition of that temporary
> +   has too, but the parameter gets its own MEM_EXPR back before any statement
> +   is expanded.  */
> +
> +typedef unsigned long long v16u64 __attribute__((vector_size (128)));
> +
> +v16u64 g0;
> +_Bool g9, ob13;
> +unsigned char g17;
> +static unsigned char g24 = 3;
> +void *a3;
> +__attribute__((cold)) void f8 (_Bool, unsigned char);
> +
> +void
> +f30 (unsigned long long a0, _Bool a1, v16u64 a2)
> +{
> +  unsigned long long v8;
> +  _Bool c9;
> +cont1:
> +  a2 = g0;
> +  g0 = __builtin_shufflevector (g0, g0, 0, 1, 1, 4, 7, 2, 0, 8, 7, 7, 7, 8, 
> 9,
> +                             0, 1, 4);
> +  switch (a0)
> +    {
> +    case 201146615185186167:
> +      goto sw3;
> +    case 1:
> +      goto sw3;
> +    default:
> +      goto cont1;
> +    }
> +sw3:
> +  c9 = g24;
> +  goto bf66;
> +bf26:
> +  c9 = v8;
> +  a3 = &c9;
> +  if (c9)
> +    g0 = ~g0;
> +  if (a1)
> +    goto br51;
> +  goto bf66;
> +br32:
> +  if (ob13)
> +    goto br47;
> +  if (__builtin_expect_with_probability (g9, 0, 0.265))
> +    goto br32;
> +  goto bf66;
> +br47:
> +  f8 (a1, g17);
> +br51:
> +  a2 = g0;
> +  if (c9)
> +    goto bf26;
> +sw55:
> +  g0 = a2;
> +  return;
> +bf66:
> +  if (__builtin_expect_with_probability (c9, 0, 0.519))
> +    goto br32;
> +  goto sw55;
> +}
> diff --git a/gcc/tree-outof-ssa.cc b/gcc/tree-outof-ssa.cc
> index af9d79fedcd..409e951b212 100644
> --- a/gcc/tree-outof-ssa.cc
> +++ b/gcc/tree-outof-ssa.cc
> @@ -1103,7 +1103,11 @@ split_overlapping_partition_decls (var_map map)
>        /* Expansion hands set_rtl the representative before the other names,
>        and expand_leader_merge keeps the variable it is given first unless a
>        later one is DECL_IGNORED_P, so merging the two gives the variable
> -      this partition ends up with.  */
> +      this partition ends up with.  A partition holding the default
> +      definition of a parameter or of the result is instead seeded with that
> +      decl, and is given it back once its RTL is restored at the end of
> +      expansion, so the variable it ends up with is one that the rule below
> +      keeps for it alone.  */
>        tree var = SSA_NAME_VAR (repr);
>        if (part_var[i])
>       var = expand_leader_merge (var, part_var[i]);
> 

-- 
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Jochen Jaser, Andrew McDonald, Abhinav Puri; (HRB 36809, AG Nuernberg)

Reply via email to