Beispiel #1
0
void
gimple_gen_ic_func_profiler (void)
{
  struct cgraph_node * c_node = cgraph_get_node (current_function_decl);
  gimple_stmt_iterator gsi;
  gimple stmt1, stmt2;
  tree tree_uid, cur_func, void0;

  if (cgraph_only_called_directly_p (c_node))
    return;

  gimple_init_edge_profiler ();

  /* Insert code:

    stmt1: __gcov_indirect_call_profiler_v2 (profile_id,
					     &current_function_decl)
   */
  gsi =
					     gsi_after_labels (split_edge (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun))));

  cur_func = force_gimple_operand_gsi (&gsi,
				       build_addr (current_function_decl,
						   current_function_decl),
				       true, NULL_TREE,
				       true, GSI_SAME_STMT);
  tree_uid = build_int_cst
	      (gcov_type_node, cgraph_get_node (current_function_decl)->profile_id);
  /* Workaround for binutils bug 14342.  Once it is fixed, remove lto path.  */
  if (flag_lto)
    {
      tree counter_ptr, ptr_var;
      counter_ptr = force_gimple_operand_gsi (&gsi, ic_gcov_type_ptr_var,
					      true, NULL_TREE, true,
					      GSI_SAME_STMT);
      ptr_var = force_gimple_operand_gsi (&gsi, ic_void_ptr_var,
					  true, NULL_TREE, true,
					  GSI_SAME_STMT);

      stmt1 = gimple_build_call (tree_indirect_call_profiler_fn, 4,
				 counter_ptr, tree_uid, cur_func, ptr_var);
    }
  else
    {
      stmt1 = gimple_build_call (tree_indirect_call_profiler_fn, 2,
				 tree_uid, cur_func);
    }
  gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);

  /* Set __gcov_indirect_call_callee to 0,
     so that calls from other modules won't get misattributed
     to the last caller of the current callee. */
  void0 = build_int_cst (build_pointer_type (void_type_node), 0);
  stmt2 = gimple_build_assign (ic_void_ptr_var, void0);
  gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT);
}
void
gimple_gen_ic_func_profiler (void)
{
  struct cgraph_node * c_node = cgraph_get_node (current_function_decl);
  gimple_stmt_iterator gsi;
  gimple stmt1, stmt2;
  tree tree_uid, cur_func, counter_ptr, ptr_var, void0;

  if (cgraph_only_called_directly_p (c_node))
    return;

  gimple_init_edge_profiler ();

  /* Insert code:

    stmt1: __gcov_indirect_call_profiler (__gcov_indirect_call_counters,
					  current_function_funcdef_no,
					  &current_function_decl,
					  __gcov_indirect_call_callee);
   */
  gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR));

  cur_func = force_gimple_operand_gsi (&gsi,
				       build_addr (current_function_decl,
						   current_function_decl),
				       true, NULL_TREE,
				       true, GSI_SAME_STMT);
  counter_ptr = force_gimple_operand_gsi (&gsi, ic_gcov_type_ptr_var,
					  true, NULL_TREE, true,
					  GSI_SAME_STMT);
  ptr_var = force_gimple_operand_gsi (&gsi, ic_void_ptr_var,
				      true, NULL_TREE, true,
				      GSI_SAME_STMT);
  tree_uid = build_int_cst (gcov_type_node, current_function_funcdef_no);
  stmt1 = gimple_build_call (tree_indirect_call_profiler_fn, 4,
			     counter_ptr, tree_uid, cur_func, ptr_var);
  gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);

  /* Set __gcov_indirect_call_callee to 0,
     so that calls from other modules won't get misattributed
     to the last caller of the current callee. */
  void0 = build_int_cst (build_pointer_type (void_type_node), 0);
  stmt2 = gimple_build_assign (ic_void_ptr_var, void0);
  gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT);
}
Beispiel #3
0
/* Return true if this NODE is viable candidate for cloning.  */
static bool
ipcp_cloning_candidate_p (struct cgraph_node *node)
{
  int n_calls = 0;
  int n_hot_calls = 0;
  gcov_type direct_call_sum = 0;
  struct cgraph_edge *e;

  /* We never clone functions that are not visible from outside.
     FIXME: in future we should clone such functions when they are called with
     different constants, but current ipcp implementation is not good on this.
     */
  if (cgraph_only_called_directly_p (node) || !node->analyzed)
    return false;

  /* When function address is taken, we are pretty sure it will be called in hidden way.  */
  if (node->address_taken)
    {
      if (dump_file)
        fprintf (dump_file, "Not considering %s for cloning; address is taken.\n",
 	         cgraph_node_name (node));
      return false;
    }

  if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE)
    {
      if (dump_file)
        fprintf (dump_file, "Not considering %s for cloning; body is overwritable.\n",
 	         cgraph_node_name (node));
      return false;
    }
  if (!ipcp_versionable_function_p (node))
    {
      if (dump_file)
        fprintf (dump_file, "Not considering %s for cloning; body is not versionable.\n",
 	         cgraph_node_name (node));
      return false;
    }
  for (e = node->callers; e; e = e->next_caller)
    {
      direct_call_sum += e->count;
      n_calls ++;
      if (cgraph_maybe_hot_edge_p (e))
	n_hot_calls ++;
    }

  if (!n_calls)
    {
      if (dump_file)
        fprintf (dump_file, "Not considering %s for cloning; no direct calls.\n",
 	         cgraph_node_name (node));
      return false;
    }
  if (node->local.inline_summary.self_size < n_calls)
    {
      if (dump_file)
        fprintf (dump_file, "Considering %s for cloning; code would shrink.\n",
 	         cgraph_node_name (node));
      return true;
    }

  if (!flag_ipa_cp_clone)
    {
      if (dump_file)
        fprintf (dump_file, "Not considering %s for cloning; -fipa-cp-clone disabled.\n",
 	         cgraph_node_name (node));
      return false;
    }

  if (!optimize_function_for_speed_p (DECL_STRUCT_FUNCTION (node->decl)))
    {
      if (dump_file)
        fprintf (dump_file, "Not considering %s for cloning; optimizing it for size.\n",
 	         cgraph_node_name (node));
      return false;
    }

  /* When profile is available and function is hot, propagate into it even if
     calls seems cold; constant propagation can improve function's speed
     significantly.  */
  if (max_count)
    {
      if (direct_call_sum > node->count * 90 / 100)
	{
	  if (dump_file)
	    fprintf (dump_file, "Considering %s for cloning; usually called directly.\n",
		     cgraph_node_name (node));
	  return true;
        }
    }
  if (!n_hot_calls)
    {
      if (dump_file)
	fprintf (dump_file, "Not considering %s for cloning; no hot calls.\n",
		 cgraph_node_name (node));
      return false;
    }
  if (dump_file)
    fprintf (dump_file, "Considering %s for cloning.\n",
	     cgraph_node_name (node));
  return true;
}