Пример #1
0
/* Return true if this callsite should be redirected to the original callee
   (instead of the cloned one).  */
static bool
ipcp_need_redirect_p (struct cgraph_edge *cs)
{
  struct ipa_node_params *orig_callee_info;
  int i, count;
  struct cgraph_node *node = cs->callee, *orig;

  if (!n_cloning_candidates)
    return false;

  if ((orig = ipcp_get_orig_node (node)) != NULL)
    node = orig;
  if (ipcp_get_orig_node (cs->caller))
    return false;

  orig_callee_info = IPA_NODE_REF (node);
  count = ipa_get_param_count (orig_callee_info);
  for (i = 0; i < count; i++)
    {
      struct ipcp_lattice *lat = ipcp_get_lattice (orig_callee_info, i);
      struct ipa_jump_func *jump_func;

      jump_func = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), i);
      if ((ipcp_lat_is_const (lat)
	   && jump_func->type != IPA_JF_CONST)
	  || (!ipa_param_cannot_devirtualize_p (orig_callee_info, i)
	      && !ipa_param_types_vec_empty (orig_callee_info, i)
	      && jump_func->type != IPA_JF_CONST
	      && jump_func->type != IPA_JF_KNOWN_TYPE))
	return true;
    }

  return false;
}
Пример #2
0
/* Initialize ipcp_lattices array.  The lattices corresponding to supported
   types (integers, real types and Fortran constants defined as const_decls)
   are initialized to IPA_TOP, the rest of them to IPA_BOTTOM.  */
static void
ipcp_initialize_node_lattices (struct cgraph_node *node)
{
  int i;
  struct ipa_node_params *info = IPA_NODE_REF (node);
  enum ipa_lattice_type type;

  if (ipa_is_called_with_var_arguments (info))
    type = IPA_BOTTOM;
  else if (node->local.local)
    type = IPA_TOP;
  /* When cloning is allowed, we can assume that externally visible functions
     are not called.  We will compensate this by cloning later.  */
  else if (ipcp_cloning_candidate_p (node))
    type = IPA_TOP, n_cloning_candidates ++;
  else
    type = IPA_BOTTOM;

  for (i = 0; i < ipa_get_param_count (info) ; i++)
    {
      ipcp_get_lattice (info, i)->type = type;
      if (type == IPA_BOTTOM)
	ipa_set_param_cannot_devirtualize (info, i);
    }
}
Пример #3
0
int ipa_get_param_decl_index (struct ipa_node_params *info, tree ptree)
{
  int i, count;
  count = ipa_get_param_count (info);
  for (i = 0; i < count; i++)
    if (ipa_get_param (info, i) == ptree)       return i;
  return -1;
}
Пример #4
0
/* If NODE was cloned, how much would program grow? */
static long
ipcp_estimate_growth (struct cgraph_node *node)
{
  struct cgraph_edge *cs;
  int redirectable_node_callers = 0;
  int removable_args = 0;
  bool need_original
     = !cgraph_will_be_removed_from_program_if_no_direct_calls (node);
  struct ipa_node_params *info;
  int i, count;
  int growth;

  for (cs = node->callers; cs != NULL; cs = cs->next_caller)
    if (cs->caller == node || !ipcp_need_redirect_p (cs))
      redirectable_node_callers++;
    else
      need_original = true;

  /* If we will be able to fully replace original node, we never increase
     program size.  */
  if (!need_original)
    return 0;

  info = IPA_NODE_REF (node);
  count = ipa_get_param_count (info);
  if (node->local.can_change_signature)
    for (i = 0; i < count; i++)
      {
	struct ipcp_lattice *lat = ipcp_get_lattice (info, i);

	/* We can proactively remove obviously unused arguments.  */
	if (!ipa_is_param_used (info, i))
	  removable_args++;

	if (lat->type == IPA_CONST_VALUE)
	  removable_args++;
      }

  /* We make just very simple estimate of savings for removal of operand from
     call site.  Precise cost is difficult to get, as our size metric counts
     constants and moves as free.  Generally we are looking for cases that
     small function is called very many times.  */
  growth = node->local.inline_summary.self_size
  	   - removable_args * redirectable_node_callers;
  if (growth < 0)
    return 0;
  return growth;
}
Пример #5
0
/* Fix the callsites and the call graph after function cloning was done.  */
static void
ipcp_update_callgraph (void)
{
  struct cgraph_node *node;

  for (node = cgraph_nodes; node; node = node->next)
    if (node->analyzed && ipcp_node_is_clone (node))
      {
	bitmap args_to_skip = NULL;
	struct cgraph_node *orig_node = ipcp_get_orig_node (node);
        struct ipa_node_params *info = IPA_NODE_REF (orig_node);
        int i, count = ipa_get_param_count (info);
        struct cgraph_edge *cs, *next;

	if (node->local.can_change_signature)
	  {
	    args_to_skip = BITMAP_ALLOC (NULL);
	    for (i = 0; i < count; i++)
	      {
		struct ipcp_lattice *lat = ipcp_get_lattice (info, i);

		/* We can proactively remove obviously unused arguments.  */
		if (!ipa_is_param_used (info, i))
		  {
		    bitmap_set_bit (args_to_skip, i);
		    continue;
		  }

		if (lat->type == IPA_CONST_VALUE)
		  bitmap_set_bit (args_to_skip, i);
	      }
	  }
	for (cs = node->callers; cs; cs = next)
	  {
	    next = cs->next_caller;
	    if (!ipcp_node_is_clone (cs->caller) && ipcp_need_redirect_p (cs))
	      {
		if (dump_file)
		  fprintf (dump_file, "Redirecting edge %s/%i -> %s/%i "
			   "back to %s/%i.",
			   cgraph_node_name (cs->caller), cs->caller->uid,
			   cgraph_node_name (cs->callee), cs->callee->uid,
			   cgraph_node_name (orig_node), orig_node->uid);
		cgraph_redirect_edge_callee (cs, orig_node);
	      }
	  }
      }
}
Пример #6
0
/* Print all ipcp_lattices of all functions to F.  */
static void
ipcp_print_all_lattices (FILE * f)
{
  struct cgraph_node *node;
  int i, count;

  fprintf (f, "\nLattice:\n");
  for (node = cgraph_nodes; node; node = node->next)
    {
      struct ipa_node_params *info;

      if (!node->analyzed)
	continue;
      info = IPA_NODE_REF (node);
      fprintf (f, "  Node: %s:\n", cgraph_node_name (node));
      count = ipa_get_param_count (info);
      for (i = 0; i < count; i++)
	{
	  struct ipcp_lattice *lat = ipcp_get_lattice (info, i);

	  fprintf (f, "    param [%d]: ", i);
	  if (lat->type == IPA_CONST_VALUE)
	    {
	      tree cst = lat->constant;
	      fprintf (f, "type is CONST ");
	      print_generic_expr (f, cst, 0);
	      if (TREE_CODE (cst) == ADDR_EXPR
		  && TREE_CODE (TREE_OPERAND (cst, 0)) == CONST_DECL)
		{
		  fprintf (f, " -> ");
		  print_generic_expr (f, DECL_INITIAL (TREE_OPERAND (cst, 0)),
						       0);
		}
	    }
	  else if (lat->type == IPA_TOP)
	    fprintf (f, "type is TOP");
	  else
	    fprintf (f, "type is BOTTOM");
	  if (ipa_param_cannot_devirtualize_p (info, i))
	    fprintf (f, " - cannot_devirtualize set\n");
	  else if (ipa_param_types_vec_empty (info, i))
	    fprintf (f, " - type list empty\n");
	  else
	    fprintf (f, "\n");
	}
    }
}
Пример #7
0
/* Return true if there are some formal parameters whose value is IPA_TOP (in
   the whole compilation unit).  Change their values to IPA_BOTTOM, since they
   most probably get their values from outside of this compilation unit.  */
static bool
ipcp_change_tops_to_bottom (void)
{
  int i, count;
  struct cgraph_node *node;
  bool prop_again;

  prop_again = false;
  for (node = cgraph_nodes; node; node = node->next)
    {
      struct ipa_node_params *info = IPA_NODE_REF (node);
      count = ipa_get_param_count (info);
      for (i = 0; i < count; i++)
	{
	  struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
	  if (lat->type == IPA_TOP)
	    {
	      prop_again = true;
	      if (dump_file)
		{
		  fprintf (dump_file, "Forcing param ");
		  print_generic_expr (dump_file, ipa_get_param (info, i), 0);
		  fprintf (dump_file, " of node %s to bottom.\n",
			   cgraph_node_name (node));
		}
	      lat->type = IPA_BOTTOM;
	    }
	  if (!ipa_param_cannot_devirtualize_p (info, i)
	      && ipa_param_types_vec_empty (info, i))
	    {
	      prop_again = true;
	      ipa_set_param_cannot_devirtualize (info, i);
	      if (dump_file)
		{
		  fprintf (dump_file, "Marking param ");
		  print_generic_expr (dump_file, ipa_get_param (info, i), 0);
		  fprintf (dump_file, " of node %s as unusable for "
			   "devirtualization.\n",
			   cgraph_node_name (node));
		}
	    }
	}
    }
  return prop_again;
}
Пример #8
0
/* Return number of live constant parameters.  */
static int
ipcp_const_param_count (struct cgraph_node *node)
{
  int const_param = 0;
  struct ipa_node_params *info = IPA_NODE_REF (node);
  int count = ipa_get_param_count (info);
  int i;

  for (i = 0; i < count; i++)
    {
      struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
      if ((ipcp_lat_is_insertable (lat)
	  /* Do not count obviously unused arguments.  */
	   && ipa_is_param_used (info, i))
	  || (!ipa_param_cannot_devirtualize_p (info, i)
	      && !ipa_param_types_vec_empty (info, i)))
	const_param++;
    }
  return const_param;
}
Пример #9
0
/* Propagate the constant parameters found by ipcp_iterate_stage()
   to the function's code.  */
