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]

Fix IPCP's propagation of constants to versioned functions


Hi,
some testcases in testsupte now breaks with IPCP enabled, because we try to
replace SSA names by non-gimple invariants.  This patch puts IPCP out of
busyness of updating clonned function to replace arguments by constants and use
instead existing logic in setup_one_argument that does all the neccesary
gimplification and casts and works in all cases.

Bootstrapped/regtested x86_64-linux with ipcp enabled; will commit it after
re-testing with ipcp disabled.

	* ipa-cp.c (constant_val_insert): Remove.
	(ipcp_propagate_one_const): Remove.
	(ipcp_create_replace_map): Always insert replacements to the map.
	(ipcp_insert_stage): Do not try to insert statements by hand.
	* tree-inline.c (insert_init_stmt): Break out from ...
	(setup_one_parameter): ... here; allow NULL BB pointer.
	(tree_function_versioning): Use setup_one_parameter to process
	replacement map.
Index: ipa-cp.c
===================================================================
*** ipa-cp.c	(revision 139523)
--- ipa-cp.c	(working copy)
*************** ipcp_initialize_node_lattices (struct cg
*** 369,388 ****
      ipcp_get_ith_lattice (info, i)->type = IPA_TOP;
  }
  
- /* Create a new assignment statement and make it the first statement in the
-    function.  PARM1 is the lhs of the assignment and VAL is the rhs. */
- static void
- constant_val_insert (tree parm1 ATTRIBUTE_UNUSED, tree val ATTRIBUTE_UNUSED)
- {
-   gimple init_stmt = NULL;
-   edge e_step;
- 
-   init_stmt = gimple_build_assign (parm1, val);
-   gcc_assert (init_stmt);
-   e_step = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun));
-   gsi_insert_on_edge_immediate (e_step, init_stmt);
- }
- 
  /* build INTEGER_CST tree with type TREE_TYPE and value according to LAT.
     Return the tree.  */
  static tree
--- 369,374 ----
*************** build_const_val (struct ipcp_lattice *la
*** 403,423 ****
    return val;
  }
  
- /* Build the tree representing the constant and call constant_val_insert().  */
- static void
- ipcp_propagate_one_const (struct cgraph_node *node, int param,
- 			  struct ipcp_lattice *lat)
- {
-   tree const_val;
-   tree parm_tree;
- 
-   if (dump_file)
-     fprintf (dump_file, "propagating const to %s\n", cgraph_node_name (node));
-   parm_tree = ipa_get_ith_param (IPA_NODE_REF (node), param);
-   const_val = build_const_val (lat, TREE_TYPE (parm_tree));
-   constant_val_insert (parm_tree, const_val);
- }
- 
  /* Compute the proper scale for NODE.  It is the ratio between the number of
     direct calls (represented on the incoming cgraph_edges) and sum of all
     invocations of NODE (represented as count in cgraph_node).  */
--- 389,394 ----
*************** ipcp_print_profile_data (FILE * f)
*** 755,787 ****
     PARM_TREE is the formal parameter found to be constant.  LAT represents the
     constant.  */
  static struct ipa_replace_map *
! ipcp_create_replace_map (struct function *func, tree parm_tree,
! 			 struct ipcp_lattice *lat)
  {
    struct ipa_replace_map *replace_map;
    tree const_val;
  
    replace_map = XCNEW (struct ipa_replace_map);
!   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)
! 	fprintf (dump_file, "replacing param with const\n");
!       const_val = build_const_val (lat, TREE_TYPE (parm_tree));
!       replace_map->old_tree =gimple_default_def (func, parm_tree);
!       replace_map->new_tree = const_val;
!       replace_map->replace_p = true;
!       replace_map->ref_p = false;
!     }
!   else
!     {
!       replace_map->old_tree = NULL;
!       replace_map->new_tree = NULL;
!       replace_map->replace_p = false;
!       replace_map->ref_p = false;
!     }
  
    return replace_map;
  }
--- 726,744 ----
     PARM_TREE is the formal parameter found to be constant.  LAT represents the
     constant.  */
  static struct ipa_replace_map *
! ipcp_create_replace_map (tree parm_tree, struct ipcp_lattice *lat)
  {
    struct ipa_replace_map *replace_map;
    tree const_val;
  
    replace_map = XCNEW (struct ipa_replace_map);
!   if (dump_file)
!     fprintf (dump_file, "replacing param with const\n");
!   const_val = build_const_val (lat, TREE_TYPE (parm_tree));
!   replace_map->old_tree = parm_tree;
!   replace_map->new_tree = const_val;
!   replace_map->replace_p = true;
!   replace_map->ref_p = false;
  
    return replace_map;
  }
