On Fri, Nov 15, 2024 at 3:51 AM Joseph Myers <josmy...@redhat.com> wrote:
>
> Bug 117164 is an ICE on an existing test with -std=gnu23 involving a
> nested function returning a variable-size structure (and I think the
> last bug needing to be resolved before switching to -std=gnu23 as the
> default, as without fixing this would be a clear regression from a
> change in default).
>
> The problem is a GIMPLE verification failure where (after type
> remapping from inlining / cloning) the return type of the function no
> longer exactly matches the type to which it is assigned (these types
> use structural equality, which means GIMPLE verification can't use
> TYPE_CANONICAL and expects an exact match).  Specifically, the nested
> function itself is *not* inlined (the -fno-inline-small-functions in
> the original test nested-func-12.c, I think, or the noinline attribute
> in some of my variant tests), but the function containing it is either
> cloned (the --param ipa-cp-eval-threshold=0 in the original test) or
> inlined.  (I'm not sure what role -fno-guess-branch-probability plays
> in getting the right situation for the ICE; maybe affecting when
> inlining or cloning is considered profitable?)
>
> There is in fact existing code in tree-nested.cc to prevent inlining
> of a function containing a nested function with variably modified
> *argument* types.  I think the same issue of ensuring consistency of
> types means such prevention should also apply for a variably modified
> return type.  Furthermore, exactly the same problem applies for
> cloning for other reasons as it does for inlining.  Thus, change the
> logic to include variably modified return types for nested functions
> alongside those for arguments of those functions as a reason not to
> inline, and also add the noclone attribute in these cases.
>
> Bootstrapped with no regressions for x86-64-pc-linux-gnu.

OK.

Thanks,
Richard.

