PR ipa/59831 (ipa-cp devirt issues)

Jan Hubicka hubicka@ucw.cz
Tue Feb 4 05:44:00 GMT 2014


Hi,
this patch solves the actual ICE in PR59831 by using ipa-devirt instead of
gimple_extract_devirt_binfo_from_cst as discussed in the first post.

Honza

	PR ipa/59831
	* ipa-cp.c (ipa_get_indirect_edge_target_1): Use ipa-devirt
	to figure out targets of polymorphic calls with known decl.
	* ipa-prop.c (try_make_edge_direct_virtual_call): Likewise.
	* ipa-utils.h (get_polymorphic_call_info_from_invariant): Declare.
	* ipa-devirt.c (get_polymorphic_call_info_for_decl): Break out from ...
	(get_polymorphic_call_info): ... here.
	(get_polymorphic_call_info_from_invariant): New function.

	* g++.dg/ipa/devirt-22.C: New testcase.
Index: ipa-cp.c
===================================================================
--- ipa-cp.c	(revision 207447)
+++ ipa-cp.c	(working copy)
@@ -1601,15 +1601,24 @@ ipa_get_indirect_edge_target_1 (struct c
 
   if (TREE_CODE (t) != TREE_BINFO)
     {
-      tree binfo;
-      binfo = gimple_extract_devirt_binfo_from_cst
-		 (t, ie->indirect_info->otr_type);
-      if (!binfo)
+      ipa_polymorphic_call_context context;
+      vec <cgraph_node *>targets;
+      bool final;
+
+      if (!get_polymorphic_call_info_from_invariant
+	     (&context, t, ie->indirect_info->otr_type,
+	      anc_offset))
 	return NULL_TREE;
-      binfo = get_binfo_at_offset (binfo, anc_offset, otr_type);
-      if (!binfo)
+      targets = possible_polymorphic_call_targets
+		 (ie->indirect_info->otr_type,
+		  ie->indirect_info->otr_token,
+		  context, &final);
+      if (!final || targets.length () > 1)
 	return NULL_TREE;
-      target = gimple_get_virt_method_for_binfo (token, binfo);
+      if (targets.length () == 1)
+	target = targets[0]->decl;
+      else
+	target = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
     }
   else
     {
Index: testsuite/g++.dg/ipa/devirt-22.C
===================================================================
--- testsuite/g++.dg/ipa/devirt-22.C	(revision 0)
+++ testsuite/g++.dg/ipa/devirt-22.C	(revision 0)
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fno-early-inlining -fno-ipa-sra -fdump-ipa-cp"  } */
+class A {};
+class B {
+public:
+  A &operator[](int);
+};
+class C : B {
+public:
+  virtual int m_fn1() { return 0; }
+  A &operator[](int p1) {
+    int a;
+    a = m_fn1();
+    static_cast<void>(__builtin_expect(a, 0) ?: 0);
+    return B::operator[](p1);
+  }
+};
+
+C b;
+int *e;
+static void sort(C &p1, C &p2) {
+  for (int i=0;; i++) {
+    A c, d = p2[0];
+    p1[0] = c;
+    p2[0] = d;
+  }
+}
+
+void lookupSourceDone() { b[0]; }
+
+void update_sources() {
+  if (e) {
+    C f;
+    sort(f, b);
+  }
+}
+/* Note that we miss one devirtualization because we are not able to track the
+   vtbl store in destructor.  
+   Previously we devirtualized to C::m_fn1 instead of B::m_fn1.  */
+/* { dg-final { scan-tree-dump-times "Discovered a virtual call to a known target" 1 "cp"  } } */
+/* { dg-final { cleanup-ipa-dump "cp" } } */
Index: ipa-utils.h
===================================================================
--- ipa-utils.h	(revision 207439)
+++ ipa-utils.h	(working copy)
@@ -87,6 +87,8 @@ tree method_class_type (tree);
 tree get_polymorphic_call_info (tree, tree, tree *,
 				HOST_WIDE_INT *,
 				ipa_polymorphic_call_context *);
+bool get_polymorphic_call_info_from_invariant (ipa_polymorphic_call_context *,
+					       tree, tree, HOST_WIDE_INT);
 tree vtable_pointer_value_to_binfo (tree t);
 bool vtable_pointer_value_to_vtable (tree, tree *, unsigned HOST_WIDE_INT *);
 
Index: ipa-prop.c
===================================================================
--- ipa-prop.c	(revision 207447)
+++ ipa-prop.c	(working copy)
@@ -2731,19 +2731,38 @@ try_make_edge_direct_virtual_call (struc
 
   if (TREE_CODE (binfo) != TREE_BINFO)
     {
-      binfo = gimple_extract_devirt_binfo_from_cst
-		 (binfo, ie->indirect_info->otr_type);
-      if (!binfo)
+      ipa_polymorphic_call_context context;
+      vec <cgraph_node *>targets;
+      bool final;
+
+      if (!get_polymorphic_call_info_from_invariant
+	     (&context, binfo, ie->indirect_info->otr_type,
+	      ie->indirect_info->offset))
+	return NULL;
+      targets = possible_polymorphic_call_targets
+		 (ie->indirect_info->otr_type,
+		  ie->indirect_info->otr_token,
+		  context, &final);
+      if (!final || targets.length () > 1)
 	return NULL;
+      if (targets.length () == 1)
+	target = targets[0]->decl;
+      else
+	{
+          target = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
+	  cgraph_get_create_node (target);
+	}
     }
-
-  binfo = get_binfo_at_offset (binfo, ie->indirect_info->offset,
-			       ie->indirect_info->otr_type);
-  if (binfo)
-    target = gimple_get_virt_method_for_binfo (ie->indirect_info->otr_token,
-					       binfo);
   else
-    return NULL;
+    {
+      binfo = get_binfo_at_offset (binfo, ie->indirect_info->offset,
+				   ie->indirect_info->otr_type);
+      if (binfo)
+	target = gimple_get_virt_method_for_binfo (ie->indirect_info->otr_token,
+						   binfo);
+      else
+	return NULL;
+    }
 
   if (target)
     {
Index: ipa-devirt.c
===================================================================
--- ipa-devirt.c	(revision 207439)
+++ ipa-devirt.c	(working copy)
@@ -1071,6 +1071,60 @@ vtable_pointer_value_to_binfo (tree t)
 					 offset, vtable);
 }
 
+/* Proudce polymorphic call context for call method of instance
+   that is located within BASE (that is assumed to be a decl) at OFFSET. */
+
+static void
+get_polymorphic_call_info_for_decl (ipa_polymorphic_call_context *context,
+				    tree base, HOST_WIDE_INT offset)
+{
+  gcc_assert (DECL_P (base));
+
+  context->outer_type = TREE_TYPE (base);
+  context->offset = offset;
+  /* Make very conservative assumption that all objects
+     may be in construction. 
+     TODO: ipa-prop already contains code to tell better. 
+     merge it later.  */
+  context->maybe_in_construction = true;
+  context->maybe_derived_type = false;
+}
+
+/* CST is an invariant (address of decl), try to get meaningful
+   polymorphic call context for polymorphic call of method 
+   if instance of OTR_TYPE that is located at OFFSET of this invariant.
+   Return FALSE if nothing meaningful can be found.  */
+
+bool
+get_polymorphic_call_info_from_invariant (ipa_polymorphic_call_context *context,
+				          tree cst,
+				          tree otr_type,
+				          HOST_WIDE_INT offset)
+{
+  HOST_WIDE_INT offset2, size, max_size;
+  tree base;
+
+  if (TREE_CODE (cst) != ADDR_EXPR)
+    return NULL_TREE;
+
+  cst = TREE_OPERAND (cst, 0);
+  base = get_ref_base_and_extent (cst, &offset2, &size, &max_size);
+  if (!DECL_P (base)
+      || max_size == -1
+      || max_size != size)
+    return NULL_TREE;
+
+  /* Only type inconsistent programs can have otr_type that is
+     not part of outer type.  */
+  if (!contains_type_p (TREE_TYPE (base),
+			offset, otr_type))
+    return NULL_TREE;
+
+  get_polymorphic_call_info_for_decl (context,
+				     base, offset);
+  return true;
+}
+
 /* Given REF call in FNDECL, determine class of the polymorphic
    call (OTR_TYPE), its token (OTR_TOKEN) and CONTEXT.
    Return pointer to object described by the context  */
@@ -1136,14 +1190,8 @@ get_polymorphic_call_info (tree fndecl,
 		  if (!contains_type_p (TREE_TYPE (base),
 					context->offset + offset2, *otr_type))
 		    return base_pointer;
-		  context->outer_type = TREE_TYPE (base);
-		  context->offset += offset2;
-		  /* Make very conservative assumption that all objects
-		     may be in construction. 
-		     TODO: ipa-prop already contains code to tell better. 
-		     merge it later.  */
-		  context->maybe_in_construction = true;
-		  context->maybe_derived_type = false;
+		  get_polymorphic_call_info_for_decl (context, base,
+						      context->offset + offset2);
 		  return NULL;
 		}
 	      else



More information about the Gcc-patches mailing list