*************** ipcp_insert_stage (void)
*** 939,946 ****
  	    {
  	      parm_tree = ipa_get_ith_param (info, i);
  	      replace_param =
! 		ipcp_create_replace_map (DECL_STRUCT_FUNCTION (node->decl),
! 					 parm_tree, lat);
  	      VARRAY_PUSH_GENERIC_PTR (replace_trees, replace_param);
  	    }
  	}
--- 896,902 ----
  	    {
  	      parm_tree = ipa_get_ith_param (info, i);
  	      replace_param =
! 		ipcp_create_replace_map (parm_tree, lat);
  	      VARRAY_PUSH_GENERIC_PTR (replace_trees, replace_param);
  	    }
  	}
*************** ipcp_insert_stage (void)
*** 963,998 ****
  	fprintf (dump_file, "versioned function %s\n",
  		 cgraph_node_name (node));
        ipcp_init_cloned_node (node, node1);
!       if (const_param > 0)
! 	{
! 	  push_cfun (DECL_STRUCT_FUNCTION (node1->decl));
! 	  gimple_register_cfg_hooks ();
! 	  current_function_decl = node1->decl;
! 
! 	  for (i = 0; i < count; i++)
! 	    {
! 	      struct ipcp_lattice *lat = ipcp_get_ith_lattice (info, i);
! 	      if (ipcp_lat_is_insertable (lat))
! 		{
! 		  parm_tree = ipa_get_ith_param (info, i);
! 		  if (!is_gimple_reg (parm_tree))
! 		    ipcp_propagate_one_const (node1, i, lat);
! 		}
! 	    }
! 	  if (gimple_in_ssa_p (cfun))
! 	    {
! 	      update_ssa (TODO_update_ssa);
! #ifdef   ENABLE_CHECKING
! 	      verify_ssa (true);
! #endif
! 	    }
! 	  free_dominance_info (CDI_DOMINATORS);
! 	  free_dominance_info (CDI_POST_DOMINATORS);
! 	  pop_cfun ();
! 	  current_function_decl = NULL;
! 	  /* We've possibly introduced direct calls.  */
! 	  ipcp_update_cloned_node (node1);
! 	}
  
        if (dump_file)
  	dump_function_to_file (node1->decl, dump_file, dump_flags);
--- 919,926 ----
  	fprintf (dump_file, "versioned function %s\n",
  		 cgraph_node_name (node));
        ipcp_init_cloned_node (node, node1);
!       /* We've possibly introduced direct calls.  */
!       ipcp_update_cloned_node (node1);
  
        if (dump_file)
  	dump_function_to_file (node1->decl, dump_file, dump_flags);
Index: tree-inline.c
===================================================================
*** tree-inline.c	(revision 139523)
--- tree-inline.c	(working copy)
*************** self_inlining_addr_expr (tree value, tre
*** 1856,1865 ****
  }
  
  static void
  setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
  		     basic_block bb, tree *vars)
  {
!   gimple init_stmt;
    tree var;
    tree rhs = value;
    tree def = (gimple_in_ssa_p (cfun)
--- 1856,1907 ----
  }
  
  static void
+ insert_init_stmt (basic_block bb, gimple init_stmt)
+ {
+   gimple_stmt_iterator si = gsi_last_bb (bb);
+   gimple_stmt_iterator i;
+   gimple_seq seq = gimple_seq_alloc ();
+   struct gimplify_ctx gctx;
+ 
+   push_gimplify_context (&gctx);
+ 
+   i = gsi_start (seq);
+   gimple_regimplify_operands (init_stmt, &i);
+ 
+   if (gimple_in_ssa_p (cfun)
+       && init_stmt
+       && !gimple_seq_empty_p (seq))
+     {
+       /* The replacement can expose previously unreferenced
+ 	 variables.  */
+       for (i = gsi_start (seq); !gsi_end_p (i); gsi_next (&i))
+ 	find_new_referenced_vars (gsi_stmt (i));
+ 
+       /* Insert the gimplified sequence needed for INIT_STMT
+ 	 after SI.  INIT_STMT will be inserted after SEQ.  */
+       gsi_insert_seq_after (&si, seq, GSI_NEW_STMT);
+      }
+ 
+   pop_gimplify_context (NULL);
+ 
+   /* If VAR represents a zero-sized variable, it's possible that the
+      assignment statement may result in no gimple statements.  */
+   if (init_stmt)
+     gsi_insert_after (&si, init_stmt, GSI_NEW_STMT);
+ 
+   if (gimple_in_ssa_p (cfun))
+     for (;!gsi_end_p (si); gsi_next (&si))
+       mark_symbols_for_renaming (gsi_stmt (si));
+ }
+ 
+ /* Initialize parameter P with VALUE.  If needed, produce init statement
+    at the end of BB.  When BB is NULL, we return init statement to be
+    output later.  */
+ static gimple
  setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
  		     basic_block bb, tree *vars)
  {
!   gimple init_stmt = NULL;
    tree var;
    tree rhs = value;
    tree def = (gimple_in_ssa_p (cfun)
*************** setup_one_parameter (copy_body_data *id,
*** 1902,1908 ****
  	  && ! self_inlining_addr_expr (value, fn))
  	{
  	  insert_decl_map (id, p, value);
! 	  return;
  	}
      }
  
--- 1944,1950 ----
  	  && ! self_inlining_addr_expr (value, fn))
  	{
  	  insert_decl_map (id, p, value);
! 	  return NULL;
  	}
      }
  