>         PR c/117164
>
> gcc/
>         * tree-nested.cc: Include "attribs.h".
>         (check_for_nested_with_variably_modified): Also return true for
>         variably modified return type.
>         (create_nesting_tree): If check_for_nested_with_variably_modified
>         returns true, also add noclone attribute.
>
> gcc/testsuite/
>         * gcc.dg/nested-func-13.c, gcc.dg/nested-func-14.c:
>         gcc.dg/nested-func-15.c, gcc.dg/nested-func-16.c,
>         gcc.dg/nested-func-17.c: New tests.
>
> diff --git a/gcc/testsuite/gcc.dg/nested-func-13.c 
> b/gcc/testsuite/gcc.dg/nested-func-13.c
> new file mode 100644
> index 000000000000..697a62354109
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/nested-func-13.c
> @@ -0,0 +1,6 @@
> +/* Test nested-func-12.c with -std=gnu17.  */
> +/* { dg-do run } */
> +/* { dg-options "-Ofast --param ipa-cp-eval-threshold=0 
> -fno-guess-branch-probability -fno-inline-small-functions -std=gnu17" } */
> +/* { dg-require-effective-target alloca } */
> +
> +#include "nested-func-12.c"
> diff --git a/gcc/testsuite/gcc.dg/nested-func-14.c 
> b/gcc/testsuite/gcc.dg/nested-func-14.c
> new file mode 100644
> index 000000000000..05a77bdb1a5a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/nested-func-14.c
> @@ -0,0 +1,6 @@
> +/* Test nested-func-12.c with -std=gnu23.  */
> +/* { dg-do run } */
> +/* { dg-options "-Ofast --param ipa-cp-eval-threshold=0 
> -fno-guess-branch-probability -fno-inline-small-functions -std=gnu23" } */
> +/* { dg-require-effective-target alloca } */
> +
> +#include "nested-func-12.c"
> diff --git a/gcc/testsuite/gcc.dg/nested-func-15.c 
> b/gcc/testsuite/gcc.dg/nested-func-15.c
> new file mode 100644
> index 000000000000..490d69599868
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/nested-func-15.c
> @@ -0,0 +1,29 @@
> +/* Bug 117164: ICE with -std=gnu23 inlining function containing call
> +   to non-inlined nested function returning variable-size struct.  */
> +/* { dg-do run } */
> +/* { dg-options "-O3 --param ipa-cp-eval-threshold=0 
> -fno-guess-branch-probability -fno-inline-small-functions -std=gnu23" } */
> +/* { dg-require-effective-target alloca } */
> +
> +void
> +foo (int n)
> +{
> +  struct S { int a[n]; };
> +
> +  struct S
> +  fn (void)
> +  {
> +    struct S s;
> +    s.a[0] = 42;
> +    return s;
> +  }
> +
> +  fn ();
> +  fn ();
> +  fn ();
> +}
> +
> +int
> +main (void)
> +{
> +  foo (1);
> +}
> diff --git a/gcc/testsuite/gcc.dg/nested-func-16.c 
> b/gcc/testsuite/gcc.dg/nested-func-16.c
> new file mode 100644
> index 000000000000..061485727bba
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/nested-func-16.c
> @@ -0,0 +1,27 @@
> +/* Bug 117164: ICE with -std=gnu23 inlining function containing call
> +   to non-inlined nested function returning variable-size struct.  */
> +/* { dg-do run } */
> +/* { dg-options "-O3 -fno-guess-branch-probability -std=gnu23" } */
> +/* { dg-require-effective-target alloca } */
> +
> +void
> +foo (int n)
> +{
> +  struct S { int a[n]; };
> +
> +  __attribute__ ((noinline)) struct S
> +  fn (void)
> +  {
> +    struct S s;
> +    s.a[0] = 42;
> +    return s;
> +  }
> +
> +  fn ();
> +}
> +
> +int
> +main (void)
> +{
> +  foo (1);
> +}
> diff --git a/gcc/testsuite/gcc.dg/nested-func-17.c 
> b/gcc/testsuite/gcc.dg/nested-func-17.c
> new file mode 100644
> index 000000000000..3441d79ac0dd
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/nested-func-17.c
> @@ -0,0 +1,7 @@
> +/* Bug 117164: ICE with -std=gnu23 inlining function containing call
> +   to non-inlined nested function returning variable-size struct.  */
> +/* { dg-do run } */
> +/* { dg-options "-O3 --param ipa-cp-eval-threshold=0 
> -fno-guess-branch-probability -std=gnu23" } */
> +/* { dg-require-effective-target alloca } */
> +
> +#include "nested-func-16.c"
> diff --git a/gcc/tree-nested.cc b/gcc/tree-nested.cc
> index a54e72c32370..4f5763634d3f 100644
> --- a/gcc/tree-nested.cc
> +++ b/gcc/tree-nested.cc
> @@ -47,6 +47,7 @@
>  #include "tree-nested.h"
>  #include "symbol-summary.h"
>  #include "symtab-thunks.h"
> +#include "attribs.h"
>
>  /* Summary of nested functions.  */
>  static function_summary <nested_function_info *>
> @@ -908,7 +909,11 @@ walk_all_functions (walk_stmt_fn callback_stmt, 
> walk_tree_fn callback_op,
>     add a VIEW_CONVERT_EXPR to each such operand for each call to the nested
>     function.  The former is not practical.  The latter would still require
>     detecting this case to know when to add the conversions.  So, for now at
> -   least, we don't inline such an enclosing function.
> +   least, we don't inline such an enclosing function.  A similar issue
> +   applies if the nested function has a variably modified return type, and
> +   is not inlined, but the enclosing function is inlined and so the type of
> +   the return slot as used in the enclosing function is remapped, so also
> +   avoid inlining in that case.
>
>     We have to do that check recursively, so here return indicating whether
>     FNDECL has such a nested function.  ORIG_FN is the function we were
> @@ -929,6 +934,9 @@ check_for_nested_with_variably_modified (tree fndecl, 
> tree orig_fndecl)
>    for (cgn = first_nested_function (cgn); cgn;
>         cgn = next_nested_function (cgn))
>      {
> +      if (variably_modified_type_p (TREE_TYPE (TREE_TYPE (cgn->decl)),
> +                                   orig_fndecl))
> +       return true;
>        for (arg = DECL_ARGUMENTS (cgn->decl); arg; arg = DECL_CHAIN (arg))
>         if (variably_modified_type_p (TREE_TYPE (arg), orig_fndecl))
>           return true;
> @@ -967,7 +975,13 @@ create_nesting_tree (struct cgraph_node *cgn)
>    /* See discussion at check_for_nested_with_variably_modified for a
>       discussion of why this has to be here.  */
>    if (check_for_nested_with_variably_modified (info->context, info->context))
> -    DECL_UNINLINABLE (info->context) = true;
> +    {
> +      DECL_UNINLINABLE (info->context) = true;
> +      tree attrs = DECL_ATTRIBUTES (info->context);
> +      if (lookup_attribute ("noclone", attrs) == NULL)
> +       DECL_ATTRIBUTES (info->context)
> +         = tree_cons (get_identifier ("noclone"), NULL, attrs);
> +    }
>
>    return info;
>  }
>
> --
> Joseph S. Myers
> josmy...@redhat.com
>

Reply via email to