Patchwork Fix OBJ_TYPE_REF handling in ipa-cp

login
register
mail settings
Submitter Jan Hubicka
Date Aug. 22, 2013, 3:33 p.m.
Message ID <20130822153350.GD19256@kam.mff.cuni.cz>
Download mbox | patch
Permalink /patch/269093/
State New
Headers show

Comments

Jan Hubicka - Aug. 22, 2013, 3:33 p.m.
Hi,
this problem was noticed by my verifier that binfo walks are not across type
hiearchy. ipa_intraprocedural_devirtualization is one remaining place where we
take class of object from OBJ_TYPE_REF_OBJECT instead of
obj_type_ref_class_type.

Unforutnately I noticed that this problem is propagated quite further across ipa-prop
design.  We assume that types of pointers taken from gimple call arguments
are types of pointers to classes pass down to the callee.  This is not true
after propagation.

I did not fix the all places, only places needed to get parameter for
ipa_set_jf_known_type and detect_type_change_ssa right. Also I modified
ipa_set_jf_known_type to not record non-polymorphic type. It is a waste
of memory and LTO streaming bandwidth.

Bootstrapped/regtesed x86_64-linux. Martin, please can you review the change?

	* ipa-prop.c (ipa_set_jf_known_type): Check that component type
	is a record type with BINFO.
	(detect_type_change_ssa):  Add comp_type argument.
	(compute_complex_assign_jump_func): Add param_type argument; pass
	it down to detect_type_change_ssa.
	(compute_known_type_jump_func): Add expected_type parameter.
	Do not bother tracking a non-polymorphic type.
	(ipa_get_callee_param_type): New function.
	(ipa_compute_jump_functions_for_edge): Pass down calle parm types.
	(ipa_analyze_virtual_call_uses): Use class typee as argument
	of detect_type_change_1.
	(ipa_intraprocedural_devirtualization): Pass down class type.
Martin Jambor - Aug. 26, 2013, 9:24 p.m.
Hi,

On Thu, Aug 22, 2013 at 05:33:50PM +0200, Jan Hubicka wrote:
> Hi,
> this problem was noticed by my verifier that binfo walks are not across type
> hiearchy. ipa_intraprocedural_devirtualization is one remaining place where we
> take class of object from OBJ_TYPE_REF_OBJECT instead of
> obj_type_ref_class_type.
> 
> Unforutnately I noticed that this problem is propagated quite further across ipa-prop
> design.  We assume that types of pointers taken from gimple call arguments
> are types of pointers to classes pass down to the callee.  This is not true
> after propagation.
> 
> I did not fix the all places, only places needed to get parameter
> for ipa_set_jf_known_type and detect_type_change_ssa right.  Also I
> modified ipa_set_jf_known_type to not record non-polymorphic
> type. It is a waste of memory and LTO streaming bandwidth.
> 
> Bootstrapped/regtesed x86_64-linux. Martin, please can you review the change?
> 
> 	* ipa-prop.c (ipa_set_jf_known_type): Check that component type
> 	is a record type with BINFO.
> 	(detect_type_change_ssa):  Add comp_type argument.
> 	(compute_complex_assign_jump_func): Add param_type argument; pass
> 	it down to detect_type_change_ssa.
> 	(compute_known_type_jump_func): Add expected_type parameter.
> 	Do not bother tracking a non-polymorphic type.
> 	(ipa_get_callee_param_type): New function.
> 	(ipa_compute_jump_functions_for_edge): Pass down calle parm types.
> 	(ipa_analyze_virtual_call_uses): Use class typee as argument
> 	of detect_type_change_1.
> 	(ipa_intraprocedural_devirtualization): Pass down class type.

Hopefully I'll get rid of the component_types in the jump functions
and most of this won't be necesary.  Meanwhile, this is OK.

Thanks,

Martin

Patch

