Ejemplo n.º 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
cgraph_rebuild_references (void)
{
  basic_block bb;
  struct cgraph_node *node = cgraph_get_node (current_function_decl);
  gimple_stmt_iterator gsi;

  ipa_remove_all_references (&node->ref_list);

  node->count = ENTRY_BLOCK_PTR->count;

  FOR_EACH_BB (bb)
    {
      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
	{
	  gimple stmt = gsi_stmt (gsi);

	  walk_stmt_load_store_addr_ops (stmt, node, mark_load,
					 mark_store, mark_address);

	}
      for (gsi = gsi_start (phi_nodes (bb)); !gsi_end_p (gsi); gsi_next (&gsi))
	walk_stmt_load_store_addr_ops (gsi_stmt (gsi), node,
				       mark_load, mark_store, mark_address);
    }
  record_eh_tables (node, cfun);
}
static void walk_functions(tree_set *visited, const struct cgraph_node *node)
{
	struct cgraph_edge *e;
	const_tree caller;

	if (!node)
		return;
	caller = NODE_DECL(node);

	if (pointer_set_insert(visited, caller))
		return;

	for (e = node->callees; e; e = e->next_callee) {
		const struct cgraph_node *next_node;
		tree callee = gimple_call_fndecl(e->call_stmt);

		if (DECL_BUILT_IN(callee))
			continue;

		print_function(caller, callee);

		next_node = cgraph_get_node(callee);
		walk_functions(visited, next_node);
	}
}
Ejemplo n.º 4
0
static void
update_call_edge_frequencies (gimple_seq_node first, basic_block bb)
{
  struct cgraph_node *cfun_node = NULL;
  int bb_freq = 0;
  gimple_seq_node n;

  for (n = first; n ; n = n->next)
    if (is_gimple_call (n->stmt))
      {
	struct cgraph_edge *e;

	/* These function calls are expensive enough that we want
	   to avoid calling them if we never see any calls.  */
	if (cfun_node == NULL)
	  {
	    cfun_node = cgraph_get_node (current_function_decl);
	    bb_freq = (compute_call_stmt_bb_frequency
		       (current_function_decl, bb));
	  }

	e = cgraph_edge (cfun_node, n->stmt);
	if (e != NULL)
	  e->frequency = bb_freq;
      }
}
Ejemplo n.º 5
0
void
cgraph_rebuild_references (void)
{
  basic_block bb;
  struct cgraph_node *node = cgraph_get_node (current_function_decl);
  gimple_stmt_iterator gsi;
  struct ipa_ref *ref;
  int i;

  /* Keep speculative references for further cgraph edge expansion.  */
  for (i = 0; ipa_ref_list_reference_iterate (&node->ref_list, i, ref);)
    if (!ref->speculative)
      ipa_remove_reference (ref);
    else
      i++;

  node->count = ENTRY_BLOCK_PTR_FOR_FN (cfun)->count;

  FOR_EACH_BB_FN (bb, cfun)
    {
      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
	ipa_record_stmt_references (node, gsi_stmt (gsi));
      for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
	ipa_record_stmt_references (node, gsi_stmt (gsi));
    }
  record_eh_tables (node, cfun);
}
/* Create clone of E in the node N represented by CALL_EXPR the callgraph.  */
struct cgraph_edge *
cgraph_clone_edge (struct cgraph_edge *e, struct cgraph_node *n,
		   gimple call_stmt, unsigned stmt_uid, gcov_type count_scale,
		   int freq_scale, bool update_original)
{
  struct cgraph_edge *new_edge;
  gcov_type count = apply_probability (e->count, count_scale);
  gcov_type freq;

  /* We do not want to ignore loop nest after frequency drops to 0.  */
  if (!freq_scale)
    freq_scale = 1;
  freq = e->frequency * (gcov_type) freq_scale / CGRAPH_FREQ_BASE;
  if (freq > CGRAPH_FREQ_MAX)
    freq = CGRAPH_FREQ_MAX;

  if (e->indirect_unknown_callee)
    {
      tree decl;

      if (call_stmt && (decl = gimple_call_fndecl (call_stmt)))
	{
	  struct cgraph_node *callee = cgraph_get_node (decl);
	  gcc_checking_assert (callee);
	  new_edge = cgraph_create_edge (n, callee, call_stmt, count, freq);
	}
      else
	{
	  new_edge = cgraph_create_indirect_edge (n, call_stmt,
						  e->indirect_info->ecf_flags,
						  count, freq);
	  *new_edge->indirect_info = *e->indirect_info;
	}
    }
  else
    {
      new_edge = cgraph_create_edge (n, e->callee, call_stmt, count, freq);
      if (e->indirect_info)
	{
	  new_edge->indirect_info
	    = ggc_alloc_cleared_cgraph_indirect_call_info ();
	  *new_edge->indirect_info = *e->indirect_info;
	}
    }

  new_edge->inline_failed = e->inline_failed;
  new_edge->indirect_inlining_edge = e->indirect_inlining_edge;
  new_edge->lto_stmt_uid = stmt_uid;
  /* Clone flags that depend on call_stmt availability manually.  */
  new_edge->can_throw_external = e->can_throw_external;
  new_edge->call_stmt_cannot_inline_p = e->call_stmt_cannot_inline_p;
  if (update_original)
    {
      e->count -= new_edge->count;
      if (e->count < 0)
	e->count = 0;
    }
  cgraph_call_edge_duplication_hooks (e, new_edge);
  return new_edge;
}
Ejemplo n.º 7
0
static unsigned int
remove_cgraph_callee_edges (void)
{
  struct cgraph_node *node = cgraph_get_node (current_function_decl);
  cgraph_node_remove_callees (node);
  ipa_remove_all_references (&node->ref_list);
  return 0;
}
unsigned int
rebuild_cgraph_edges (void)
{
  basic_block bb;
  struct cgraph_node *node = cgraph_get_node (current_function_decl);
  gimple_stmt_iterator gsi;

  cgraph_node_remove_callees (node);
  ipa_remove_all_references (&node->ref_list);

  node->count = ENTRY_BLOCK_PTR->count;

  FOR_EACH_BB (bb)
    {
      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
	{
	  gimple stmt = gsi_stmt (gsi);
	  tree decl;

	  if (is_gimple_call (stmt))
	    {
	      int freq = compute_call_stmt_bb_frequency (current_function_decl,
							 bb);
	      decl = gimple_call_fndecl (stmt);
	      if (decl)
		cgraph_create_edge (node, cgraph_get_create_node (decl), stmt,
				    bb->count, freq);
	      else
		cgraph_create_indirect_edge (node, stmt,
					     gimple_call_flags (stmt),
					     bb->count, freq);
	    }
	  walk_stmt_load_store_addr_ops (stmt, node, mark_load,
					 mark_store, mark_address);

	}
      for (gsi = gsi_start (phi_nodes (bb)); !gsi_end_p (gsi); gsi_next (&gsi))
	walk_stmt_load_store_addr_ops (gsi_stmt (gsi), node,
				       mark_load, mark_store, mark_address);
    }
  record_eh_tables (node, cfun);
  gcc_assert (!node->global.inlined_to);

  return 0;
}
Ejemplo n.º 9
0
void
lto_symtab_merge_symbols (void)
{
  symtab_node node;

  if (!flag_ltrans)
    {
      symtab_initialize_asm_name_hash ();

      /* Do the actual merging.  
         At this point we invalidate hash translating decls into symtab nodes
	 because after removing one of duplicate decls the hash is not correcly
	 updated to the ohter dupliate.  */
      FOR_EACH_SYMBOL (node)
	if (lto_symtab_symbol_p (node)
	    && node->symbol.next_sharing_asm_name
	    && !node->symbol.previous_sharing_asm_name)
	  lto_symtab_merge_symbols_1 (node);

      /* Resolve weakref aliases whose target are now in the compilation unit.  
	 also re-populate the hash translating decls into symtab nodes*/
      FOR_EACH_SYMBOL (node)
	{
	  cgraph_node *cnode, *cnode2;
	  if (!node->symbol.analyzed && node->symbol.alias_target)
	    {
	      symtab_node tgt = symtab_node_for_asm (node->symbol.alias_target);
	      gcc_assert (node->symbol.weakref);
	      if (tgt)
		symtab_resolve_alias (node, tgt);
	    }
	  node->symbol.aux = NULL;
	  
	  if (!(cnode = dyn_cast <cgraph_node> (node))
	      || !cnode->clone_of
	      || cnode->clone_of->symbol.decl != cnode->symbol.decl)
	    {
	      if (cnode && DECL_BUILT_IN (node->symbol.decl)
		  && (cnode2 = cgraph_get_node (node->symbol.decl))
		  && cnode2 != cnode)
		lto_cgraph_replace_node (cnode2, cnode);
	      symtab_insert_node_to_hashtable ((symtab_node)node);
	    }
	}
    }
Ejemplo n.º 10
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, 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);
}
Ejemplo n.º 11
0
static void stackleak_add_instrumentation(gimple_stmt_iterator *gsi)
{
	gimple stmt;
	gcall *track_stack;
	cgraph_node_ptr node;
	int frequency;
	basic_block bb;

	// insert call to void pax_track_stack(void)
	stmt = gimple_build_call(track_function_decl, 0);
	track_stack = as_a_gcall(stmt);
	gsi_insert_after(gsi, track_stack, GSI_CONTINUE_LINKING);

	// update the cgraph
	bb = gimple_bb(track_stack);
	node = cgraph_get_create_node(track_function_decl);
	gcc_assert(node);
	frequency = compute_call_stmt_bb_frequency(current_function_decl, bb);
	cgraph_create_edge(cgraph_get_node(current_function_decl), node, track_stack, bb->count, frequency, bb->loop_depth);
}
Ejemplo n.º 12
0
static void stackleak_check_alloca(gimple_stmt_iterator *gsi)
{
	gimple stmt;
	gcall *check_alloca;
	tree alloca_size;
	cgraph_node_ptr node;
	int frequency;
	basic_block bb;

	// insert call to void pax_check_alloca(unsigned long size)
	alloca_size = gimple_call_arg(gsi_stmt(*gsi), 0);
	stmt = gimple_build_call(check_function_decl, 1, alloca_size);
	check_alloca = as_a_gcall(stmt);
	gsi_insert_before(gsi, check_alloca, GSI_SAME_STMT);

	// update the cgraph
	bb = gimple_bb(check_alloca);
	node = cgraph_get_create_node(check_function_decl);
	gcc_assert(node);
	frequency = compute_call_stmt_bb_frequency(current_function_decl, bb);
	cgraph_create_edge(cgraph_get_node(current_function_decl), node, check_alloca, bb->count, frequency, bb->loop_depth);
}
Ejemplo n.º 13
0
static void
maybe_record_node (vec <cgraph_node *> &nodes,
		   tree target, pointer_set_t *inserted)
{
  struct cgraph_node *target_node;
  enum built_in_function fcode;

  if (target
      /* Those are used to mark impossible scenarios.  */
      && (fcode = DECL_FUNCTION_CODE (target))
	  != BUILT_IN_UNREACHABLE
      && fcode != BUILT_IN_TRAP
      && !pointer_set_insert (inserted, target)
      && (target_node = cgraph_get_node (target)) != NULL
      && (TREE_PUBLIC (target)
	  || target_node->symbol.definition)
      && symtab_real_symbol_p ((symtab_node)target_node))
    {
      pointer_set_insert (cached_polymorphic_call_targets,
			  target_node);
      nodes.safe_push (target_node);
    }
}
Ejemplo n.º 14
0
static void
maybe_record_node (vec <cgraph_node *> &nodes,
		   tree target, pointer_set_t *inserted,
		   bool *completep)
{
  struct cgraph_node *target_node;
  enum built_in_function fcode;

  if (!target
      /* Those are used to mark impossible scenarios.  */
      || (fcode = DECL_FUNCTION_CODE (target))
	  == BUILT_IN_UNREACHABLE
      || fcode == BUILT_IN_TRAP)
    return;

  target_node = cgraph_get_node (target);

  if (target_node != NULL
      && (TREE_PUBLIC (target)
	  || target_node->definition)
      && symtab_real_symbol_p (target_node))
    {
      gcc_assert (!target_node->global.inlined_to);
      gcc_assert (symtab_real_symbol_p (target_node));
      if (!pointer_set_insert (inserted, target))
	{
	  pointer_set_insert (cached_polymorphic_call_targets,
			      target_node);
	  nodes.safe_push (target_node);
	}
    }
  else if (completep
	   && !type_in_anonymous_namespace_p
		 (method_class_type (TREE_TYPE (target))))
    *completep = true;
}
Ejemplo n.º 15
0
static unsigned int
build_cgraph_edges (void)
{
  basic_block bb;
  struct cgraph_node *node = cgraph_get_node (current_function_decl);
  struct pointer_set_t *visited_nodes = pointer_set_create ();
  gimple_stmt_iterator gsi;
  tree decl;
  unsigned ix;

  /* Create the callgraph edges and record the nodes referenced by the function.
     body.  */
  FOR_EACH_BB_FN (bb, cfun)
    {
      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
	{
	  gimple stmt = gsi_stmt (gsi);
	  tree decl;

	  if (is_gimple_debug (stmt))
	    continue;

	  if (is_gimple_call (stmt))
	    {
	      int freq = compute_call_stmt_bb_frequency (current_function_decl,
							 bb);
	      decl = gimple_call_fndecl (stmt);
	      if (decl)
		cgraph_create_edge (node, cgraph_get_create_node (decl),
				    stmt, bb->count, freq);
	      else if (gimple_call_internal_p (stmt))
		;
	      else
		cgraph_create_indirect_edge (node, stmt,
					     gimple_call_flags (stmt),
					     bb->count, freq);
	    }
	  ipa_record_stmt_references (node, stmt);
	  if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL
	      && gimple_omp_parallel_child_fn (stmt))
	    {
	      tree fn = gimple_omp_parallel_child_fn (stmt);
	      ipa_record_reference (node,
				    cgraph_get_create_node (fn),
				    IPA_REF_ADDR, stmt);
	    }
	  if (gimple_code (stmt) == GIMPLE_OMP_TASK)
	    {
	      tree fn = gimple_omp_task_child_fn (stmt);
	      if (fn)
		ipa_record_reference (node,
				      cgraph_get_create_node (fn),
				      IPA_REF_ADDR, stmt);
	      fn = gimple_omp_task_copy_fn (stmt);
	      if (fn)
		ipa_record_reference (node,
				      cgraph_get_create_node (fn),
				      IPA_REF_ADDR, stmt);
	    }
	}
      for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
	ipa_record_stmt_references (node, gsi_stmt (gsi));
   }

  /* Look for initializers of constant variables and private statics.  */
  FOR_EACH_LOCAL_DECL (cfun, ix, decl)
    if (TREE_CODE (decl) == VAR_DECL
	&& (TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
	&& !DECL_HAS_VALUE_EXPR_P (decl))
      varpool_finalize_decl (decl);
  record_eh_tables (node, cfun);

  pointer_set_destroy (visited_nodes);
  return 0;
}
Ejemplo n.º 16
0
static struct cgraph_node *
save_inline_function_body (struct cgraph_node *node)
{
  struct cgraph_node *first_clone, *n;

  if (dump_file)
    fprintf (dump_file, "\nSaving body of %s for later reuse\n",
	     cgraph_node_name (node));
 
  gcc_assert (node == cgraph_get_node (node->symbol.decl));

  /* first_clone will be turned into real function.  */
  first_clone = node->clones;
  first_clone->symbol.decl = copy_node (node->symbol.decl);
  symtab_insert_node_to_hashtable ((symtab_node) first_clone);
  gcc_assert (first_clone == cgraph_get_node (first_clone->symbol.decl));

  /* Now reshape the clone tree, so all other clones descends from
     first_clone.  */
  if (first_clone->next_sibling_clone)
    {
      for (n = first_clone->next_sibling_clone; n->next_sibling_clone; n = n->next_sibling_clone)
        n->clone_of = first_clone;
      n->clone_of = first_clone;
      n->next_sibling_clone = first_clone->clones;
      if (first_clone->clones)
        first_clone->clones->prev_sibling_clone = n;
      first_clone->clones = first_clone->next_sibling_clone;
      first_clone->next_sibling_clone->prev_sibling_clone = NULL;
      first_clone->next_sibling_clone = NULL;
      gcc_assert (!first_clone->prev_sibling_clone);
    }
  first_clone->clone_of = NULL;

  /* Now node in question has no clones.  */
  node->clones = NULL;

  /* Inline clones share decl with the function they are cloned
     from.  Walk the whole clone tree and redirect them all to the
     new decl.  */
  if (first_clone->clones)
    for (n = first_clone->clones; n != first_clone;)
      {
        gcc_assert (n->symbol.decl == node->symbol.decl);
	n->symbol.decl = first_clone->symbol.decl;
	if (n->clones)
	  n = n->clones;
	else if (n->next_sibling_clone)
	  n = n->next_sibling_clone;
	else
	  {
	    while (n != first_clone && !n->next_sibling_clone)
	      n = n->clone_of;
	    if (n != first_clone)
	      n = n->next_sibling_clone;
	  }
      }

  /* Copy the OLD_VERSION_NODE function tree to the new version.  */
  tree_function_versioning (node->symbol.decl, first_clone->symbol.decl,
			    NULL, true, NULL, false,
			    NULL, NULL);

  /* The function will be short lived and removed after we inline all the clones,
     but make it internal so we won't confuse ourself.  */
  DECL_EXTERNAL (first_clone->symbol.decl) = 0;
  DECL_COMDAT_GROUP (first_clone->symbol.decl) = NULL_TREE;
  TREE_PUBLIC (first_clone->symbol.decl) = 0;
  DECL_COMDAT (first_clone->symbol.decl) = 0;
  first_clone->ipa_transforms_to_apply.release ();

  /* When doing recursive inlining, the clone may become unnecessary.
     This is possible i.e. in the case when the recursive function is proved to be
     non-throwing and the recursion happens only in the EH landing pad.
     We can not remove the clone until we are done with saving the body.
     Remove it now.  */
  if (!first_clone->callers)
    {
      cgraph_remove_node_and_inline_clones (first_clone, NULL);
      first_clone = NULL;
    }
#ifdef ENABLE_CHECKING
  else
    verify_cgraph_node (first_clone);
#endif
  return first_clone;
}
Ejemplo n.º 17
0
unsigned int
execute_fixup_cfg (void)
{
  basic_block bb;
  gimple_stmt_iterator gsi;
  int todo = gimple_in_ssa_p (cfun) ? TODO_verify_ssa : 0;
  gcov_type count_scale;
  edge e;
  edge_iterator ei;

  count_scale
      = GCOV_COMPUTE_SCALE (cgraph_get_node (current_function_decl)->count,
                            ENTRY_BLOCK_PTR->count);

  ENTRY_BLOCK_PTR->count = cgraph_get_node (current_function_decl)->count;
  EXIT_BLOCK_PTR->count = apply_scale (EXIT_BLOCK_PTR->count,
                                       count_scale);

  FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs)
    e->count = apply_scale (e->count, count_scale);

  FOR_EACH_BB (bb)
    {
      bb->count = apply_scale (bb->count, count_scale);
      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
	{
	  gimple stmt = gsi_stmt (gsi);
	  tree decl = is_gimple_call (stmt)
		      ? gimple_call_fndecl (stmt)
		      : NULL;
	  if (decl)
	    {
	      int flags = gimple_call_flags (stmt);
	      if (flags & (ECF_CONST | ECF_PURE | ECF_LOOPING_CONST_OR_PURE))
		{
		  if (gimple_purge_dead_abnormal_call_edges (bb))
		    todo |= TODO_cleanup_cfg;

		  if (gimple_in_ssa_p (cfun))
		    {
		      todo |= TODO_update_ssa | TODO_cleanup_cfg;
		      update_stmt (stmt);
		    }
		}

	      if (flags & ECF_NORETURN
		  && fixup_noreturn_call (stmt))
		todo |= TODO_cleanup_cfg;
	     }

	  if (maybe_clean_eh_stmt (stmt)
	      && gimple_purge_dead_eh_edges (bb))
	    todo |= TODO_cleanup_cfg;
	}

      FOR_EACH_EDGE (e, ei, bb->succs)
        e->count = apply_scale (e->count, count_scale);

      /* If we have a basic block with no successors that does not
	 end with a control statement or a noreturn call end it with
	 a call to __builtin_unreachable.  This situation can occur
	 when inlining a noreturn call that does in fact return.  */
      if (EDGE_COUNT (bb->succs) == 0)
	{
	  gimple stmt = last_stmt (bb);
	  if (!stmt
	      || (!is_ctrl_stmt (stmt)
		  && (!is_gimple_call (stmt)
		      || (gimple_call_flags (stmt) & ECF_NORETURN) == 0)))
	    {
	      stmt = gimple_build_call
		  (builtin_decl_implicit (BUILT_IN_UNREACHABLE), 0);
	      gimple_stmt_iterator gsi = gsi_last_bb (bb);
	      gsi_insert_after (&gsi, stmt, GSI_NEW_STMT);
	    }
	}
    }
  if (count_scale != REG_BR_PROB_BASE)
    compute_function_frequency ();

  /* We just processed all calls.  */
  if (cfun->gimple_df)
    vec_free (MODIFIED_NORETURN_CALLS (cfun));

  /* Dump a textual representation of the flowgraph.  */
  if (dump_file)
    gimple_dump_cfg (dump_file, dump_flags);

  if (current_loops
      && (todo & TODO_cleanup_cfg))
    loops_state_set (LOOPS_NEED_FIXUP);

  return todo;
}
static unsigned int
remove_cgraph_callee_edges (void)
{
  cgraph_node_remove_callees (cgraph_get_node (current_function_decl));
  return 0;
}
Ejemplo n.º 19
0
static void
lto_symtab_resolve_symbols (void **slot)
{
  lto_symtab_entry_t e;
  lto_symtab_entry_t prevailing = NULL;

  /* Always set e->node so that edges are updated to reflect decl merging. */
  for (e = (lto_symtab_entry_t) *slot; e; e = e->next)
    {
      if (TREE_CODE (e->decl) == FUNCTION_DECL)
	e->node = cgraph_get_node (e->decl);
      else if (TREE_CODE (e->decl) == VAR_DECL)
	e->vnode = varpool_get_node (e->decl);
      if (e->resolution == LDPR_PREVAILING_DEF_IRONLY
	  || e->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP
	  || e->resolution == LDPR_PREVAILING_DEF)
	prevailing = e;
    }

  /* If the chain is already resolved there is nothing else to do.  */
  if (prevailing)
    return;

  /* Find the single non-replaceable prevailing symbol and
     diagnose ODR violations.  */
  for (e = (lto_symtab_entry_t) *slot; e; e = e->next)
    {
      if (!lto_symtab_resolve_can_prevail_p (e))
	{
	  e->resolution = LDPR_RESOLVED_IR;
          e->guessed = true;
	  continue;
	}

      /* Set a default resolution - the final prevailing one will get
         adjusted later.  */
      e->resolution = LDPR_PREEMPTED_IR;
      e->guessed = true;
      if (!lto_symtab_resolve_replaceable_p (e))
	{
	  if (prevailing)
	    {
	      error_at (DECL_SOURCE_LOCATION (e->decl),
			"%qD has already been defined", e->decl);
	      inform (DECL_SOURCE_LOCATION (prevailing->decl),
		      "previously defined here");
	    }
	  prevailing = e;
	}
    }
  if (prevailing)
    goto found;

  /* Do a second round choosing one from the replaceable prevailing decls.  */
  for (e = (lto_symtab_entry_t) *slot; e; e = e->next)
    {
      if (e->resolution != LDPR_PREEMPTED_IR)
	continue;

      /* Choose the first function that can prevail as prevailing.  */
      if (TREE_CODE (e->decl) == FUNCTION_DECL)
	{
	  prevailing = e;
	  break;
	}

      /* From variables that can prevail choose the largest one.  */
      if (!prevailing
	  || tree_int_cst_lt (DECL_SIZE (prevailing->decl),
			      DECL_SIZE (e->decl)))
	prevailing = e;
    }

  if (!prevailing)
    return;

found:
  /* If current lto files represent the whole program,
    it is correct to use LDPR_PREVALING_DEF_IRONLY.
    If current lto files are part of whole program, internal
    resolver doesn't know if it is LDPR_PREVAILING_DEF
    or LDPR_PREVAILING_DEF_IRONLY.  Use IRONLY conforms to
    using -fwhole-program.  Otherwise, it doesn't
    matter using either LDPR_PREVAILING_DEF or
    LDPR_PREVAILING_DEF_IRONLY
    
    FIXME: above workaround due to gold plugin makes some
    variables IRONLY, which are indeed PREVAILING_DEF in
    resolution file.  These variables still need manual
    externally_visible attribute.  */
    prevailing->resolution = LDPR_PREVAILING_DEF_IRONLY;
    prevailing->guessed = true;
}