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)