diff mbox

[PR,45934,5/6] Identify the new dynamic type after change

Message ID 20101201201711.438583439@virgil.suse.cz
State New
Headers show

Commit Message

Martin Jambor Dec. 1, 2010, 8:16 p.m. UTC
This patch adds code attempting to identify of the new dynamic type
after it has been changed, which has been missing in the previous
patch.  All the details are in the previous email.

Just for the record, this has been also bootstrapped and tested
(without the last patch applied) on x86-64-linux and has passed make
check-c++ on i686.

Thanks,

Martin


2010-11-30  Martin Jambor  <mjambor@suse.cz>

	* ipa-prop.c (type_change_info): New fields object and
	known_current_type.
	(extr_type_from_vtbl_ptr_store): New function.
	(check_stmt_for_type_change): Call it.
	(detect_type_change_1): Set up new fields in tci, build knonw type
	jump functions if the new type chan be identified.

	* testsuite/g++.dg/ipa/devirt-c-1.C: Add dump scans.
	* testsuite/g++.dg/ipa/devirt-c-2.C: Likewise.
	* testsuite/g++.dg/ipa/devirt-c-3.C: Likewise.
	* testsuite/g++.dg/ipa/devirt-c-4.C: Likewise.
diff mbox

Patch

Index: icln/gcc/ipa-prop.c
===================================================================
--- icln.orig/gcc/ipa-prop.c
+++ icln/gcc/ipa-prop.c
@@ -355,6 +355,12 @@  ipa_print_all_jump_functions (FILE *f)
 
 struct type_change_info
 {
+  /* The declaration or SSA_NAME pointer of the base that we are checking for
+     type change.  */
+  tree object;
+  /* If we actually can tell the type that the object has changed to, it is
+     stored in this field.  Otherwise it remains NULL_TREE.  */
+  tree known_current_type;
   /* Set to true if dynamic type change has been detected.  */
   bool type_maybe_changed;
 };
@@ -387,6 +393,49 @@  stmt_may_be_vtbl_ptr_store (gimple stmt)
   return true;
 }
 
+/* If STMT can be proved to be an assignment to the virtual method table
+   pointer of ANALYZED_OBJ and the type associated witht the new table
+   identified, return the type.  Otherwise return NULL_TREE.  */
+
+static tree
+extr_type_from_vtbl_ptr_store (gimple stmt, tree analyzed_obj)
+{
+  tree lhs, t, obj;
+
+  if (!is_gimple_assign (stmt))
+    return NULL_TREE;
+
+  lhs = gimple_assign_lhs (stmt);
+
+  if (TREE_CODE (lhs) != COMPONENT_REF)
+    return NULL_TREE;
+   obj = lhs;
+
+   if (!DECL_VIRTUAL_P (TREE_OPERAND (lhs, 1)))
+     return NULL_TREE;
+
+   do
+     {
+       obj = TREE_OPERAND (obj, 0);
+     } while (TREE_CODE (obj) == COMPONENT_REF);
+   if (TREE_CODE (obj) == MEM_REF)
+     obj = TREE_OPERAND (obj, 0);
+   if (TREE_CODE (obj) == ADDR_EXPR)
+     obj = TREE_OPERAND (obj, 0);
+   if (obj != analyzed_obj)
+     return NULL_TREE;
+
+
+   t = gimple_assign_rhs1 (stmt);
+   if (TREE_CODE (t) != ADDR_EXPR)
+     return NULL_TREE;
+   t = get_base_address (TREE_OPERAND (t, 0));
+   if (!t || TREE_CODE (t) != VAR_DECL || !DECL_VIRTUAL_P (t))
+     return NULL_TREE;
+
+   return DECL_CONTEXT (t);
+}
+
 /* Callbeck of walk_aliased_vdefs and a helper function for
    detect_type_change_anc to check whether a particular statement may modify
    the virtual table pointer, and if possible also determine the new type of
@@ -402,6 +451,8 @@  check_stmt_for_type_change (ao_ref *ao A
   if (stmt_may_be_vtbl_ptr_store (stmt))
     {
       tci->type_maybe_changed = true;
+      tci->known_current_type = extr_type_from_vtbl_ptr_store (stmt,
+							       tci->object);
       return true;
     }
   else
@@ -417,9 +468,10 @@  check_stmt_for_type_change (ao_ref *ao A
 
 static bool
 detect_type_change_anc (tree arg, gimple call, struct ipa_jump_func *jfunc,
-			HOST_WIDE_INT anc_offset ATTRIBUTE_UNUSED)
+			HOST_WIDE_INT anc_offset)
 {
   struct type_change_info tci;
+  tree obj;
   ao_ref ar;
 
   /* Const calls cannot call virtual methods through VMT and so type changes do
@@ -427,6 +479,15 @@  detect_type_change_anc (tree arg, gimple
   if (!gimple_vuse (call))
     return false;
 
+  obj = arg;
+  while (handled_component_p (obj))
+    obj = TREE_OPERAND (obj, 0);
+  if (TREE_CODE (obj) == MEM_REF)
+    obj = TREE_OPERAND (obj, 0);
+  if (TREE_CODE (obj) == ADDR_EXPR)
+    obj = TREE_OPERAND (obj, 0);
+  tci.object = obj;
+  tci.known_current_type = NULL_TREE;
   tci.type_maybe_changed = false;
 
   ao_ref_init (&ar, arg);
@@ -435,7 +496,31 @@  detect_type_change_anc (tree arg, gimple
   if (!tci.type_maybe_changed)
     return false;
 
-  jfunc->type = IPA_JF_UNKNOWN;
+  if (!tci.known_current_type)
+    jfunc->type = IPA_JF_UNKNOWN;
+  else if (anc_offset != 0)
+    {
+      tree new_binfo = get_binfo_at_offset (TYPE_BINFO (tci.known_current_type),
+					    anc_offset, TREE_TYPE (arg));
+
+      if (new_binfo)
+	{
+	  jfunc->type = IPA_JF_KNOWN_TYPE;
+	  jfunc->value.base_binfo = new_binfo;
+	}
+      else
+	jfunc->type = IPA_JF_UNKNOWN;
+    }
+  else
+    {
+      /* If an offset of a searched-for sub-object actually happens to be zero,
+	 we do not have to worry about non-artificialness.  Either there are no
+	 virtual methods anyway or there is a VMT pointer at offset zero and so
+	 artificial sub-objects start at higher offsets.  */
+      jfunc->type = IPA_JF_KNOWN_TYPE;
+      jfunc->value.base_binfo = TYPE_BINFO (tci.known_current_type);
+    }
+
   return true;
 }
 