*************** setup_one_parameter (copy_body_data *id,
*** 1960,1966 ****
        && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def))
      {
        insert_decl_map (id, def, rhs);
!       return;
      }
  
    /* If the value of argument is never used, don't care about initializing
--- 2002,2008 ----
        && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def))
      {
        insert_decl_map (id, def, rhs);
!       return NULL;
      }
  
    /* If the value of argument is never used, don't care about initializing
*************** setup_one_parameter (copy_body_data *id,
*** 1968,1986 ****
    if (gimple_in_ssa_p (cfun) && !def && is_gimple_reg (p))
      {
        gcc_assert (!value || !TREE_SIDE_EFFECTS (value));
!       return;
      }
  
    /* Initialize this VAR_DECL from the equivalent argument.  Convert
       the argument to the proper type in case it was promoted.  */
    if (value)
      {
-       gimple_stmt_iterator si = gsi_last_bb (bb);
- 
        if (rhs == error_mark_node)
  	{
  	  insert_decl_map (id, p, var);
! 	  return;
  	}
  
        STRIP_USELESS_TYPE_CONVERSION (rhs);
--- 2010,2026 ----
    if (gimple_in_ssa_p (cfun) && !def && is_gimple_reg (p))
      {
        gcc_assert (!value || !TREE_SIDE_EFFECTS (value));
!       return NULL;
      }
  
    /* Initialize this VAR_DECL from the equivalent argument.  Convert
       the argument to the proper type in case it was promoted.  */
    if (value)
      {
        if (rhs == error_mark_node)
  	{
  	  insert_decl_map (id, p, var);
! 	  return NULL;
  	}
  
        STRIP_USELESS_TYPE_CONVERSION (rhs);
*************** setup_one_parameter (copy_body_data *id,
*** 1997,2047 ****
        else
          init_stmt = gimple_build_assign (var, rhs);
  
!       /* If we did not create a gimple value and we did not create a gimple
! 	 cast of a gimple value, then we will need to gimplify INIT_STMT
! 	 at the end.  Note that is_gimple_cast only checks the outer
! 	 tree code, not its operand.  Thus the explicit check that its
! 	 operand is a gimple value.  */
!       if ((!is_gimple_val (rhs)
! 	  && (!is_gimple_cast (rhs)
! 	      || !is_gimple_val (TREE_OPERAND (rhs, 0))))
! 	  || !is_gimple_reg (var))
! 	{
! 	  gimple_stmt_iterator i;
! 	  gimple_seq seq = gimple_seq_alloc ();
!           struct gimplify_ctx gctx;
! 
! 	  push_gimplify_context (&gctx);
! 
! 	  i = gsi_start (seq);
! 	  gimple_regimplify_operands (init_stmt, &i);
! 
! 	  if (gimple_in_ssa_p (cfun)
!               && init_stmt
! 	      && !gimple_seq_empty_p (seq))
! 	    {
! 	      /* The replacement can expose previously unreferenced
! 		 variables.  */
! 	      for (i = gsi_start (seq); !gsi_end_p (i); gsi_next (&i))
! 		find_new_referenced_vars (gsi_stmt (i));
! 
! 	      /* Insert the gimplified sequence needed for INIT_STMT
! 		 after SI.  INIT_STMT will be inserted after SEQ.  */
! 	      gsi_insert_seq_after (&si, seq, GSI_NEW_STMT);
! 	     }
! 
! 	  pop_gimplify_context (NULL);
! 	}
! 
!       /* If VAR represents a zero-sized variable, it's possible that the
! 	 assignment statement may result in no gimple statements.  */
!       if (init_stmt)
!         gsi_insert_after (&si, init_stmt, GSI_NEW_STMT);
! 
!       if (gimple_in_ssa_p (cfun))
! 	for (;!gsi_end_p (si); gsi_next (&si))
! 	  mark_symbols_for_renaming (gsi_stmt (si));
      }
  }
  
  /* Generate code to initialize the parameters of the function at the
--- 2037,2046 ----
        else
          init_stmt = gimple_build_assign (var, rhs);
  
!       if (bb && init_stmt)
!         insert_init_stmt (bb, init_stmt);
      }
+   return init_stmt;
  }
  
  /* Generate code to initialize the parameters of the function at the
*************** tree_function_versioning (tree old_decl,
*** 4149,4156 ****
--- 4148,4158 ----
    unsigned i;
    struct ipa_replace_map *replace_info;
    basic_block old_entry_block;
+   VEC (gimple, heap) *init_stmts = VEC_alloc (gimple, heap, 10);
+ 
    tree t_step;
    tree old_current_function_decl = current_function_decl;
+   tree vars = NULL_TREE;
  
    gcc_assert (TREE_CODE (old_decl) == FUNCTION_DECL
  	      && TREE_CODE (new_decl) == FUNCTION_DECL);
*************** tree_function_versioning (tree old_decl,
*** 4207,4216 ****
--- 4209,4224 ----
      DECL_ARGUMENTS (new_decl) =
        copy_arguments_for_versioning (DECL_ARGUMENTS (old_decl), &id);
    
+   DECL_INITIAL (new_decl) = remap_blocks (DECL_INITIAL (id.src_fn), &id);
+   
+   /* Renumber the lexical scoping (non-code) blocks consecutively.  */
+   number_blocks (id.dst_fn);
+   
    /* If there's a tree_map, prepare for substitution.  */
    if (tree_map)
      for (i = 0; i < VARRAY_ACTIVE_SIZE (tree_map); i++)
        {
+ 	gimple init;
  	replace_info
  	  = (struct ipa_replace_map *) VARRAY_GENERIC_PTR (tree_map, i);
  	if (replace_info->replace_p)
*************** tree_function_versioning (tree old_decl,
*** 4223,4238 ****
  		if (TREE_CODE (op) == VAR_DECL)
  		  add_referenced_var (op);
  	      }
! 	    insert_decl_map (&id, replace_info->old_tree,
! 			     replace_info->new_tree);
  	  }
        }
    