Index: ipa-prop.c
===================================================================
--- ipa-prop.c	(revision 201919)
+++ ipa-prop.c	(working copy)
@@ -367,6 +367,8 @@  static void
 ipa_set_jf_known_type (struct ipa_jump_func *jfunc, HOST_WIDE_INT offset,
 		       tree base_type, tree component_type)
 {
+  gcc_assert (TREE_CODE (component_type) == RECORD_TYPE
+	      && TYPE_BINFO (component_type));
   jfunc->type = IPA_JF_KNOWN_TYPE;
   jfunc->value.known_type.offset = offset,
   jfunc->value.known_type.base_type = base_type;
@@ -674,20 +676,18 @@  detect_type_change (tree arg, tree base,
 
 /* 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).  */
+   be zero).  COMP_TYPE is type of object being tracked.  */
 
 static bool
-detect_type_change_ssa (tree arg, gimple call, struct ipa_jump_func *jfunc)
+detect_type_change_ssa (tree arg, tree comp_type,
+			gimple call, struct ipa_jump_func *jfunc)
 {
-  tree comp_type;
-
   gcc_checking_assert (TREE_CODE (arg) == SSA_NAME);
   if (!flag_devirtualize
       || !POINTER_TYPE_P (TREE_TYPE (arg))
       || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != RECORD_TYPE)
     return false;
 
-  comp_type = TREE_TYPE (TREE_TYPE (arg));
   arg = build2 (MEM_REF, ptr_type_node, arg,
 		build_int_cst (ptr_type_node, 0));
 
@@ -961,13 +961,16 @@  ipa_load_from_parm_agg (struct ipa_node_
 
    INFO is the structure describing individual parameters access different
    stages of IPA optimizations.  PARMS_AINFO contains the information that is
-   only needed for intraprocedural analysis.  */
+   only needed for intraprocedural analysis. 
+
+   PARAM_TYPE is type of the parameter, NULL if not available.  */
 
 static void
 compute_complex_assign_jump_func (struct ipa_node_params *info,
 				  struct param_analysis_info *parms_ainfo,
 				  struct ipa_jump_func *jfunc,
-				  gimple call, gimple stmt, tree name)
+				  gimple call, gimple stmt, tree name,
+				  tree param_type)
 {
   HOST_WIDE_INT offset, size, max_size;
   tree op1, tc_ssa, base, ssa;
@@ -1006,7 +1009,10 @@  compute_complex_assign_jump_func (struct
 					 gimple_assign_rhs_code (stmt));
 	}
       else if (gimple_assign_single_p (stmt)
-	       && !detect_type_change_ssa (tc_ssa, call, jfunc))
+	       && param_type
+	       && !detect_type_change_ssa (tc_ssa,
+					   TREE_TYPE (param_type),
+					   call, jfunc))
 	{
 	  bool agg_p = parm_ref_data_pass_through_p (&parms_ainfo[index],
 						     call, tc_ssa);
@@ -1171,18 +1177,25 @@  compute_complex_ancestor_jump_func (stru
 
 /* Given OP which is passed as an actual argument to a called function,
    determine if it is possible to construct a KNOWN_TYPE jump function for it
-   and if so, create one and store it to JFUNC.  */
+   and if so, create one and store it to JFUNC.
+   EXPECTED_TYPE represents a type the argument should be in  */
 
 static void
 compute_known_type_jump_func (tree op, struct ipa_jump_func *jfunc,
-			      gimple call)
+			      gimple call, tree expected_type)
 {
   HOST_WIDE_INT offset, size, max_size;
   tree base;
 
   if (!flag_devirtualize
       || TREE_CODE (op) != ADDR_EXPR
-      || TREE_CODE (TREE_TYPE (TREE_TYPE (op))) != RECORD_TYPE)
+      || TREE_CODE (TREE_TYPE (TREE_TYPE (op))) != RECORD_TYPE
+      /* Do not bother to track types that are not polymorphic.
+	 We use type knowledge only for devirtualization.  */
+      || !expected_type
+      || TREE_CODE (expected_type) != RECORD_TYPE
+      || !TYPE_BINFO (expected_type)
+      || !BINFO_VTABLE (TYPE_BINFO (expected_type)))
     return;
 
   op = TREE_OPERAND (op, 0);
@@ -1194,11 +1207,11 @@  compute_known_type_jump_func (tree op, s
       || is_global_var (base))
     return;
 
-  if (!TYPE_BINFO (TREE_TYPE (base))
-      || detect_type_change (op, base, call, jfunc, offset))
+  if (detect_type_change_1 (op, base, expected_type, call, jfunc, offset))
     return;
 
-  ipa_set_jf_known_type (jfunc, offset, TREE_TYPE (base), TREE_TYPE (op));
+  ipa_set_jf_known_type (jfunc, offset, TREE_TYPE (base),
+			 expected_type);
 }
 
 /* Inspect the given TYPE and return true iff it has the same structure (the
@@ -1469,6 +1482,42 @@  determine_known_aggregate_parts (gimple
     }
 }
 
+/* Return type of I-th parameter of callee of E.  This may differ from
+   type of I-th argument of call operand of E->call_stmt because
+   pointer conversions are considered useless.  For devirtualization
+   we really need the type of object being passed.  */
+
+static tree
+ipa_get_callee_param_type (struct cgraph_edge *e, int i)
+{
+  int n;
+  tree type = (e->callee
+	       ? TREE_TYPE (e->callee->symbol.decl)
+	       : gimple_call_fntype (e->call_stmt));
+  tree t = TYPE_ARG_TYPES (type);
+
+  for (n = 0; n < i; n++)
+    {
+      if (!t)
+        break;
+      t = TREE_CHAIN (t);
+    }
+  if (t)
+    return TREE_VALUE (t);
+  if (!e->callee)
+    return NULL;
+  t = DECL_ARGUMENTS (e->callee->symbol.decl);
+  for (n = 0; n < i; n++)
+    {
+      if (!t)
+	return NULL;
+      t = TREE_CHAIN (t);
+    }
+  if (t)
+    return TREE_TYPE (t);
+  return NULL;
+}
+
 /* Compute jump function for all arguments of callsite CS and insert the
    information in the jump_functions array in the ipa_edge_args corresponding
    to this callsite.  */
@@ -1493,6 +1542,7 @@  ipa_compute_jump_functions_for_edge (str
     {
       struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, n);
       tree arg = gimple_call_arg (call, n);
+      tree param_type = ipa_get_callee_param_type (cs, n);
 
       if (is_gimple_ip_invariant (arg))
 	ipa_set_jf_constant (jfunc, arg, cs);
@@ -1517,7 +1567,8 @@  ipa_compute_jump_functions_for_edge (str
 	    {
 	      int index = ipa_get_param_decl_index (info, SSA_NAME_VAR (arg));
 	      if (index >= 0
-		  && !detect_type_change_ssa (arg, call, jfunc))
+		  && !detect_type_change_ssa (arg, TREE_TYPE (TREE_TYPE (arg)),
+					      call, jfunc))
 		{
 		  bool agg_p;
 		  agg_p = parm_ref_data_pass_through_p (&parms_ainfo[index],
@@ -1530,14 +1581,17 @@  ipa_compute_jump_functions_for_edge (str
 	      gimple stmt = SSA_NAME_DEF_STMT (arg);
 	      if (is_gimple_assign (stmt))
 		compute_complex_assign_jump_func (info, parms_ainfo, jfunc,
-						  call, stmt, arg);
+						  call, stmt, arg, param_type);
 	      else if (gimple_code (stmt) == GIMPLE_PHI)
 		compute_complex_ancestor_jump_func (info, parms_ainfo, jfunc,
 						    call, stmt);
 	    }
 	}
       else
-	compute_known_type_jump_func (arg, jfunc, call);
+	compute_known_type_jump_func (arg, jfunc, call,
+				      param_type
+				      ? TREE_TYPE (param_type)
+				      : NULL);
 
       if ((jfunc->type != IPA_JF_PASS_THROUGH
 	      || !ipa_get_jf_pass_through_agg_preserved (jfunc))
@@ -1881,7 +1935,8 @@  ipa_analyze_virtual_call_uses (struct cg
       anc_offset = 0;
       index = ipa_get_param_decl_index (info, SSA_NAME_VAR (obj));
       gcc_assert (index >= 0);
-      if (detect_type_change_ssa (obj, call, &jfunc))
+      if (detect_type_change_ssa (obj, obj_type_ref_class (target),
+				  call, &jfunc))
 	return;
     }
   else
@@ -1895,7 +1950,8 @@  ipa_analyze_virtual_call_uses (struct cg
       index = ipa_get_param_decl_index (info,
 					SSA_NAME_VAR (TREE_OPERAND (expr, 0)));
       gcc_assert (index >= 0);
-      if (detect_type_change (obj, expr, call, &jfunc, anc_offset))
+      if (detect_type_change_1 (obj, expr, obj_type_ref_class (target),
+				call, &jfunc, anc_offset))
 	return;
     }
 
@@ -2107,7 +2163,7 @@  ipa_intraprocedural_devirtualization (gi
 
   jfunc.type = IPA_JF_UNKNOWN;
   compute_known_type_jump_func (OBJ_TYPE_REF_OBJECT (otr), &jfunc,
-				call);
+				call, obj_type_ref_class (otr));
   if (jfunc.type != IPA_JF_KNOWN_TYPE)
     return NULL_TREE;
   binfo = ipa_binfo_from_known_type_jfunc (&jfunc);