Index: icln/gcc/testsuite/g++.dg/ipa/devirt-c-1.C
===================================================================
--- icln.orig/gcc/testsuite/g++.dg/ipa/devirt-c-1.C
+++ icln/gcc/testsuite/g++.dg/ipa/devirt-c-1.C
@@ -1,7 +1,7 @@ 
 /* Verify that ipa-cp correctly detects the dynamic type of an object
    under construction when doing devirtualization.  */
 /* { dg-do run } */
-/* { dg-options "-O3 -fno-early-inlining -fno-inline"  } */
+/* { dg-options "-O3 -fno-early-inlining -fno-inline -fdump-ipa-cp -fdump-tree-optimized"  } */
 
 extern "C" void abort (void);
 
@@ -69,3 +69,8 @@  int main (int argc, char *argv[])
     bah ();
   return 0;
 }
+
+/* { dg-final { scan-ipa-dump "Discovered a virtual call to a known target.*A::foo"  "cp"  } } */
+/* { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 0 "optimized"} } */
+/* { dg-final { cleanup-ipa-dump "cp" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
Index: icln/gcc/testsuite/g++.dg/ipa/devirt-c-2.C
===================================================================
--- icln.orig/gcc/testsuite/g++.dg/ipa/devirt-c-2.C
+++ icln/gcc/testsuite/g++.dg/ipa/devirt-c-2.C
@@ -1,7 +1,7 @@ 
 /* Verify that ipa-cp correctly detects the dynamic type of an object
    under construction when doing devirtualization.  */
 /* { dg-do run } */
-/* { dg-options "-O3 -fno-early-inlining -fno-inline"  } */
+/* { dg-options "-O3 -fno-early-inlining -fno-inline -fdump-ipa-cp -fdump-tree-optimized"  } */
 
 extern "C" void abort (void);
 
@@ -77,3 +77,8 @@  int main (int argc, char *argv[])
     bah ();
   return 0;
 }
+
+/* { dg-final { scan-ipa-dump "Discovered a virtual call to a known target.*A::foo"  "cp"  } } */
+/* { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 0 "optimized"} } */
+/* { dg-final { cleanup-ipa-dump "cp" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
Index: icln/gcc/testsuite/g++.dg/ipa/devirt-c-3.C
===================================================================
--- icln.orig/gcc/testsuite/g++.dg/ipa/devirt-c-3.C
+++ icln/gcc/testsuite/g++.dg/ipa/devirt-c-3.C
@@ -1,7 +1,7 @@ 
 /* Verify that ipa-cp correctly detects the dynamic type of an object
    under construction when doing devirtualization.  */
 /* { dg-do run } */
-/* { dg-options "-O3 -fno-inline"  } */
+/* { dg-options "-O3 -fno-inline -fdump-ipa-cp -fdump-tree-optimized"  } */
 
 extern "C" void abort (void);
 
@@ -78,3 +78,8 @@  int main (int argc, char *argv[])
     bah ();
   return 0;
 }
+
+/* { dg-final { scan-ipa-dump "Discovered a virtual call to a known target.*A::foo"  "cp"  } } */
+/* { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 0 "optimized"} } */
+/* { dg-final { cleanup-ipa-dump "cp" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
Index: icln/gcc/testsuite/g++.dg/ipa/devirt-c-4.C
===================================================================
--- icln.orig/gcc/testsuite/g++.dg/ipa/devirt-c-4.C
+++ icln/gcc/testsuite/g++.dg/ipa/devirt-c-4.C
@@ -1,7 +1,7 @@ 
 /* Verify that ipa-cp correctly detects the dynamic type of an object
    under construction when doing devirtualization.  */
 /* { dg-do run } */
-/* { dg-options "-O3 -fno-inline"  } */
+/* { dg-options "-O3 -fno-inline -fdump-tree-optimized"  } */
 
 extern "C" void abort (void);
 
@@ -108,3 +108,6 @@  int main (int argc, char *argv[])
     bah ();
   return 0;
 }
+
+/* { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 0 "optimized"} } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */