diff mbox

Add predicate to test if type contains polymorphic type

Message ID 20140702074107.GD27906@kam.mff.cuni.cz
State New
Headers show

Commit Message

Jan Hubicka July 2, 2014, 7:41 a.m. UTC
Hi,
this patch adds predicate contains_polymorphic_type_p.  This can be used
in the ICF pass - if one of the types is contains_polymorphic_type_p,
then TYPE_MAIN_VARIANTs of both types should be the same, at least for
now.  Of course it would be possible to compare types for equality and then
also polymorphic types for equality (i.e. that all virtual functions in
vtables are equivalent).  I am not sure how much that matters
and we can definitely implement that incrementally.

I also changed ipa-prop to use the predicate - this lifts the unnecesary
restriction that type propagation needs to be done only on polymorphic types;
it makes perfect sense to propagate a knowledge that type contains fileds
that are polymorphic.
To do this in full generality the propagation engine has to be updated to
not work on binfos though.

Bootstrapped/regtested x86_64-linux, will commit it shortly.

Honza

	* ipa-utils.h (method_class_type, vtable_pointer_value_to_binfo,
	vtable_pointer_value_to_vtable): Constify.
	(contains_polymorphic_type_p): Declare.
	* ipa-devirt.c (method_class_type, vtable_pointer_value_to_binfo,
	vtable_pointer_value_to_vtable): Constify.
	(contains_polymorphic_type_p): New predicate.
	* ipa-prop.c (ipa_set_jf_known_type): Allow types containing
	polymorphic types.
	(ipa_set_ancestor_jf): Likewise.
	(detect_type_change): Return false in easy cases.
	(compute_complex_assign_jump_func): Require type to contain
	polymorphic type.
	(compute_known_type_jump_func): Likewise.
diff mbox

Patch

Index: ipa-utils.h
===================================================================
--- ipa-utils.h	(revision 212217)
+++ ipa-utils.h	(working copy)
@@ -83,15 +83,16 @@  void dump_possible_polymorphic_call_targ
 					     const ipa_polymorphic_call_context &);
 bool possible_polymorphic_call_target_p (tree, HOST_WIDE_INT,
 				         const ipa_polymorphic_call_context &,
-					 struct cgraph_node *n);
-tree method_class_type (tree);
+					 struct cgraph_node *);
+tree method_class_type (const_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 *);
+tree vtable_pointer_value_to_binfo (const_tree);
+bool vtable_pointer_value_to_vtable (const_tree, tree *, unsigned HOST_WIDE_INT *);
+bool contains_polymorphic_type_p (const_tree);
 
 /* Return vector containing possible targets of polymorphic call E.
    If FINALP is non-NULL, store true if the list is complette. 
Index: ipa-devirt.c
===================================================================
--- ipa-devirt.c	(revision 212218)
+++ ipa-devirt.c	(working copy)
@@ -742,7 +742,7 @@  dump_type_inheritance_graph (FILE *f)
    Lookup this pointer and get its type.    */
 
 tree
-method_class_type (tree t)
+method_class_type (const_tree t)
 {
   tree first_parm_type = TREE_VALUE (TYPE_ARG_TYPES (t));
   gcc_assert (TREE_CODE (t) == METHOD_TYPE);
@@ -1187,6 +1187,31 @@  devirt_node_removal_hook (struct cgraph_
     free_polymorphic_call_targets_hash ();
 }
 
+/* Return true when TYPE contains an polymorphic type and thus is interesting
+   for devirtualization machinery.  */
+
+bool
+contains_polymorphic_type_p (const_tree type)
+{
+  type = TYPE_MAIN_VARIANT (type);
+
+  if (RECORD_OR_UNION_TYPE_P (type))
+    {
+      if (TYPE_BINFO (type)
+          && polymorphic_type_binfo_p (TYPE_BINFO (type)))
+	return true;
+      for (tree fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld))
+	if (TREE_CODE (fld) == FIELD_DECL
+	    && !DECL_ARTIFICIAL (fld)
+	    && contains_polymorphic_type_p (TREE_TYPE (fld)))
+	  return true;
+      return false;
+    }
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    return contains_polymorphic_type_p (TREE_TYPE (type));
+  return false;
+}
+
 /* CONTEXT->OUTER_TYPE is a type of memory object where object of EXPECTED_TYPE
    is contained at CONTEXT->OFFSET.  Walk the memory representation of
    CONTEXT->OUTER_TYPE and find the outermost class type that match
@@ -1349,7 +1374,8 @@  subbinfo_with_vtable_at_offset (tree bin
    Return false if T does not look like virtual table reference.  */
 
 bool
-vtable_pointer_value_to_vtable (tree t, tree *v, unsigned HOST_WIDE_INT *offset)
+vtable_pointer_value_to_vtable (const_tree t, tree *v,
+				unsigned HOST_WIDE_INT *offset)
 {
   /* We expect &MEM[(void *)&virtual_table + 16B].
      We obtain object's BINFO from the context of the virtual table. 
@@ -1395,7 +1421,7 @@  vtable_pointer_value_to_vtable (tree t,
    instance type.  */
 
 tree
-vtable_pointer_value_to_binfo (tree t)
+vtable_pointer_value_to_binfo (const_tree t)
 {
   tree vtable;
   unsigned HOST_WIDE_INT offset;
Index: ipa-prop.c
===================================================================
--- ipa-prop.c	(revision 212217)
+++ ipa-prop.c	(working copy)
@@ -443,11 +443,10 @@  ipa_set_jf_known_type (struct ipa_jump_f
   base_type = TYPE_MAIN_VARIANT (base_type);
   component_type = TYPE_MAIN_VARIANT (component_type);
 
-  gcc_assert (TREE_CODE (component_type) == RECORD_TYPE
-	      && TYPE_BINFO (component_type));
+  gcc_assert (contains_polymorphic_type_p (base_type)
+	      && contains_polymorphic_type_p (component_type));
   if (!flag_devirtualize)
     return;
-  gcc_assert (BINFO_VTABLE (TYPE_BINFO (component_type)));
   jfunc->type = IPA_JF_KNOWN_TYPE;
   jfunc->value.known_type.offset = offset,
   jfunc->value.known_type.base_type = base_type;
@@ -534,12 +533,11 @@  ipa_set_ancestor_jf (struct ipa_jump_fun
 {
   if (!flag_devirtualize)
     type_preserved = false;
+  if (!type_preserved)
+    type = NULL_TREE;
   if (type)
     type = TYPE_MAIN_VARIANT (type);
-  gcc_assert (!type_preserved
-	      || (TREE_CODE (type) == RECORD_TYPE
-		  && TYPE_BINFO (type)
-		  && BINFO_VTABLE (TYPE_BINFO (type))));
+  gcc_assert (!type_preserved || contains_polymorphic_type_p (type));
   jfunc->type = IPA_JF_ANCESTOR;
   jfunc->value.ancestor.formal_id = formal_id;
   jfunc->value.ancestor.offset = offset;
@@ -752,18 +750,12 @@  detect_type_change (tree arg, tree base,
   gcc_checking_assert (DECL_P (arg)
 		       || TREE_CODE (arg) == MEM_REF
 		       || handled_component_p (arg));
-  /* Const calls cannot call virtual methods through VMT and so type changes do
-     not matter.  */
-  if (!flag_devirtualize || !gimple_vuse (call)
-      /* Be sure expected_type is polymorphic.  */
-      || !comp_type
-      || TREE_CODE (comp_type) != RECORD_TYPE
-      || !TYPE_BINFO (TYPE_MAIN_VARIANT (comp_type))
-      || !BINFO_VTABLE (TYPE_BINFO (TYPE_MAIN_VARIANT (comp_type))))
-    return true;
 
   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
@@ -775,7 +767,20 @@  detect_type_change (tree arg, tree base,
       && !DECL_CXX_DESTRUCTOR_P (current_function_decl)
       && (SSA_NAME_VAR (TREE_OPERAND (base, 0))
 	  == DECL_ARGUMENTS (current_function_decl)))
-    return false;
+    {
+      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)
+      /* Be sure expected_type is polymorphic.  */
+      || !comp_type
+      || TREE_CODE (comp_type) != RECORD_TYPE
+      || !TYPE_BINFO (TYPE_MAIN_VARIANT (comp_type))
+      || !BINFO_VTABLE (TYPE_BINFO (TYPE_MAIN_VARIANT (comp_type))))
+    return true;
 
   ao_ref_init (&ao, arg);
   ao.base = base;
@@ -1258,8 +1263,9 @@  compute_complex_assign_jump_func (struct
   index = ipa_get_param_decl_index (info, SSA_NAME_VAR (ssa));
   if (index >= 0 && param_type && POINTER_TYPE_P (param_type))
     {
-      bool type_p = !detect_type_change (op1, base, TREE_TYPE (param_type),
-					 call, jfunc, offset);
+      bool type_p = (contains_polymorphic_type_p (TREE_TYPE (param_type))
+		     && !detect_type_change (op1, base, TREE_TYPE (param_type),
+					     call, jfunc, offset));
       if (type_p || jfunc->type == IPA_JF_UNKNOWN)
 	ipa_set_ancestor_jf (jfunc, offset,
 			     type_p ? TREE_TYPE (param_type) : NULL, index,
@@ -1391,7 +1397,8 @@  compute_complex_ancestor_jump_func (stru
     }
 
   bool type_p = false;
-  if (param_type && POINTER_TYPE_P (param_type))
+  if (param_type && POINTER_TYPE_P (param_type)
+      && contains_polymorphic_type_p (TREE_TYPE (param_type)))
     type_p = !detect_type_change (obj, expr, TREE_TYPE (param_type),
 				  call, jfunc, offset);
   if (type_p || jfunc->type == IPA_JF_UNKNOWN)
@@ -1415,12 +1422,10 @@  compute_known_type_jump_func (tree op, s
 
   if (!flag_devirtualize
       || TREE_CODE (op) != ADDR_EXPR
-      || TREE_CODE (TREE_TYPE (TREE_TYPE (op))) != RECORD_TYPE
+      || !contains_polymorphic_type_p (TREE_TYPE (TREE_TYPE (op)))
       /* Be sure expected_type is polymorphic.  */
       || !expected_type
-      || TREE_CODE (expected_type) != RECORD_TYPE
-      || !TYPE_BINFO (TYPE_MAIN_VARIANT (expected_type))
-      || !BINFO_VTABLE (TYPE_BINFO (TYPE_MAIN_VARIANT (expected_type))))
+      || !contains_polymorphic_type_p (expected_type))
     return;
 
   op = TREE_OPERAND (op, 0);
@@ -1428,7 +1433,7 @@  compute_known_type_jump_func (tree op, s
   if (!DECL_P (base)
       || max_size == -1
       || max_size != size
-      || TREE_CODE (TREE_TYPE (base)) != RECORD_TYPE
+      || !contains_polymorphic_type_p (TREE_TYPE (base))
       || is_global_var (base))
     return;