On Thu, Mar 5, 2026 at 2:44 PM Jan Hubicka <[email protected]> wrote:
>
> Hi,
> I am testing this variant of the patch with comment and more explicit
> merging along the inline path.

Thank you for taking this over.

Thanks,
Andrew

>
> Honza
>
> diff --git a/gcc/ipa-modref.cc b/gcc/ipa-modref.cc
> index fc00acecfce..312beebf07c 100644
> --- a/gcc/ipa-modref.cc
> +++ b/gcc/ipa-modref.cc
> @@ -5342,13 +5342,41 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge 
> *edge)
>                                       : NULL;
>    class modref_summary_lto *callee_info_lto
>                  = summaries_lto ? summaries_lto->get (edge->callee) : NULL;
> +
> +  /* Compute effective ECF_CONST, ECF_PURE, ECF_NOVOPS,
> +     ECF_LOOPING_CONST_OR_PURE and ignore_stores of the inlined function from
> +     the point of view of caller of the function it is transitively inlined 
> to.
> +     If we have inline chaing A->B->C
> +     then ECF_CONST, ECF_PURE_ECF, ECF_NOVOPS and ignore_stores is the 
> strongest
> +     flag seen on the inline path.
> +
> +     ECF_LOOPING_CONST_OR_PURE is bit special since, for example if C
> +     is ECF_CONST | ECF_LOOPING_CONST_OR_PURE and B is ECF_PURE, then outcome
> +     is ECF_CONST and !ECF_LOOPING_CONST_OR_PURE.
> +
> +     Flags are later used to avoid merging info about side-effects of C which
> +     are invisible to to the caller of A.  For example, it is possible for 
> const
> +     function to have local array and call functions modifying it.  */
>    int flags = flags_from_decl_or_type (edge->callee->decl);
> -  /* Combine in outer flags.  */
> -  cgraph_node *n;
> -  for (n = edge->caller; n->inlined_to; n = n->callers->caller)
> -    flags |= flags_from_decl_or_type (n->decl);
> -  flags |= flags_from_decl_or_type (n->decl);
> -  bool ignore_stores = ignore_stores_p (edge->caller->decl, flags);
> +  bool ignore_stores = ignore_stores_p (edge->callee->decl, flags);
> +  for (cgraph_node *n = edge->caller; n;
> +       n = n->inlined_to ? n->callers->caller : NULL)
> +    {
> +      int f = flags_from_decl_or_type (n->decl);
> +
> +      ignore_stores |= ignore_stores_p (n->decl, f);
> +      /* If we see first CONST/PURE flag in the chain, take its
> +        ECF_LOOPING_CONST_OR_PURE  */
> +      if (!(flags & (ECF_CONST | ECF_PURE)) && (f & (ECF_CONST | ECF_PURE)))
> +        flags |= (f & ECF_LOOPING_CONST_OR_PURE);
> +      /* If we already have ECF_CONST or ECF_PURE flag
> +        just improve ECF_LOOPING_CONST_OR_PURE if possible.  */
> +      if ((flags & (ECF_CONST | ECF_PURE))
> +         && (flags & ECF_LOOPING_CONST_OR_PURE)
> +         && (f & (ECF_CONST | ECF_PURE)) && !(f & ECF_LOOPING_CONST_OR_PURE))
> +       flags &= ECF_LOOPING_CONST_OR_PURE;
> +      flags |= f & (ECF_CONST | ECF_PURE | ECF_NOVOPS);
> +    }
>
>    if (!callee_info && to_info)
>      {
> diff --git a/gcc/testsuite/g++.dg/torture/pr120987-1.C 
> b/gcc/testsuite/g++.dg/torture/pr120987-1.C
> new file mode 100644
> index 00000000000..4209679bc03
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/torture/pr120987-1.C
> @@ -0,0 +1,57 @@
> +// { dg-do run { target c++11 } }
> +// { dg-skip-if "requires hosted libstdc++ for string/memory" { ! hostedlib 
> } }
> +// PR tree-optimization/120987
> +
> +#include <memory>
> +#include <string>
> +#include <cstdlib>
> +
> +#define ERROR_STRING  "012345678901234567"
> +
> +struct gdb_exception
> +{
> +  gdb_exception (const char *s)
> +    : message (std::make_shared<std::string> (s))
> +  {}
> +
> +  explicit gdb_exception (gdb_exception &&other) noexcept
> +    : message (std::move (other.message))
> +  {
> +    volatile int a = 1;
> +    if (a != 1)
> +      abort ();
> +  }
> +
> +
> +  std::shared_ptr<std::string> message;
> +};
> +
> +void __attribute__((noinline, noclone))
> +throw_exception (gdb_exception &&exception)
> +{
> +  throw gdb_exception (std::move (exception));
> +}
> +
> +static void __attribute__((noinline, noclone))
> +parse_linespec (void)
> +{
> +  struct gdb_exception file_exception (ERROR_STRING);
> +  throw_exception (std::move (file_exception));
> +}
> +
> +int
> +main (void)
> +{
> +  try
> +    {
> +      parse_linespec ();
> +    }
> +  catch (const gdb_exception &e)
> +    {
> +      if (*e.message != ERROR_STRING)
> +        __builtin_abort();
> +      return 0;
> +    }
> +
> +  __builtin_abort();
> +}

Reply via email to