On Mon, Dec 12, 2011 at 6:01 PM, Jakub Jelinek <ja...@redhat.com> wrote:
> Hi!
>
> In gimple_fold_call (called from fold_stmt from replace_uses_by from cfg
> cleanup) we weren't calling maybe_clean_or_replace_eh_stmt, so when
> we've replaced a printf call (which can throw) with puts (which can throw
> too), nothing would update EH stmts.  It would be problematic calling
> gimple_purge_dead_eh_edges, because callers might be surprised by that,
> especially when this happens during cfg cleanup, so instead I just assert
> it is not needed and don't try to fold if a throwing stmt would be replaced
> by non-throwing.  FAB pass can handle that instead.  No folding
> has been actually disabled because of that check during bootstrap/regtest,
> so it is there just in case.

I think that all callers of fold_stmt are supposed to handle EH
updating themselves, similar to how they are supposed to
call update_stmt.  I see that replace_uses_by does call
maybe_clean_or_replace_eh_stmt - are you sure it is this path
the issue triggers on?

Richard.

> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
>
> 2011-12-12  Jakub Jelinek  <ja...@redhat.com>
>
>        PR tree-optimization/51481
>        * gimple-fold.c (gimple_fold_call): Call
>        maybe_clean_or_replace_eh_stmt.  Avoid optimization if stmt has EH
>        edges, but gimple_fold_builtin result can't throw.
>
>        * gcc.dg/pr51481.c: New test.
>
> --- gcc/gimple-fold.c.jj        2011-12-11 22:02:37.000000000 +0100
> +++ gcc/gimple-fold.c   2011-12-12 11:42:34.740168390 +0100
> @@ -1117,10 +1117,21 @@ gimple_fold_call (gimple_stmt_iterator *
>   if (callee && DECL_BUILT_IN (callee))
>     {
>       tree result = gimple_fold_builtin (stmt);
> -      if (result)
> +      if (result
> +         /* Disallow EH edge removal here.  We can't call
> +            gimple_purge_dead_eh_edges here.  */
> +         && (lookup_stmt_eh_lp (stmt) == 0
> +             || tree_could_throw_p (result)))
>        {
>           if (!update_call_from_tree (gsi, result))
>            gimplify_and_update_call_from_tree (gsi, result);
> +         if (!gsi_end_p (*gsi))
> +           {
> +             gimple new_stmt = gsi_stmt (*gsi);
> +             bool update_eh ATTRIBUTE_UNUSED
> +               = maybe_clean_or_replace_eh_stmt (stmt, new_stmt);
> +             gcc_assert (!update_eh);
> +           }
>          changed = true;
>        }
>     }
> --- gcc/testsuite/gcc.dg/pr51481.c.jj   2011-12-12 11:18:27.304678207 +0100
> +++ gcc/testsuite/gcc.dg/pr51481.c      2011-12-12 11:18:02.000000000 +0100
> @@ -0,0 +1,33 @@
> +/* PR tree-optimization/51481 */
> +/* { dg-do compile } */
> +/* { dg-options "-O -fexceptions -fipa-cp -fipa-cp-clone" } */
> +
> +extern const unsigned short int **foo (void)
> +  __attribute__ ((__nothrow__, __const__));
> +struct S { unsigned short s1; int s2; };
> +extern struct S *s[26];
> +
> +void
> +bar (int x, struct S *y, ...)
> +{
> +  static struct S *t;
> +  __builtin_va_list ap;
> +  __builtin_va_start (ap, y);
> +  if (t != s[7])
> +    {
> +      const char *p = "aAbBc";
> +      t = s[7];
> +      while ((*foo ())[(unsigned char) *p])
> +       p++;
> +    }
> +  __builtin_printf (x == 0 ? "abc\n" : "def\n");
> +  if (y != 0)
> +    __builtin_printf ("ghi %d %d", y->s2, y->s1);
> +  __builtin_va_end (ap);
> +}
> +
> +void
> +baz (char *x)
> +{
> +  bar (1, 0, x);
> +}
>
>        Jakub

Reply via email to