On Tue, 16 Aug 2016, Jakub Jelinek wrote:

> Hi!
> 
> The FRE devirtualization unlike gimple-fold or other places would transform
> some method call with TREE_ADDRESSABLE lhs into __builtin_unreachable call
> with the same lhs, which is invalid (__builtin_unreachable returns void).
> Also, gimple_call_fntype has not been adjusted in these cases.
> 
> Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux, ok for
> trunk?  What about 6.x?  Do you prefer it in 6.2, or 6.3?

I think the patch can be simplified to just set fntype - PRE/FRE already
arrange to fixup stmts, including calling fixup_noreturn_call which
removes the lhs if required.

Richard.

> 2016-08-16  Jakub Jelinek  <ja...@redhat.com>
> 
>       PR middle-end/77259
>       * tree-ssa-pre.c (eliminate_dom_walker::before_dom_children): If
>       turning a call into __builtin_unreachable-like noreturn call, adjust
>       gimple_call_set_fntype and remove lhs if needed.
> 
>       * g++.dg/ipa/devirt-52.C: New test.
> 
> --- gcc/tree-ssa-pre.c.jj     2016-08-12 17:33:46.000000000 +0200
> +++ gcc/tree-ssa-pre.c        2016-08-16 11:24:53.605976981 +0200
> @@ -4543,6 +4543,32 @@ eliminate_dom_walker::before_dom_childre
>                                      lang_hooks.decl_printable_name (fn, 2));
>                   }
>                 gimple_call_set_fndecl (call_stmt, fn);
> +               /* If changing the call to __builtin_unreachable
> +                  or similar noreturn function, adjust gimple_call_fntype
> +                  too.  */
> +               if ((gimple_call_flags (call_stmt) & ECF_NORETURN)
> +                   && VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fn)))
> +                   && TYPE_ARG_TYPES (TREE_TYPE (fn))
> +                   && (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (fn)))
> +                       == void_type_node))
> +                 gimple_call_set_fntype (call_stmt, TREE_TYPE (fn));
> +               tree lhs = gimple_call_lhs (call_stmt);
> +               /* If the call becomes noreturn, remove the lhs.  */
> +               if (lhs
> +                   && gimple_call_noreturn_p (call_stmt)
> +                   && (VOID_TYPE_P (TREE_TYPE (gimple_call_fntype
> +                                                             (call_stmt)))
> +                       || should_remove_lhs_p (lhs)))
> +                 {
> +                   if (TREE_CODE (lhs) == SSA_NAME)
> +                     {
> +                       tree var = create_tmp_var (TREE_TYPE (lhs));
> +                       tree def = get_or_create_ssa_default_def (cfun, var);
> +                       gimple *new_stmt = gimple_build_assign (lhs, def);
> +                       gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT);
> +                     }
> +                   gimple_call_set_lhs (call_stmt, NULL_TREE);
> +                 }
>                 maybe_remove_unused_call_args (cfun, call_stmt);
>                 gimple_set_modified (stmt, true);
>               }
> --- gcc/testsuite/g++.dg/ipa/devirt-52.C.jj   2016-08-16 11:08:49.943108247 
> +0200
> +++ gcc/testsuite/g++.dg/ipa/devirt-52.C      2016-08-16 11:32:25.295300721 
> +0200
> @@ -0,0 +1,56 @@
> +// PR middle-end/77259
> +// { dg-do compile { target c++11 } }
> +// { dg-options "-O2" }
> +
> +template <typename, typename = int> class A;
> +template <typename, typename> struct A
> +{
> +  A (A &&);
> +};
> +template <typename S, typename T, typename U>
> +A<S> operator+(S *, const A<T, U> &);
> +template <typename S, typename T, typename U>
> +void operator+(const A<T, U> &, S *);
> +struct B
> +{
> +  template <typename V> B (V);
> +};
> +template <typename V> V foo (B) {}
> +class C;
> +template <typename> struct D
> +{
> +  C *operator->() { return d; }
> +  C *d;
> +};
> +struct C
> +{
> +  virtual A<int> bar ();
> +};
> +struct E
> +{
> +  ~E ();
> +  virtual A<char> bar (const B &) const;
> +};
> +template <typename> struct F : E
> +{
> +};
> +template <typename W> struct F<D<W>> : E
> +{
> +  A<char> bar (const B &) const try
> +    {
> +      D<W> a = baz ();
> +    }
> +  catch (int)
> +    {
> +    }
> +  D<W> baz () const
> +  {
> +    D<C> b = foo<D<C>>(0);
> +    "" + b->bar () + "";
> +  }
> +};
> +struct G : F<D<int>>
> +{
> +  G (int);
> +};
> +void test () { G (0); }
> 
>       Jakub
> 
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 
21284 (AG Nuernberg)

Reply via email to