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]

Strenghten assumption about dynamic type changes (placement new)


Hi,
this patch strengthens detect_type_change and makes it cheaper based on the following observation.

We propagate types from places we know instances are created across pointers
passed to functions.  Once non-POD type is created at a given memory location,
one can not change its type by placement_new into something else.
This makes it easier to check if types may be altered from function start to
a given call site (information needed to produce jump function) by checking
whether function in question is a constructor or destructor and the parameter
is THIS pointer.  In other cases we can not retype anymore.

Jason, this assumes that one can not destroy the type and re-construct same
type at the same spot.  Is this valid for THIS pointer of normal methods and is
this valid in general?  If so, we will need to walk inline stack of the call
statement and watch for inlined constructor, as we may be within the
destructing/reconstructing sequence. This is not hard to do and I want to do it
anyway to disprove the fact htat local variable may be in
construction/destruction - that can be true only for calls that are within the
inlined constructor/destructor.

Bootstrapped/regtested x86_64-linux, will commit it if the above question is resolved.

Honza

	* ipa-prop.c (param_type_may_change_p): New function.
	(detect_type_change_from_memory_writes): Break out from ....
	(detect_type_change): ... here; use param_type_may_change_p.
	(detect_type_change_ssa): Use param_type_may_change_p.

Index: ipa-prop.c
===================================================================
--- ipa-prop.c	(revision 212234)
+++ ipa-prop.c	(working copy)
@@ -731,18 +731,45 @@ check_stmt_for_type_change (ao_ref *ao A
     return false;
 }
 
+/* See if ARG is PARAM_DECl describing instance passed by pointer
+   or reference in FUNCTION.  Return false if the dynamic type may not change.
 
+   Generally functions are not allowed to change type of such instances,
+   only excetions are C++ constructors and destructors.  */
+
+static bool
+param_type_may_change_p (tree function, tree arg)
+{
+  if (TREE_CODE (arg) == SSA_NAME
+      && SSA_NAME_IS_DEFAULT_DEF (arg)
+      && TREE_CODE (SSA_NAME_VAR (arg)) == PARM_DECL)
+    {
+      if (TREE_CODE (TREE_TYPE (function)) == METHOD_TYPE
+	  && !DECL_CXX_CONSTRUCTOR_P (function)
+	  && !DECL_CXX_DESTRUCTOR_P (function)
+	  && (SSA_NAME_VAR (arg) == DECL_ARGUMENTS (function)))
+	return false;
+
+      if (SSA_NAME_VAR (arg) != DECL_ARGUMENTS (function))
+	return false;
+    }
+  return true;
+}
 
 /* Detect whether the dynamic type of ARG of COMP_TYPE has changed (before
    callsite CALL) by looking for assignments to its virtual table pointer.  If
    it is, return true and fill in the jump function JFUNC with relevant type
    information or set it to unknown.  ARG is the object itself (not a pointer
    to it, unless dereferenced).  BASE is the base of the memory access as
-   returned by get_ref_base_and_extent, as is the offset.  */
+   returned by get_ref_base_and_extent, as is the offset. 
+
+   This is helper function for detect_type_change and detect_type_change_ssa
+   that does the heavy work which is usually unnecesary.  */
 
 static bool
-detect_type_change (tree arg, tree base, tree comp_type, gimple call,
-		    struct ipa_jump_func *jfunc, HOST_WIDE_INT offset)
+detect_type_change_from_memory_writes (tree arg, tree base, tree comp_type,
+				       gimple call, struct ipa_jump_func *jfunc,
+				       HOST_WIDE_INT offset)
 {
   struct type_change_info tci;
   ao_ref ao;
@@ -753,25 +780,6 @@ detect_type_change (tree arg, tree base,
 
   comp_type = TYPE_MAIN_VARIANT (comp_type);
 
-  if (!flag_devirtualize)
-    return false;
-
-  /* C++ methods are not allowed to change THIS pointer unless they
-     are constructors or destructors.  */
-  if (TREE_CODE	(base) == MEM_REF
-      && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME
-      && SSA_NAME_IS_DEFAULT_DEF (TREE_OPERAND (base, 0))
-      && TREE_CODE (SSA_NAME_VAR (TREE_OPERAND (base, 0))) == PARM_DECL
-      && TREE_CODE (TREE_TYPE (current_function_decl)) == METHOD_TYPE
-      && !DECL_CXX_CONSTRUCTOR_P (current_function_decl)
-      && !DECL_CXX_DESTRUCTOR_P (current_function_decl)
-      && (SSA_NAME_VAR (TREE_OPERAND (base, 0))
-	  == DECL_ARGUMENTS (current_function_decl)))
-    {
-      gcc_assert (comp_type);
-      return false;
-    }
-
   /* Const calls cannot call virtual methods through VMT and so type changes do
      not matter.  */
   if (!flag_devirtualize || !gimple_vuse (call)
@@ -809,6 +817,27 @@ detect_type_change (tree arg, tree base,
   return true;
 }
 
+/* Detect whether the dynamic type of ARG of COMP_TYPE may have changed.
+   If it is, return true and fill in the jump function JFUNC with relevant type
+   information or set it to unknown.  ARG is the object itself (not a pointer
+   to it, unless dereferenced).  BASE is the base of the memory access as
+   returned by get_ref_base_and_extent, as is the offset.  */
+
+static bool
+detect_type_change (tree arg, tree base, tree comp_type, gimple call,
+		    struct ipa_jump_func *jfunc, HOST_WIDE_INT offset)
+{
+  if (!flag_devirtualize)
+    return false;
+
+  if (TREE_CODE	(base) == MEM_REF
+      && !param_type_may_change_p (current_function_decl,
+				   TREE_OPERAND (base, 0)))
+    return false;
+  return detect_type_change_from_memory_writes (arg, base, comp_type,
+						call, jfunc, offset);
+}
+
 /* Like detect_type_change but ARG is supposed to be a non-dereferenced pointer
    SSA name (its dereference will become the base and the offset is assumed to
    be zero).  */
@@ -822,10 +851,14 @@ detect_type_change_ssa (tree arg, tree c
       || !POINTER_TYPE_P (TREE_TYPE (arg)))
     return false;
 
+  if (!param_type_may_change_p (current_function_decl, arg))
+    return false;
+
   arg = build2 (MEM_REF, ptr_type_node, arg,
 		build_int_cst (ptr_type_node, 0));
 
-  return detect_type_change (arg, arg, comp_type, call, jfunc, 0);
+  return detect_type_change_from_memory_writes (arg, arg, comp_type,
+						call, jfunc, 0);
 }
 
 /* Callback of walk_aliased_vdefs.  Flags that it has been invoked to the


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