static void
ipcp_insert_stage (void)
{
  struct cgraph_node *node, *node1 = NULL;
  int i;
  VEC (cgraph_edge_p, heap) * redirect_callers;
  VEC (ipa_replace_map_p,gc)* replace_trees;
  int node_callers, count;
  tree parm_tree;
  struct ipa_replace_map *replace_param;
  fibheap_t heap;
  long overall_size = 0, new_size = 0;
  long max_new_size;

  ipa_check_create_node_params ();
  ipa_check_create_edge_args ();
  if (dump_file)
    fprintf (dump_file, "\nIPA insert stage:\n\n");

  dead_nodes = BITMAP_ALLOC (NULL);

  for (node = cgraph_nodes; node; node = node->next)
    if (node->analyzed)
      {
	if (node->count > max_count)
	  max_count = node->count;
	overall_size += node->local.inline_summary.self_size;
      }

  max_new_size = overall_size;
  if (max_new_size < PARAM_VALUE (PARAM_LARGE_UNIT_INSNS))
    max_new_size = PARAM_VALUE (PARAM_LARGE_UNIT_INSNS);
  max_new_size = max_new_size * PARAM_VALUE (PARAM_IPCP_UNIT_GROWTH) / 100 + 1;

  /* First collect all functions we proved to have constant arguments to
     heap.  */
  heap = fibheap_new ();
  for (node = cgraph_nodes; node; node = node->next)
    {
      struct ipa_node_params *info;
      /* Propagation of the constant is forbidden in certain conditions.  */
      if (!node->analyzed || !ipcp_node_modifiable_p (node))
	  continue;
      info = IPA_NODE_REF (node);
      if (ipa_is_called_with_var_arguments (info))
	continue;
      if (ipcp_const_param_count (node))
	node->aux = fibheap_insert (heap, ipcp_estimate_cloning_cost (node),
				    node);
     }

  /* Now clone in priority order until code size growth limits are met or
     heap is emptied.  */
  while (!fibheap_empty (heap))
    {
      struct ipa_node_params *info;
      int growth = 0;
      bitmap args_to_skip;
      struct cgraph_edge *cs;

      node = (struct cgraph_node *)fibheap_extract_min (heap);
      node->aux = NULL;
      if (dump_file)
	fprintf (dump_file, "considering function %s\n",
		 cgraph_node_name (node));

      growth = ipcp_estimate_growth (node);

      if (new_size + growth > max_new_size)
	break;
      if (growth
	  && optimize_function_for_size_p (DECL_STRUCT_FUNCTION (node->decl)))
	{
	  if (dump_file)
	    fprintf (dump_file, "Not versioning, cold code would grow");
	  continue;
	}

      info = IPA_NODE_REF (node);
      count = ipa_get_param_count (info);

      replace_trees = VEC_alloc (ipa_replace_map_p, gc, 1);

      if (node->local.can_change_signature)
	args_to_skip = BITMAP_GGC_ALLOC ();
      else
	args_to_skip = NULL;
      for (i = 0; i < count; i++)
	{
	  struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
	  parm_tree = ipa_get_param (info, i);

	  /* We can proactively remove obviously unused arguments.  */
	  if (!ipa_is_param_used (info, i))
	    {
	      if (args_to_skip)
	        bitmap_set_bit (args_to_skip, i);
	      continue;
	    }

	  if (lat->type == IPA_CONST_VALUE)
	    {
	      replace_param =
		ipcp_create_replace_map (parm_tree, lat);
	      if (replace_param == NULL)
		break;
	      VEC_safe_push (ipa_replace_map_p, gc, replace_trees, replace_param);
	      if (args_to_skip)
	        bitmap_set_bit (args_to_skip, i);
	    }
	}
      if (i < count)
	{
	  if (dump_file)
	    fprintf (dump_file, "Not versioning, some parameters couldn't be replaced");
	  continue;
	}

      new_size += growth;

      /* Look if original function becomes dead after cloning.  */
      for (cs = node->callers; cs != NULL; cs = cs->next_caller)
	if (cs->caller == node || ipcp_need_redirect_p (cs))
	  break;
      if (!cs && cgraph_will_be_removed_from_program_if_no_direct_calls (node))
	bitmap_set_bit (dead_nodes, node->uid);

      /* Compute how many callers node has.  */
      node_callers = 0;
      for (cs = node->callers; cs != NULL; cs = cs->next_caller)
	node_callers++;
      redirect_callers = VEC_alloc (cgraph_edge_p, heap, node_callers);
      for (cs = node->callers; cs != NULL; cs = cs->next_caller)
	if (!cs->indirect_inlining_edge)
	  VEC_quick_push (cgraph_edge_p, redirect_callers, cs);

      /* Redirecting all the callers of the node to the
         new versioned node.  */
      node1 =
	cgraph_create_virtual_clone (node, redirect_callers, replace_trees,
				     args_to_skip, "constprop");
      args_to_skip = NULL;
      VEC_free (cgraph_edge_p, heap, redirect_callers);
      replace_trees = NULL;

      if (node1 == NULL)
	continue;
      ipcp_process_devirtualization_opportunities (node1);

      if (dump_file)
	fprintf (dump_file, "versioned function %s with growth %i, overall %i\n",
		 cgraph_node_name (node), (int)growth, (int)new_size);
      ipcp_init_cloned_node (node, node1);

      info = IPA_NODE_REF (node);
      for (i = 0; i < count; i++)
	{
	  struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
	  if (lat->type == IPA_CONST_VALUE)
	    ipcp_discover_new_direct_edges (node1, i, lat->constant);
        }

      if (dump_file)
	dump_function_to_file (node1->decl, dump_file, dump_flags);

      for (cs = node->callees; cs; cs = cs->next_callee)
        if (cs->callee->aux)
	  {
	    fibheap_delete_node (heap, (fibnode_t) cs->callee->aux);
	    cs->callee->aux = fibheap_insert (heap,
	    				      ipcp_estimate_cloning_cost (cs->callee),
					      cs->callee);
	  }
    }

  while (!fibheap_empty (heap))
    {
      if (dump_file)
	fprintf (dump_file, "skipping function %s\n",
		 cgraph_node_name (node));
      node = (struct cgraph_node *) fibheap_extract_min (heap);
      node->aux = NULL;
    }
  fibheap_delete (heap);
  BITMAP_FREE (dead_nodes);
  ipcp_update_callgraph ();
  ipcp_update_profiling ();
}