[middle-end, patch 3/8] Rewritten jump functions calculation

Martin Jambor mjambor@suse.cz
Mon Jul 21 18:56:00 GMT 2008


Hi,

On Fri, Jul 18, 2008 at 12:33:30AM +0200, Jan Hubicka wrote:
> > 2008-07-15  Martin Jambor  <mjambor@suse.cz>
> > 
> > 	* ipa-prop.c (ipa_print_all_jump_functions): Moved here from
> > 	ipa-cp.c and split into two functions.
> > 	(ipa_print_node_jump_functions): New function.
> > 	(compute_scalar_jump_functions): New function.
> > 	(type_like_member_ptr_p): New function.
> > 	(compute_pass_through_member_ptrs): New function.
> > 	(fill_member_ptr_cst_jump_function): New function.
> > 	(determine_cst_member_ptr): New function.
> > 	(compute_cst_member_ptr_arguments): New function.
> > 	(ipa_compute_jump_functions): Complete rewrite.
> > 
> > 	* ipa-prop.h (enum jump_func_type): Make explicit that we depend
> > 	on IPA_UNKNOWN being zero. Added value IPA_CONST_MEMBER_PTR.
> > 	(struct ipa_member_ptr_cst): New structure.
> > 	(union jump_func_value): New field member_cst.
> > 
> > 	* ipa-cp.c (ipcp_lat_is_insertable): New function.
> > 	(ipcp_lattice_from_jfunc): Produces bottom lattices for unhandled
> > 	jump function types.
> > 	(ipcp_print_all_lattices): Slight fprintf rearrangement.
> > 	(ipcp_print_all_structures): Call ipa_print_all_jump_functions
> > 	instead of ipcp_print_all_jump_functions.
> > 	(ipcp_insert_stage): Use ipcp_lat_is_insertable, create replace maps
> > 	only for replacable scalars.
> > 
> > 
> > Index: iinln/gcc/ipa-prop.c
> > ===================================================================
> > --- iinln.orig/gcc/ipa-prop.c
> > +++ iinln/gcc/ipa-prop.c
> > @@ -239,92 +239,348 @@ ipa_count_arguments (struct cgraph_edge 
> >    ipa_set_cs_argument_count (IPA_EDGE_REF (cs), arg_num);
> >  }
> >  
> > -/* 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.  */
> > +/* The following function prints the jump functions of all arguments on all
> > +   call graph edges going from NODE to file F.  */
> 
> Hehe, this ended up quite unreadable.
> It would be better to send -c3p diffs.

Well,  I use quilt  default, I  have not  experimented with  quilt and
context  diffs yet,  even  though  it should  handle  those, at  least
according  to the man  pages.  I  have converted  the unified  diff to
context diff in emacs and will attach it to this message.

> > +/* The following function determines the jump functions of scalar arguments.
> > +   Scalar means SSA names and constants of a number of selected types.  INFO is
> > +   the ipa_node_params structure associated with the caller, FUNCTIONS is a
> > +   pointer to an array of jump function structures associated with CALL which
> > +   is the call statement being examined.*/
> > +static void
> > +compute_scalar_jump_functions (struct ipa_node_params *info,
> > +			       struct ipa_jump_func *functions,
> > +			       tree call)
> > +{
> > +  call_expr_arg_iterator iter;
> > +  tree arg;
> > +  int num = 0;
> > +
> > +  FOR_EACH_CALL_EXPR_ARG (arg, iter, call)
> > +    {
> > +      if (TREE_CODE (arg) == INTEGER_CST
> > +	  || TREE_CODE (arg) == REAL_CST
> > +	  || TREE_CODE (arg) == FIXED_CST)
> 
> It would be very nice to propagate over all invariants instead of
> listing selected "nice" guys.  I understand that this is how original
> code was written.
> 
> But perhaps simply dropping here is_gimple_constant would work?
> Or even add is_gimple_ipa_min_invariant or similar predicate that would
> be same as is_gimple_invariant allowing only addresses of static
> storage?
> Well, if the rest of code can't deal with this well, lets deal with this
> later.
> > +	{
> > +	  functions[num].type = IPA_CONST;
> > +	  functions[num].value.constant = arg;
> > +	}
> > +      else if (TREE_CODE (arg) == ADDR_EXPR)
> > +	{
> Similarly here, the logic should be more is_gimple_invariant_address_p
> check.. 

I did sort-of-that in my thesis and weird corner cases popped-up every
here and  there.  When  I attempted to  propagate addresses, I  had to
distinguish between local and global objects.  I would therefore leave
this as another requirement for the ipa-cp changes that will come next
after this is done.

> I wonder why value.constant expect declaration here for
> ADDR_EXPR arguments.  I would expect whole expression here, so component
> refs can be handled more easilly.

Yes, when we decide propagate pointers in general, we will probably
have to change this.

Let's postpone this for two months  too, it's difficult to get this in
as it is now.  I've started a new TODO file and put both of these in it.

> > +/* The following function traverses statements from CALL_STMT backwards,
> > +   scanning whether the argument ARG which is a member pointer is filled in
> > +   with constant values.  If it is, the jump function JFUNC is filled in
> > +   appropriately.  METHOD_FIELD and DELTA_FIELD are fields of the record type
> > +   of the member pointer.  */
> > +static void
> > +determine_cst_member_ptr (tree call_stmt, tree arg, tree method_field,
> > +			  tree delta_field, struct ipa_jump_func *jfunc)
> 
> I guess this pattern matching is OK, however I wonder why C++ frontend
> don't produce member pointer initializers dirrectly as:
>  member_ptr = {&func,delta};
> as this would translate to gimple_min_invariant and would be easier to
> match by optimizers...

It's no big deal.  

> (and I think your analysis could be easilly extended to constantly
> initialized aggregates in general.  Not sure if it is too important)

Well, I thought about that too but the lattices would get complex and
bigger for no obvious benefit and the code would have to be more
complex too so I settled just for the member pointers.

> 
> Please add example of gimple of pattern you are matching in comment.
> 

OK

> Otherwise patch is OK.

I have noticed a small leftover in determine_cst_member_ptr() which is
no longer necessary, this is the patch without it:

Thanks,

Martin


2008-07-21  Martin Jambor  <mjambor@suse.cz>

	* ipa-prop.c (ipa_print_all_jump_functions): Moved here from
	ipa-cp.c and split into two functions.
	(ipa_print_node_jump_functions): New function.
	(compute_scalar_jump_functions): New function.
	(type_like_member_ptr_p): New function.
	(compute_pass_through_member_ptrs): New function.
	(fill_member_ptr_cst_jump_function): New function.
	(determine_cst_member_ptr): New function.
	(compute_cst_member_ptr_arguments): New function.
	(ipa_compute_jump_functions): Complete rewrite.
	* ipa-prop.h (enum jump_func_type): Make explicit that we depend
	on IPA_UNKNOWN being zero. Added value IPA_CONST_MEMBER_PTR.
	(struct ipa_member_ptr_cst): New structure.
	(union jump_func_value): New field member_cst.
	* ipa-cp.c (ipcp_lat_is_insertable): New function.
	(ipcp_lattice_from_jfunc): Produces bottom lattices for unhandled
	jump function types.
	(ipcp_print_all_lattices): Slight fprintf rearrangement.
	(ipcp_print_all_structures): Call ipa_print_all_jump_functions
	instead of ipcp_print_all_jump_functions.
	(ipcp_insert_stage): Use ipcp_lat_is_insertable, create replace maps
	only for replacable scalars.


Index: iinln/gcc/ipa-prop.c
===================================================================
--- iinln.orig/gcc/ipa-prop.c
+++ iinln/gcc/ipa-prop.c
@@ -238,92 +238,341 @@ ipa_count_arguments (struct cgraph_edge 
   ipa_set_cs_argument_count (IPA_EDGE_REF (cs), arg_num);
 }
 
-/* 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.  */
+/* The following function prints the jump functions of all arguments on all
+   call graph edges going from NODE to file F.  */
 void
-ipa_compute_jump_functions (struct cgraph_edge *cs)
+ipa_print_node_jump_functions (FILE *f, struct cgraph_node *node)
 {
-  tree call_tree;
-  tree arg, cst_decl;
-  int arg_num;
-  struct cgraph_node *mt;
-  tree parm_decl;
-  struct function *curr_cfun;
-  call_expr_arg_iterator iter;
-  struct ipa_edge_args *args = IPA_EDGE_REF (cs);
+  int i, count;
+  struct cgraph_edge *cs;
+  struct ipa_jump_func *jump_func;
+  enum jump_func_type type;
 
-  if (ipa_get_cs_argument_count (args) == 0 || args->jump_functions)
-    return;
-  args->jump_functions = XCNEWVEC (struct ipa_jump_func,
-				   ipa_get_cs_argument_count (args));
-  call_tree = get_call_expr_in (cs->call_stmt);
-  gcc_assert (TREE_CODE (call_tree) == CALL_EXPR);
-  arg_num = 0;
+  fprintf (f, "JUMP FUNCTIONS OF CALLER  %s:\n", cgraph_node_name (node));
+  for (cs = node->callees; cs; cs = cs->next_callee)
+    {
+      if (!ipa_edge_args_info_available_for_edge_p (cs))
+	continue;
+
+      fprintf (f, "callsite  %s ", cgraph_node_name (node));
+      fprintf (f, "-> %s :: \n", cgraph_node_name (cs->callee));
+
+      count = ipa_get_cs_argument_count (IPA_EDGE_REF (cs));
+      for (i = 0; i < count; i++)
+	{
+	  jump_func = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), i);
+	  type = jump_func->type;
+
+	  fprintf (f, "  param %d: ", i);
+	  if (type == IPA_UNKNOWN)
+	    fprintf (f, "UNKNOWN\n");
+	  else if (type == IPA_CONST || type == IPA_CONST_REF)
+ 	    {
+	      tree val = jump_func->value.constant;
+	      fprintf (f, "CONST: ");
+	      print_generic_expr (f, val, 0);
+	      fprintf (f, "\n");
+	    }
+	  else if (type == IPA_CONST_MEMBER_PTR)
+	    {
+	      fprintf (f, "CONST MEMBER PTR: ");
+	      print_generic_expr (f, jump_func->value.member_cst.pfn, 0);
+	      fprintf (f, ", ");
+	      print_generic_expr (f, jump_func->value.member_cst.delta, 0);
+	      fprintf (f, "\n");
+	    }
+	  else if (type == IPA_PASS_THROUGH)
+ 	    {
+	      fprintf (f, "PASS THROUGH: ");
+	      fprintf (f, "%d\n", jump_func->value.formal_id);
+ 	    }
+	}
+    }
+}
+
+/* Print ipa_jump_func data structures of all nodes in the call graph to F.  */
+void
+ipa_print_all_jump_functions (FILE *f)
+{
+  struct cgraph_node *node;
 
-  FOR_EACH_CALL_EXPR_ARG (arg, iter, call_tree)
+  fprintf (f, "\nCALLSITE PARAM PRINT\n");
+  for (node = cgraph_nodes; node; node = node->next)
     {
-      /* If the formal parameter was passed as argument, we store 
-         IPA_PASS_THROUGH and its index in the caller as the jump function
-         of this argument.  */
-      if ((TREE_CODE (arg) == SSA_NAME
-	   && TREE_CODE (SSA_NAME_VAR (arg)) == PARM_DECL)
-	  || TREE_CODE (arg) == PARM_DECL)
+      ipa_print_node_jump_functions (f, node);
+    }
+}
+
+/* The following function determines the jump functions of scalar arguments.
+   Scalar means SSA names and constants of a number of selected types.  INFO is
+   the ipa_node_params structure associated with the caller, FUNCTIONS is a
+   pointer to an array of jump function structures associated with CALL which
+   is the call statement being examined.*/
+static void
+compute_scalar_jump_functions (struct ipa_node_params *info,
+			       struct ipa_jump_func *functions,
+			       tree call)
+{
+  call_expr_arg_iterator iter;
+  tree arg;
+  int num = 0;
+
+  FOR_EACH_CALL_EXPR_ARG (arg, iter, call)
+    {
+      if (TREE_CODE (arg) == INTEGER_CST
+	  || TREE_CODE (arg) == REAL_CST
+	  || TREE_CODE (arg) == FIXED_CST)
 	{
-	  struct ipa_node_params *info;
-	  int index;
+	  functions[num].type = IPA_CONST;
+	  functions[num].value.constant = arg;
+	}
+      else if (TREE_CODE (arg) == ADDR_EXPR)
+	{
+	  if (TREE_CODE (TREE_OPERAND (arg, 0)) == FUNCTION_DECL)
+	    {
+	      functions[num].type = IPA_CONST;
+	      functions[num].value.constant = TREE_OPERAND (arg, 0);
+	    }
+	  else if (TREE_CODE (TREE_OPERAND (arg, 0)) == CONST_DECL)
+	    {
+	      tree cst_decl = TREE_OPERAND (arg, 0);
 
-	  mt = cs->caller;
-	  info = IPA_NODE_REF (mt);
-	  parm_decl = TREE_CODE (arg) == PARM_DECL ? arg : SSA_NAME_VAR (arg);
-          
-	  index = ipa_get_param_decl_index (info, parm_decl);
-	  if (TREE_CODE (arg) == SSA_NAME && IS_VALID_JUMP_FUNC_INDEX (index))
+	      if (TREE_CODE (DECL_INITIAL (cst_decl)) == INTEGER_CST
+		  || TREE_CODE (DECL_INITIAL (cst_decl)) == REAL_CST
+		  || TREE_CODE (DECL_INITIAL (cst_decl)) == FIXED_CST)
+		{
+		  functions[num].type = IPA_CONST_REF;
+		  functions[num].value.constant = cst_decl;
+		}
+	    }
+ 	}
+      else if ((TREE_CODE (arg) == SSA_NAME) && SSA_NAME_IS_DEFAULT_DEF (arg))
+	{
+	  int index = ipa_get_param_decl_index (info, SSA_NAME_VAR (arg));
+
+	  if (index >= 0)
 	    {
-	      curr_cfun = DECL_STRUCT_FUNCTION (mt->decl);
-	      if (!gimple_default_def (curr_cfun, parm_decl)
-	          || gimple_default_def (curr_cfun, parm_decl) != arg)
-		info->param_flags[index].modified = true;
+	      functions[num].type = IPA_PASS_THROUGH;
+	      functions[num].value.formal_id = index;
 	    }
-	  if (!IS_VALID_JUMP_FUNC_INDEX (index)
-	      || ipa_is_ith_param_modified (info, index))
-	    args->jump_functions[arg_num].type = IPA_UNKNOWN;
-	  else
+	}
+
+      num++;
+    }
+}
+
+/* This function inspects the given TYPE and returns true iff it has the same
+   structure (the same number of fields of the same types) as a C++ member
+   pointer.  If METHOD_PTR and DELTA are non-NULL, the trees representing the
+   corresponding fields are stored there.  */
+static bool
+type_like_member_ptr_p (tree type, tree *method_ptr, tree *delta)
+{
+  tree fld;
+
+  if (TREE_CODE (type) != RECORD_TYPE)
+    return false;
+
+  fld = TYPE_FIELDS (type);
+  if (!fld || !POINTER_TYPE_P (TREE_TYPE (fld))
+      || TREE_CODE (TREE_TYPE (TREE_TYPE (fld))) != METHOD_TYPE)
+    return false;
+
+  if (method_ptr)
+    *method_ptr = fld;
+
+  fld = TREE_CHAIN (fld);
+  if (!fld || INTEGRAL_TYPE_P (fld))
+    return false;
+  if (delta)
+    *delta = fld;
+
+  if (TREE_CHAIN (fld))
+    return false;
+
+  return true;
+}
+
+/* This function goes through arguments of the CALL and for every one that
+   looks like a member pointer, it checks whether it can be safely declared
+   pass-through and if so, marks that to the corresponding item of jum
+   FUNCTIONS .  It returns true iff there were non-pass-through member pointers
+   within the arguments.  INFO describes formal parameters of the caller.  */
+static bool
+compute_pass_through_member_ptrs (struct ipa_node_params *info,
+				  struct ipa_jump_func *functions,
+				  tree call)
+{
+  call_expr_arg_iterator iter;
+  bool undecided_members = false;
+  int num = 0;
+  tree arg;
+
+  FOR_EACH_CALL_EXPR_ARG (arg, iter, call)
+    {
+      if (type_like_member_ptr_p (TREE_TYPE (arg), NULL, NULL))
+	{
+	  if (TREE_CODE (arg) == PARM_DECL)
 	    {
-	      args->jump_functions[arg_num].type = IPA_PASS_THROUGH;
-	      args->jump_functions[arg_num].value.formal_id = index;
+	      int index = ipa_get_param_decl_index (info, arg);
+
+	      gcc_assert (index >=0);
+	      if (!ipa_is_ith_param_modified (info, index))
+		{
+		  functions[num].type = IPA_PASS_THROUGH;
+		  functions[num].value.formal_id = index;
+		}
+	      else
+		undecided_members = true;
 	    }
+	  else
+	    undecided_members = true;
 	}
-      /* If a constant value was passed as argument, 
-         we store IPA_CONST and its value as the jump function
-         of this argument.  */
-      else if (TREE_CODE (arg) == INTEGER_CST
-	       || TREE_CODE (arg) == REAL_CST
-	       || TREE_CODE (arg) == FIXED_CST)
+
+      num++;
+    }
+
+  return undecided_members;
+}
+
+/* Simple function filling in a member pointer constant jump function (with PFN
+   and DELTA as the constant value) into JFUNC.  */
+static void
+fill_member_ptr_cst_jump_function (struct ipa_jump_func *jfunc,
+				   tree pfn, tree delta)
+{
+  jfunc->type = IPA_CONST_MEMBER_PTR;
+  jfunc->value.member_cst.pfn = pfn;
+  jfunc->value.member_cst.delta = delta;
+}
+
+/* Traverse statements from CALL_STMT backwards, scanning whether the argument
+   ARG which is a member pointer is filled in with constant values.  If it is,
+   fill the jump function JFUNC in appropriately.  METHOD_FIELD and DELTA_FIELD
+   are fields of the record type of the member pointer.  To give an example, we
+   look for a pattern looking like the following:  
+
+     D.2515.__pfn ={v} printStuff;
+     D.2515.__delta ={v} 0;
+     i_1 = doprinting (D.2515);  */
+static void
+determine_cst_member_ptr (tree call_stmt, tree arg, tree method_field,
+			  tree delta_field, struct ipa_jump_func *jfunc)
+{
+  block_stmt_iterator bsi;
+  tree method = NULL_TREE;
+  tree delta = NULL_TREE;
+
+  bsi = bsi_for_stmt (call_stmt);
+
+  bsi_prev (&bsi);
+  for (; !bsi_end_p (bsi); bsi_prev (&bsi))
+    {
+      tree stmt = bsi_stmt (bsi);
+      tree lhs, rhs, fld;
+
+      if (TREE_CODE (stmt) != GIMPLE_MODIFY_STMT)
+	return;
+
+      rhs = GIMPLE_STMT_OPERAND (stmt, 1);
+      if (TREE_CODE (rhs) == CALL_EXPR)
+	return;
+
+      lhs = GIMPLE_STMT_OPERAND (stmt, 0);
+
+      if (TREE_CODE (lhs) != COMPONENT_REF
+	  || TREE_OPERAND (lhs, 0) != arg)
+	continue;
+
+      fld = TREE_OPERAND (lhs, 1);
+      if (!method && fld == method_field)
 	{
-	  args->jump_functions[arg_num].type = IPA_CONST;
-	  args->jump_functions[arg_num].value.constant = arg;
+	  if (TREE_CODE (rhs) == ADDR_EXPR
+	      && TREE_CODE (TREE_OPERAND (rhs, 0)) == FUNCTION_DECL
+	      && TREE_CODE (TREE_TYPE (TREE_OPERAND (rhs, 0))) == METHOD_TYPE)
+	    {
+	      method = TREE_OPERAND (rhs, 0);
+	      if (delta)
+		{
+		  fill_member_ptr_cst_jump_function (jfunc, method, delta);
+		  return;
+		}
+	    }
+	  else
+	    return;
 	}
-      /* This is for the case of Fortran. If the address of a const_decl 
-         was passed as argument then we store
-         IPA_CONST_REF/IPA_CONST_REF and the constant
-         value as the jump function corresponding to this argument.  */
-      else if (TREE_CODE (arg) == ADDR_EXPR
-	       && TREE_CODE (TREE_OPERAND (arg, 0)) == CONST_DECL)
+
+      if (!delta && fld == delta_field)
 	{
-	  cst_decl = TREE_OPERAND (arg, 0);
-	  if (TREE_CODE (DECL_INITIAL (cst_decl)) == INTEGER_CST
-	      || TREE_CODE (DECL_INITIAL (cst_decl)) == REAL_CST
-	      || TREE_CODE (DECL_INITIAL (cst_decl)) == FIXED_CST)
+	  if (TREE_CODE (rhs) == INTEGER_CST)
 	    {
-	      args->jump_functions[arg_num].type = IPA_CONST_REF;
-	      args->jump_functions[arg_num].value.constant = cst_decl;
+	      delta = rhs;
+	      if (method)
+		{
+		  fill_member_ptr_cst_jump_function (jfunc, method, delta);
+		  return;
+		}
 	    }
+	  else
+	    return;
 	}
-      else
-	args->jump_functions[arg_num].type = IPA_UNKNOWN;
-      arg_num++;
     }
+
+  return;
+}
+
+/* Go through the arguments of the call in CALL_STMT and for every member
+   pointer within tries determine whether it is a constant.  If it is, create a
+   corresponding constant jump function in FUNCTIONS which is an array of jump
+   functions associated with the call.  */
+static void
+compute_cst_member_ptr_arguments (struct ipa_jump_func *functions,
+				  tree call_stmt)
+{
+  call_expr_arg_iterator iter;
+  int num = 0;
+  tree call = get_call_expr_in (call_stmt);
+  tree arg, method_field, delta_field;
+
+  FOR_EACH_CALL_EXPR_ARG (arg, iter, call)
+    {
+      if (functions[num].type == IPA_UNKNOWN
+	  && type_like_member_ptr_p (TREE_TYPE (arg), &method_field,
+				     &delta_field))
+	determine_cst_member_ptr (call_stmt, arg, method_field,
+				  delta_field, &functions[num]);
+
+      num++;
+    }
+}
+
+/* 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.  */
+void
+ipa_compute_jump_functions (struct cgraph_edge *cs)
+{
+  struct ipa_node_params *info = IPA_NODE_REF (cs->caller);
+  struct ipa_edge_args *arguments = IPA_EDGE_REF (cs);
+  tree call;
+
+  if (ipa_get_cs_argument_count (arguments) == 0 || arguments->jump_functions)
+    return;
+  arguments->jump_functions = XCNEWVEC (struct ipa_jump_func,
+					ipa_get_cs_argument_count (arguments));
+  call = get_call_expr_in (cs->call_stmt);
+
+  /* We will deal with constants and SSA scalars first:  */
+  compute_scalar_jump_functions (info, arguments->jump_functions, call);
+
+  /* Let's check whether there are any potential member pointers and if so,
+     whether we can determine their functions as pass_through.  */
+  if (!compute_pass_through_member_ptrs (info, arguments->jump_functions, call))
+    return;
+
+  /* Finally, let's check whether we actually pass a new constant membeer
+     pointer here...  */
+  compute_cst_member_ptr_arguments (arguments->jump_functions, cs->call_stmt);
 }
 
 /* Frees all dynamically allocated structures that the argument info points
Index: iinln/gcc/ipa-prop.h
===================================================================
--- iinln.orig/gcc/ipa-prop.h
+++ iinln/gcc/ipa-prop.h
@@ -32,21 +32,23 @@ along with GCC; see the file COPYING3.  
    Constant - a constant is passed as an actual argument.
    Unknown - neither of the above.
    Integer and real constants are represented as IPA_CONST and Fortran
-   constants are represented as IPA_CONST_REF.  */
+   constants are represented as IPA_CONST_REF.  Finally, IPA_CONST_MEMBER_PTR
+   stands for C++ member pointers constants.  */
 enum jump_func_type
 {
-  IPA_UNKNOWN,
+  IPA_UNKNOWN = 0,     /* newly allocated and zeroed jump functions default */
   IPA_CONST,
   IPA_CONST_REF,
+  IPA_CONST_MEMBER_PTR,
   IPA_PASS_THROUGH
 };
 
 /* All formal parameters in the program have a lattice associated with it
    computed by the interprocedural stage of IPCP.
    There are three main values of the lattice:
-   TOP - unknown.
-   BOTTOM - non constant.
-   CONSTANT_TYPE - constant value.
+   IPA_TOP - unknown,
+   IPA_BOTTOM - non constant,
+   IPA_CONST_VALUE - simple scalar constant,
    Cval of formal f will have a constant value if all callsites to this
    function have the same constant value passed to f.
    Integer and real constants are represented as IPA_CONST and Fortran
@@ -59,14 +61,24 @@ enum ipa_lattice_type
   IPA_TOP
 };
 
-/* Represents a value of a jump function.
-   value represents a constant.
-   formal_id is used only in jump function context and represents 
-   pass-through parameter (the formal of caller is passed as argument).  */
+/* Structure holding a C++ member pointer constant.  Holds a pointer to the
+   method and delta offset.  */
+struct ipa_member_ptr_cst
+{
+  tree pfn;
+  tree delta;
+};
+
+/* Represents a value of a jump function.  formal_id is used only in jump
+   function context and represents pass-through parameter (the formal parameter
+   of the caller is passed as argument).  constant represents the actual
+   constant in constant jump functions and member_cst holds constant c++ member
+   functions.  */
 union jump_func_value
 {
   unsigned int formal_id;
   tree constant;
+  struct ipa_member_ptr_cst member_cst;
 };
 
 /* A jump function for a callsite represents the values passed as actual 
@@ -333,5 +345,7 @@ void ipa_detect_param_modifications (str
 /* Debugging interface.  */
 void ipa_print_all_tree_maps (FILE *);
 void ipa_print_all_params_modified (FILE *);
+void ipa_print_node_jump_functions (FILE *f, struct cgraph_node *node);
+void ipa_print_all_jump_functions (FILE * f);
 
 #endif /* IPA_PROP_H */
Index: iinln/gcc/ipa-cp.c
===================================================================
--- iinln.orig/gcc/ipa-cp.c
+++ iinln/gcc/ipa-cp.c
@@ -183,6 +183,18 @@ ipcp_lat_is_const (struct ipcp_lattice *
     return false;
 }
 
+/* Return whether LAT is a constant lattice that ipa-cp can actually insert
+   into the code (i.e. constants excluding member pointers and pointers).  */
+static inline bool
+ipcp_lat_is_insertable (struct ipcp_lattice *lat)
+{
+  if ((lat->type == IPA_CONST_VALUE || lat->type == IPA_CONST_VALUE_REF)
+      && !POINTER_TYPE_P (TREE_TYPE (lat->constant)))
+    return true;
+  else
+    return false;
+}
+
 /* Return true if LAT1 and LAT2 are equal.  */
 static inline bool
 ipcp_lats_are_equal (struct ipcp_lattice *lat1, struct ipcp_lattice *lat2)
@@ -247,9 +259,7 @@ static void
 ipcp_lattice_from_jfunc (struct ipa_node_params *info, struct ipcp_lattice *lat,
 			 struct ipa_jump_func *jfunc)
 {
-  if (jfunc->type == IPA_UNKNOWN)
-    lat->type = IPA_BOTTOM;
-  else if (jfunc->type == IPA_CONST)
+  if (jfunc->type == IPA_CONST)
     {
       lat->type = IPA_CONST_VALUE;
       lat->constant = jfunc->value.constant;
@@ -267,6 +277,8 @@ ipcp_lattice_from_jfunc (struct ipa_node
       lat->type = caller_lat->type;
       lat->constant = caller_lat->constant;
     }
+  else
+    lat->type = IPA_BOTTOM;
 }
 
 /* True when OLD and NEW values are not the same.  */
@@ -303,17 +315,18 @@ ipcp_print_all_lattices (FILE * f)
       for (i = 0; i < count; i++)
 	{
 	  struct ipcp_lattice *lat = ipcp_get_ith_lattice (info, i);
+
+	  fprintf (f, " param [%d]: ", i);
 	  if (lat->type == IPA_CONST_VALUE || lat->type == IPA_CONST_VALUE_REF)
 	    {
-	      fprintf (f, " param [%d]: ", i);
 	      fprintf (f, "type is CONST ");
 	      print_generic_expr (f, lat->constant, 0);
 	      fprintf (f, "\n");
 	    }
 	  else if (lat->type == IPA_TOP)
-	    fprintf (f, "param [%d]: type is TOP  \n", i);
+	    fprintf (f, "type is TOP\n");
 	  else
-	    fprintf (f, "param [%d]: type is BOTTOM  \n", i);
+	    fprintf (f, "type is BOTTOM\n");
 	}
     }
 }
@@ -551,58 +564,6 @@ ipcp_node_not_modifiable_p (struct cgrap
   return false;
 }
 
-/* Print ipa_jump_func data structures to F.  */
-static void
-ipcp_print_all_jump_functions (FILE * f)
-{
-  struct cgraph_node *node;
-  int i, count;
-  struct cgraph_edge *cs;
-  struct ipa_jump_func *jump_func;
-  enum jump_func_type type;
-  tree info_type;
-
-  fprintf (f, "\nCALLSITE PARAM PRINT\n");
-  for (node = cgraph_nodes; node; node = node->next)
-    {
-      if (!node->analyzed)
-	continue;
-
-      for (cs = node->callees; cs; cs = cs->next_callee)
-	{
-	  fprintf (f, "callsite  %s ", cgraph_node_name (node));
-	  fprintf (f, "-> %s :: \n", cgraph_node_name (cs->callee));
-
-	  if (!ipa_edge_args_info_available_for_edge_p (cs)
-	      || ipa_is_called_with_var_arguments (IPA_NODE_REF (cs->callee)))
-	    continue;
-
-	  count = ipa_get_cs_argument_count (IPA_EDGE_REF (cs));
-	  for (i = 0; i < count; i++)
-	    {
-	      jump_func = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), i);
-	      type = jump_func->type;
-
-	      fprintf (f, " param %d: ", i);
-	      if (type == IPA_UNKNOWN)
-		fprintf (f, "UNKNOWN\n");
-	      else if (type == IPA_CONST || type == IPA_CONST_REF)
-		{
-		  info_type = jump_func->value.constant;
-		  fprintf (f, "CONST : ");
-		  print_generic_expr (f, info_type, 0);
-		  fprintf (f, "\n");
-		}
-	      else if (type == IPA_PASS_THROUGH)
-		{
-		  fprintf (f, "PASS THROUGH : ");
-		  fprintf (f, "%d\n", jump_func->value.formal_id);
-		}
-	    }
-	}
-    }
-}
-
 /* Print count scale data structures.  */
 static void
 ipcp_function_scale_print (FILE * f)
@@ -752,7 +713,7 @@ ipcp_print_all_structures (FILE * f)
   ipcp_function_scale_print (f);
   ipa_print_all_tree_maps (f);
   ipa_print_all_params_modified (f);
-  ipcp_print_all_jump_functions (f);
+  ipa_print_all_jump_functions (f);
 }
 
 /* Print profile info for all functions.  */
@@ -781,10 +742,8 @@ ipcp_create_replace_map (struct function
   tree const_val;
 
   replace_map = XCNEW (struct ipa_replace_map);
-  gcc_assert (ipcp_lat_is_const (lat));
-  if (lat->type != IPA_CONST_VALUE_REF
-      && is_gimple_reg (parm_tree) && gimple_default_def (func, parm_tree)
-	&& !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_default_def (func,
+  if (is_gimple_reg (parm_tree) && gimple_default_def (func, parm_tree)
+      && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_default_def (func,
 								 parm_tree)))
     {
       if (dump_file)
@@ -944,7 +903,7 @@ ipcp_insert_stage (void)
       for (i = 0; i < count; i++)
 	{
 	  struct ipcp_lattice *lat = ipcp_get_ith_lattice (info, i);
-	  if (ipcp_lat_is_const (lat))
+	  if (ipcp_lat_is_insertable (lat))
 	    const_param++;
 	}
       if (const_param == 0)
@@ -953,7 +912,8 @@ ipcp_insert_stage (void)
       for (i = 0; i < count; i++)
 	{
 	  struct ipcp_lattice *lat = ipcp_get_ith_lattice (info, i);
-	  if (ipcp_lat_is_const (lat))
+	  if (lat->type == IPA_CONST_VALUE
+	      && !POINTER_TYPE_P (TREE_TYPE (lat->constant)))
 	    {
 	      parm_tree = ipa_get_ith_param (info, i);
 	      replace_param =
@@ -990,7 +950,7 @@ ipcp_insert_stage (void)
 	  for (i = 0; i < count; i++)
 	    {
 	      struct ipcp_lattice *lat = ipcp_get_ith_lattice (info, i);
-	      if (ipcp_lat_is_const (lat))
+	      if (ipcp_lat_is_insertable (lat))
 		{
 		  parm_tree = ipa_get_ith_param (info, i);
 		  if (lat->type != IPA_CONST_VALUE_REF
-------------- next part --------------
A non-text attachment was scrubbed...
Name: rewrite_jmpfuncs_cntxt.diff
Type: text/x-patch
Size: 26804 bytes
Desc: not available
URL: <http://gcc.gnu.org/pipermail/gcc-patches/attachments/20080721/c3cdcdbd/attachment.bin>


More information about the Gcc-patches mailing list