!   DECL_INITIAL (new_decl) = remap_blocks (DECL_INITIAL (id.src_fn), &id);
!   
!   /* Renumber the lexical scoping (non-code) blocks consecutively.  */
!   number_blocks (id.dst_fn);
!   
    if (DECL_STRUCT_FUNCTION (old_decl)->local_decls != NULL_TREE)
      /* Add local vars.  */
      for (t_step = DECL_STRUCT_FUNCTION (old_decl)->local_decls;
--- 4231,4247 ----
  		if (TREE_CODE (op) == VAR_DECL)
  		  add_referenced_var (op);
  	      }
! 	    gcc_assert (TREE_CODE (replace_info->old_tree) == PARM_DECL);
! 	    init = setup_one_parameter (&id, replace_info->old_tree,
! 	    			        replace_info->new_tree, id.src_fn,
! 				        NULL,
! 				        &vars);
! 	    if (init)
! 	      VEC_safe_push (gimple, heap, init_stmts, init);
  	  }
        }
    
!   declare_inline_vars (DECL_INITIAL (new_decl), vars);
    if (DECL_STRUCT_FUNCTION (old_decl)->local_decls != NULL_TREE)
      /* Add local vars.  */
      for (t_step = DECL_STRUCT_FUNCTION (old_decl)->local_decls;
*************** tree_function_versioning (tree old_decl,
*** 4260,4265 ****
--- 4269,4281 ----
    /* Renumber the lexical scoping (non-code) blocks consecutively.  */
    number_blocks (new_decl);
  
+   if (VEC_length (gimple, init_stmts))
+     {
+       basic_block bb = split_edge (single_succ_edge (ENTRY_BLOCK_PTR));
+       while (VEC_length (gimple, init_stmts))
+ 	insert_init_stmt (bb, VEC_pop (gimple, init_stmts));
+     }
+ 
    /* Clean up.  */
    pointer_map_destroy (id.decl_map);
    if (!update_clones)
*************** tree_function_versioning (tree old_decl,
*** 4284,4289 ****
--- 4300,4306 ----
      }
    free_dominance_info (CDI_DOMINATORS);
    free_dominance_info (CDI_POST_DOMINATORS);
+   VEC_free (gimple, heap, init_stmts);
    pop_cfun ();
    current_function_decl = old_current_function_decl;
    gcc_assert (!current_function_decl


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