This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix ICE with FRE devirtualization (PR middle-end/77259)


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?

2016-08-16  Jakub Jelinek  <jakub@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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]