Exemple #1
0
void
symtab_node::fixup_same_cpp_alias_visibility (symtab_node *target)
{
  if (is_a <cgraph_node *> (this))
    {
      DECL_DECLARED_INLINE_P (decl)
	 = DECL_DECLARED_INLINE_P (target->decl);
      DECL_DISREGARD_INLINE_LIMITS (decl)
	 = DECL_DISREGARD_INLINE_LIMITS (target->decl);
    }
  /* FIXME: It is not really clear why those flags should not be copied for
     functions, too.  */
  else
    {
      DECL_WEAK (decl) = DECL_WEAK (target->decl);
      DECL_EXTERNAL (decl) = DECL_EXTERNAL (target->decl);
      DECL_VISIBILITY (decl) = DECL_VISIBILITY (target->decl);
    }
  DECL_VIRTUAL_P (decl) = DECL_VIRTUAL_P (target->decl);
  if (TREE_PUBLIC (decl))
    {
      tree group;

      DECL_EXTERNAL (decl) = DECL_EXTERNAL (target->decl);
      DECL_COMDAT (decl) = DECL_COMDAT (target->decl);
      group = target->get_comdat_group ();
      set_comdat_group (group);
      if (group && !same_comdat_group)
	add_to_same_comdat_group (target);
    }
  externally_visible = target->externally_visible;
}
Exemple #2
0
void
fixup_same_cpp_alias_visibility (symtab_node node, symtab_node target)
{
  if (is_a <cgraph_node> (node))
    {
      DECL_DECLARED_INLINE_P (node->symbol.decl)
	 = DECL_DECLARED_INLINE_P (target->symbol.decl);
      DECL_DISREGARD_INLINE_LIMITS (node->symbol.decl)
	 = DECL_DISREGARD_INLINE_LIMITS (target->symbol.decl);
    }
  /* FIXME: It is not really clear why those flags should not be copied for
     functions, too.  */
  else
    {
      DECL_WEAK (node->symbol.decl) = DECL_WEAK (target->symbol.decl);
      DECL_EXTERNAL (node->symbol.decl) = DECL_EXTERNAL (target->symbol.decl);
      DECL_VISIBILITY (node->symbol.decl) = DECL_VISIBILITY (target->symbol.decl);
    }
  DECL_VIRTUAL_P (node->symbol.decl) = DECL_VIRTUAL_P (target->symbol.decl);
  if (TREE_PUBLIC (node->symbol.decl))
    {
      DECL_EXTERNAL (node->symbol.decl) = DECL_EXTERNAL (target->symbol.decl);
      DECL_COMDAT (node->symbol.decl) = DECL_COMDAT (target->symbol.decl);
      DECL_COMDAT_GROUP (node->symbol.decl)
	 = DECL_COMDAT_GROUP (target->symbol.decl);
      if (DECL_ONE_ONLY (target->symbol.decl)
	  && !node->symbol.same_comdat_group)
	symtab_add_to_same_comdat_group ((symtab_node)node, (symtab_node)target);
    }
  node->symbol.externally_visible = target->symbol.externally_visible;
}
static unsigned int
function_and_variable_visibility (void)
{
  struct cgraph_node *node;
  struct varpool_node *vnode;

  for (node = cgraph_nodes; node; node = node->next)
    {
      if (node->reachable
	  && (DECL_COMDAT (node->decl)
	      || (!flag_whole_program
		  && TREE_PUBLIC (node->decl) && !DECL_EXTERNAL (node->decl))))
	node->local.externally_visible = true;
      if (!node->local.externally_visible && node->analyzed
	  && !DECL_EXTERNAL (node->decl))
	{
	  gcc_assert (flag_whole_program || !TREE_PUBLIC (node->decl));
	  TREE_PUBLIC (node->decl) = 0;
	}
      node->local.local = (!node->needed
			   && node->analyzed
			   && !DECL_EXTERNAL (node->decl)
			   && !node->local.externally_visible);
    }
  for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
    {
      if (vnode->needed
	  && !flag_whole_program
	  && (DECL_COMDAT (vnode->decl) || TREE_PUBLIC (vnode->decl)))
	vnode->externally_visible = 1;
      if (!vnode->externally_visible)
	{
	  gcc_assert (flag_whole_program || !TREE_PUBLIC (vnode->decl));
	  TREE_PUBLIC (vnode->decl) = 0;
	}
      /* Static variables defined in auxiliary modules are externalized to
         allow cross module inlining.  */
      gcc_assert (TREE_STATIC (vnode->decl)
                  || varpool_is_auxiliary (vnode));
    }

  if (dump_file)
    {
      fprintf (dump_file, "\nMarking local functions:");
      for (node = cgraph_nodes; node; node = node->next)
	if (node->local.local)
	  fprintf (dump_file, " %s", cgraph_node_name (node));
      fprintf (dump_file, "\n\n");
      fprintf (dump_file, "\nMarking externally visible functions:");
      for (node = cgraph_nodes; node; node = node->next)
	if (node->local.externally_visible)
	  fprintf (dump_file, " %s", cgraph_node_name (node));
      fprintf (dump_file, "\n\n");
    }
  cgraph_function_flags_ready = true;
  return 0;
}
Exemple #4
0
/* Make DECL local.  FIXME: We shouldn't need to mess with rtl this early,
   but other code such as notice_global_symbol generates rtl.  */
void
symtab_make_decl_local (tree decl)
{
  rtx rtl, symbol;

  if (TREE_CODE (decl) == VAR_DECL)
    DECL_COMMON (decl) = 0;
  else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);

  if (DECL_ONE_ONLY (decl) || DECL_COMDAT (decl))
    {
      /* It is possible that we are linking against library defining same COMDAT
	 function.  To avoid conflict we need to rename our local name of the
	 function just in the case WHOPR partitioning decide to make it hidden
	 to avoid cross partition references.  */
      if (flag_wpa)
	{
	  const char *old_name;
          symtab_node node = symtab_get_node (decl);
	  old_name  = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
	  change_decl_assembler_name (decl,
				      clone_function_name (decl, "local"));
	  if (node->symbol.lto_file_data)
	    lto_record_renamed_decl (node->symbol.lto_file_data,
				     old_name,
				     IDENTIFIER_POINTER
				       (DECL_ASSEMBLER_NAME (decl)));
	}
      DECL_SECTION_NAME (decl) = 0;
      DECL_COMDAT (decl) = 0;
    }
  DECL_COMDAT_GROUP (decl) = 0;
  DECL_WEAK (decl) = 0;
  DECL_EXTERNAL (decl) = 0;
  TREE_PUBLIC (decl) = 0;
  if (!DECL_RTL_SET_P (decl))
    return;

  /* Update rtl flags.  */
  make_decl_rtl (decl);

  rtl = DECL_RTL (decl);
  if (!MEM_P (rtl))
    return;

  symbol = XEXP (rtl, 0);
  if (GET_CODE (symbol) != SYMBOL_REF)
    return;

  SYMBOL_REF_WEAK (symbol) = DECL_WEAK (decl);
}
Exemple #5
0
static void
pack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr)
{
  bp_pack_value (bp, DECL_COMMON (expr), 1);
  bp_pack_value (bp, DECL_DLLIMPORT_P (expr), 1);
  bp_pack_value (bp, DECL_WEAK (expr), 1);
  bp_pack_value (bp, DECL_SEEN_IN_BIND_EXPR_P (expr),  1);
  bp_pack_value (bp, DECL_COMDAT (expr),  1);
  bp_pack_value (bp, DECL_VISIBILITY (expr),  2);
  bp_pack_value (bp, DECL_VISIBILITY_SPECIFIED (expr),  1);

  if (TREE_CODE (expr) == VAR_DECL)
    {
      bp_pack_value (bp, DECL_HARD_REGISTER (expr), 1);
      /* DECL_IN_TEXT_SECTION is set during final asm output only. */
      bp_pack_value (bp, DECL_IN_CONSTANT_POOL (expr), 1);
    }

  if (TREE_CODE (expr) == FUNCTION_DECL)
    {
      bp_pack_value (bp, DECL_FINAL_P (expr), 1);
      bp_pack_value (bp, DECL_CXX_CONSTRUCTOR_P (expr), 1);
      bp_pack_value (bp, DECL_CXX_DESTRUCTOR_P (expr), 1);
    }
}
static void
unpack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr)
{
  DECL_DEFER_OUTPUT (expr) = (unsigned) bp_unpack_value (bp, 1);
  DECL_COMMON (expr) = (unsigned) bp_unpack_value (bp, 1);
  DECL_DLLIMPORT_P (expr) = (unsigned) bp_unpack_value (bp, 1);
  DECL_WEAK (expr) = (unsigned) bp_unpack_value (bp, 1);
  DECL_SEEN_IN_BIND_EXPR_P (expr) = (unsigned) bp_unpack_value (bp,  1);
  DECL_COMDAT (expr) = (unsigned) bp_unpack_value (bp,  1);
  DECL_VISIBILITY (expr) = (enum symbol_visibility) bp_unpack_value (bp,  2);
  DECL_VISIBILITY_SPECIFIED (expr) = (unsigned) bp_unpack_value (bp,  1);

  if (TREE_CODE (expr) == VAR_DECL)
    {
      DECL_HARD_REGISTER (expr) = (unsigned) bp_unpack_value (bp, 1);
      DECL_IN_TEXT_SECTION (expr) = (unsigned) bp_unpack_value (bp, 1);
      DECL_IN_CONSTANT_POOL (expr) = (unsigned) bp_unpack_value (bp, 1);
      DECL_TLS_MODEL (expr) = (enum tls_model) bp_unpack_value (bp,  3);
    }

  if (VAR_OR_FUNCTION_DECL_P (expr))
    {
      priority_type p;
      p = (priority_type) bp_unpack_var_len_unsigned (bp);
      SET_DECL_INIT_PRIORITY (expr, p);
    }
}
Exemple #7
0
void
symtab_node::make_decl_local (void)
{
  rtx rtl, symbol;

  /* Avoid clearing comdat_groups on comdat-local decls.  */
  if (TREE_PUBLIC (decl) == 0)
    return;

  if (TREE_CODE (decl) == VAR_DECL)
    DECL_COMMON (decl) = 0;
  else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);

  DECL_COMDAT (decl) = 0;
  DECL_WEAK (decl) = 0;
  DECL_EXTERNAL (decl) = 0;
  DECL_VISIBILITY_SPECIFIED (decl) = 0;
  DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
  TREE_PUBLIC (decl) = 0;
  if (!DECL_RTL_SET_P (decl))
    return;

  /* Update rtl flags.  */
  make_decl_rtl (decl);

  rtl = DECL_RTL (decl);
  if (!MEM_P (rtl))
    return;

  symbol = XEXP (rtl, 0);
  if (GET_CODE (symbol) != SYMBOL_REF)
    return;

  SYMBOL_REF_WEAK (symbol) = DECL_WEAK (decl);
}
Exemple #8
0
/* Mark DECL as finalized.  By finalizing the declaration, frontend instruct the
   middle end to output the variable to asm file, if needed or externally
   visible.  */
void
varpool_finalize_decl (tree decl)
{
  struct varpool_node *node = varpool_node (decl);

  gcc_assert (TREE_STATIC (decl));

  /* The first declaration of a variable that comes through this function
     decides whether it is global (in C, has external linkage)
     or local (in C, has internal linkage).  So do nothing more
     if this function has already run.  */
  if (node->finalized)
    {
      if (cgraph_global_info_ready)
	varpool_assemble_pending_decls ();
      return;
    }
  if (node->needed)
    varpool_enqueue_needed_node (node);
  node->finalized = true;
  if (TREE_THIS_VOLATILE (decl) || DECL_PRESERVE_P (decl)
      /* Traditionally we do not eliminate static variables when not
	 optimizing and when not doing toplevel reoder.  */
      || (!flag_toplevel_reorder && !DECL_COMDAT (node->symbol.decl)
	  && !DECL_ARTIFICIAL (node->symbol.decl)))
    node->symbol.force_output = true;

  if (decide_is_variable_needed (node, decl))
    varpool_mark_needed_node (node);
  if (cgraph_global_info_ready)
    varpool_assemble_pending_decls ();
}
Exemple #9
0
/* Mark DECL as finalized.  By finalizing the declaration, frontend instruct the
   middle end to output the variable to asm file, if needed or externally
   visible.  */
void
varpool_finalize_decl (tree decl)
{
  struct varpool_node *node = varpool_node (decl);

  /* The first declaration of a variable that comes through this function
     decides whether it is global (in C, has external linkage)
     or local (in C, has internal linkage).  So do nothing more
     if this function has already run.  */
  if (node->finalized)
    {
      if (cgraph_global_info_ready)
	varpool_assemble_pending_decls ();
      return;
    }
  if (node->needed)
    varpool_enqueue_needed_node (node);
  node->finalized = true;

  if (decide_is_variable_needed (node, decl))
    varpool_mark_needed_node (node);
  /* Since we reclaim unreachable nodes at the end of every language
     level unit, we need to be conservative about possible entry points
     there.  */
  else if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
    varpool_mark_needed_node (node);
  if (cgraph_global_info_ready)
    varpool_assemble_pending_decls ();
}
/* Determine if variable DECL is needed.  That is, visible to something
   either outside this translation unit, something magic in the system
   configury */
bool
decide_is_variable_needed (struct varpool_node *node, tree decl)
{
  /* If the user told us it is used, then it must be so.  */
  if ((node->externally_visible && !DECL_COMDAT (decl))
      || node->force_output)
    return true;

  /* ??? If the assembler name is set by hand, it is possible to assemble
     the name later after finalizing the function and the fact is noticed
     in assemble_name then.  This is arguably a bug.  */
  if (DECL_ASSEMBLER_NAME_SET_P (decl)
      && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
    return true;

  /* Externally visible variables must be output.  The exception is
     COMDAT variables that must be output only when they are needed.  */
  if (TREE_PUBLIC (decl)
      && !flag_whole_program
      && !flag_lto
      && !flag_whopr
      && !DECL_COMDAT (decl)
      && !DECL_EXTERNAL (decl))
    return true;

  /* When emulating tls, we actually see references to the control
     variable, rather than the user-level variable.  */
  if (!targetm.have_tls
      && TREE_CODE (decl) == VAR_DECL
      && DECL_THREAD_LOCAL_P (decl))
    {
      tree control = emutls_decl (decl);
      if (decide_is_variable_needed (varpool_node (control), control))
	return true;
    }

  /* When not reordering top level variables, we have to assume that
     we are going to keep everything.  */
  if (flag_toplevel_reorder)
    return false;

  /* We want to emit COMDAT variables only when absolutely necessary.  */
  if (DECL_COMDAT (decl))
    return false;
  return true;
}
Exemple #11
0
static bool
decide_is_function_needed (struct cgraph_node *node, tree decl)
{
  if (MAIN_NAME_P (DECL_NAME (decl))
      && TREE_PUBLIC (decl))
    {
      node->local.externally_visible = true;
      return true;
    }

  /* If the user told us it is used, then it must be so.  */
  if (node->local.externally_visible)
    return true;

  /* ??? If the assembler name is set by hand, it is possible to assemble
     the name later after finalizing the function and the fact is noticed
     in assemble_name then.  This is arguably a bug.  */
  if (DECL_ASSEMBLER_NAME_SET_P (decl)
      && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
    return true;

  /* With -fkeep-inline-functions we are keeping all inline functions except
     for extern inline ones.  */
  if (flag_keep_inline_functions
      && DECL_DECLARED_INLINE_P (decl)
      && !DECL_EXTERNAL (decl)
      && !lookup_attribute ("always_inline", DECL_ATTRIBUTES (decl)))
     return true;

  /* If we decided it was needed before, but at the time we didn't have
     the body of the function available, then it's still needed.  We have
     to go back and re-check its dependencies now.  */
  if (node->needed)
    return true;

  /* Externally visible functions must be output.  The exception is
     COMDAT functions that must be output only when they are needed.

     When not optimizing, also output the static functions. (see
     PR24561), but don't do so for always_inline functions, functions
     declared inline and nested functions.  These was optimized out
     in the original implementation and it is unclear whether we want
     to change the behavior here.  */
  if (((TREE_PUBLIC (decl)
	|| (!optimize && !node->local.disregard_inline_limits
	    && !DECL_DECLARED_INLINE_P (decl)
	    && !node->origin))
      && !flag_whole_program)
      && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
    return true;

  /* Constructors and destructors are reachable from the runtime by
     some mechanism.  */
  if (DECL_STATIC_CONSTRUCTOR (decl) || DECL_STATIC_DESTRUCTOR (decl))
    return true;

  return false;
}
Exemple #12
0
void
symtab_make_decl_local (tree decl)
{
  rtx rtl, symbol;

  /* Avoid clearing DECL_COMDAT_GROUP on comdat-local decls.  */
  if (TREE_PUBLIC (decl) == 0)
    return;

  if (TREE_CODE (decl) == VAR_DECL)
    DECL_COMMON (decl) = 0;
  else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);

  if (DECL_ONE_ONLY (decl) || DECL_COMDAT (decl))
    {
      DECL_SECTION_NAME (decl) = 0;
      DECL_COMDAT (decl) = 0;
    }
  DECL_COMDAT_GROUP (decl) = 0;
  DECL_WEAK (decl) = 0;
  DECL_EXTERNAL (decl) = 0;
  DECL_VISIBILITY_SPECIFIED (decl) = 0;
  DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
  TREE_PUBLIC (decl) = 0;
  DECL_DLLIMPORT_P (decl) = 0;
  if (!DECL_RTL_SET_P (decl))
    return;

  /* Update rtl flags.  */
  make_decl_rtl (decl);

  rtl = DECL_RTL (decl);
  if (!MEM_P (rtl))
    return;

  symbol = XEXP (rtl, 0);
  if (GET_CODE (symbol) != SYMBOL_REF)
    return;

  SYMBOL_REF_WEAK (symbol) = DECL_WEAK (decl);
}
Exemple #13
0
symtab_node *
symtab_nonoverwritable_alias (symtab_node *node)
{
  tree new_decl;
  symtab_node *new_node = NULL;

  /* First try to look up existing alias or base object
     (if that is already non-overwritable).  */
  node = symtab_alias_ultimate_target (node, NULL);
  gcc_assert (!node->alias && !node->weakref);
  symtab_for_node_and_aliases (node, symtab_nonoverwritable_alias_1,
		               (void *)&new_node, true);
  if (new_node)
    return new_node;
#ifndef ASM_OUTPUT_DEF
  /* If aliases aren't supported by the assembler, fail.  */
  return NULL;
#endif

  /* Otherwise create a new one.  */
  new_decl = copy_node (node->decl);
  DECL_DLLIMPORT_P (new_decl) = 0;
  DECL_NAME (new_decl) = clone_function_name (node->decl, "localalias");
  if (TREE_CODE (new_decl) == FUNCTION_DECL)
    DECL_STRUCT_FUNCTION (new_decl) = NULL;
  DECL_INITIAL (new_decl) = NULL;
  SET_DECL_ASSEMBLER_NAME (new_decl, DECL_NAME (new_decl));
  SET_DECL_RTL (new_decl, NULL);

  /* Update the properties.  */
  DECL_EXTERNAL (new_decl) = 0;
  if (DECL_ONE_ONLY (node->decl))
    DECL_SECTION_NAME (new_decl) = NULL;
  DECL_COMDAT_GROUP (new_decl) = 0;
  TREE_PUBLIC (new_decl) = 0;
  DECL_COMDAT (new_decl) = 0;
  DECL_WEAK (new_decl) = 0;
  DECL_VIRTUAL_P (new_decl) = 0;
  if (TREE_CODE (new_decl) == FUNCTION_DECL)
    {
      DECL_STATIC_CONSTRUCTOR (new_decl) = 0;
      DECL_STATIC_DESTRUCTOR (new_decl) = 0;
      new_node = cgraph_create_function_alias
				 (new_decl, node->decl);
    }
  else
    new_node = varpool_create_variable_alias (new_decl,
							    node->decl);
  symtab_resolve_alias (new_node, node);  
  gcc_assert (decl_binds_to_current_def_p (new_decl));
  return new_node;
}
Exemple #14
0
static bool
lto_symtab_resolve_replaceable_p (symtab_node e)
{
  if (DECL_EXTERNAL (e->symbol.decl)
      || DECL_COMDAT (e->symbol.decl)
      || DECL_ONE_ONLY (e->symbol.decl)
      || DECL_WEAK (e->symbol.decl))
    return true;

  if (TREE_CODE (e->symbol.decl) == VAR_DECL)
    return (DECL_COMMON (e->symbol.decl)
	    || (!flag_no_common && !DECL_INITIAL (e->symbol.decl)));

  return false;
}
/* Return variable availability.  See cgraph.h for description of individual
   return values.  */
enum availability
cgraph_variable_initializer_availability (struct varpool_node *node)
{
  gcc_assert (cgraph_function_flags_ready);
  if (!node->finalized)
    return AVAIL_NOT_AVAILABLE;
  if (!TREE_PUBLIC (node->decl))
    return AVAIL_AVAILABLE;
  /* If the variable can be overwritten, return OVERWRITABLE.  Takes
     care of at least two notable extensions - the COMDAT variables
     used to share template instantiations in C++.  */
  if (!(*targetm.binds_local_p) (node->decl) && !DECL_COMDAT (node->decl))
    return AVAIL_OVERWRITABLE;
  return AVAIL_AVAILABLE;
}
Exemple #16
0
enum symbol_class
get_symbol_class (symtab_node *node)
{
  /* Inline clones are always duplicated.
     This include external delcarations.   */
  cgraph_node *cnode = dyn_cast <cgraph_node> (node);

  if (DECL_ABSTRACT (node->decl))
    return SYMBOL_EXTERNAL;

  if (cnode && cnode->global.inlined_to)
    return SYMBOL_DUPLICATE;

  /* Weakref aliases are always duplicated.  */
  if (node->weakref)
    return SYMBOL_DUPLICATE;

  /* External declarations are external.  */
  if (DECL_EXTERNAL (node->decl))
    return SYMBOL_EXTERNAL;

  if (varpool_node *vnode = dyn_cast <varpool_node> (node))
    {
      /* Constant pool references use local symbol names that can not
         be promoted global.  We should never put into a constant pool
         objects that can not be duplicated across partitions.  */
      if (DECL_IN_CONSTANT_POOL (node->decl))
	return SYMBOL_DUPLICATE;
      gcc_checking_assert (vnode->definition);
    }
  /* Functions that are cloned may stay in callgraph even if they are unused.
     Handle them as external; compute_ltrans_boundary take care to make
     proper things to happen (i.e. to make them appear in the boundary but
     with body streamed, so clone can me materialized).  */
  else if (!cgraph (node)->definition)
    return SYMBOL_EXTERNAL;

  /* Comdats are duplicated to every use unless they are keyed.
     Those do not need duplication.  */
  if (DECL_COMDAT (node->decl)
      && !node->force_output
      && !symtab_used_from_object_file_p (node))
    return SYMBOL_DUPLICATE;

  return SYMBOL_PARTITION;
}
Exemple #17
0
/* Determine if variable DECL is needed.  That is, visible to something
   either outside this translation unit, something magic in the system
   configury */
bool
decide_is_variable_needed (struct varpool_node *node, tree decl)
{
  /* If the user told us it is used, then it must be so.  */
  if (node->symbol.force_output)
    return true;

  gcc_assert (!DECL_EXTERNAL (decl));

  /* Externally visible variables must be output.  The exception is
     COMDAT variables that must be output only when they are needed.  */
  if (TREE_PUBLIC (decl)
      && !DECL_COMDAT (decl)
      && !DECL_EXTERNAL (decl))
    return true;

  return false;
}
Exemple #18
0
static bool
can_remove_node_now_p_1 (struct cgraph_node *node)
{
  /* FIXME: When address is taken of DECL_EXTERNAL function we still
     can remove its offline copy, but we would need to keep unanalyzed node in
     the callgraph so references can point to it.  */
  return (!node->symbol.address_taken
	  && !ipa_ref_has_aliases_p (&node->symbol.ref_list)
	  && cgraph_can_remove_if_no_direct_calls_p (node)
	  /* Inlining might enable more devirtualizing, so we want to remove
	     those only after all devirtualizable virtual calls are processed.
	     Lacking may edges in callgraph we just preserve them post
	     inlining.  */
	  && (!DECL_VIRTUAL_P (node->symbol.decl)
	      || (!DECL_COMDAT (node->symbol.decl)
		  && !DECL_EXTERNAL (node->symbol.decl)))
	  /* During early inlining some unanalyzed cgraph nodes might be in the
	     callgraph and they might reffer the function in question.  */
	  && !cgraph_new_nodes);
}
/* Mark DECL as finalized.  By finalizing the declaration, frontend instruct the
   middle end to output the variable to asm file, if needed or externally
   visible.  */
void
varpool_finalize_decl (tree decl)
{
  struct varpool_node *node = varpool_node (decl);

  /* FIXME: We don't really stream varpool datastructure and instead rebuild it
     by varpool_finalize_decl.  This is not quite correct since this way we can't
     attach any info to varpool.  Eventually we will want to stream varpool nodes
     and the flags.

     For the moment just prevent analysis of varpool nodes to happen again, so
     we will re-try to compute "address_taken" flag of varpool that breaks
     in presence of clones.  */
  if (in_lto_p)
    node->analyzed = true;

  /* The first declaration of a variable that comes through this function
     decides whether it is global (in C, has external linkage)
     or local (in C, has internal linkage).  So do nothing more
     if this function has already run.  */
  if (node->finalized)
    {
      if (cgraph_global_info_ready)
	varpool_assemble_pending_decls ();
      return;
    }
  if (node->needed)
    varpool_enqueue_needed_node (node);
  node->finalized = true;

  if (decide_is_variable_needed (node, decl))
    varpool_mark_needed_node (node);
  /* Since we reclaim unreachable nodes at the end of every language
     level unit, we need to be conservative about possible entry points
     there.  */
  else if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
    varpool_mark_needed_node (node);
  if (cgraph_global_info_ready)
    varpool_assemble_pending_decls ();
}
Exemple #20
0
static tree
associated_type (tree decl)
{
  tree t = NULL_TREE;

  /* In the C++ frontend, DECL_CONTEXT for a method doesn't actually refer
     to the containing class.  So we look at the 'this' arg.  */
  if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
    {
      /* Artificial methods are not affected by the import/export status
	 of their class unless they are COMDAT.  Implicit copy ctor's and
	 dtor's are not affected by class status but virtual and
	 non-virtual thunks are.  */
      if (!DECL_ARTIFICIAL (decl) || DECL_COMDAT (decl))
	t = TYPE_MAIN_VARIANT
	  (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl)))));
    }
  else if (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl)))
    t = DECL_CONTEXT (decl);

  return t;
}
Exemple #21
0
/* Determine if variable DECL is needed.  That is, visible to something
   either outside this translation unit, something magic in the system
   configury */
bool
decide_is_variable_needed (struct varpool_node *node, tree decl)
{
  /* If the user told us it is used, then it must be so.  */
  if (node->force_output)
    return true;

  gcc_assert (!DECL_EXTERNAL (decl));

  /* Externally visible variables must be output.  The exception is
     COMDAT variables that must be output only when they are needed.  */
  if (TREE_PUBLIC (decl)
      && !DECL_COMDAT (decl)
      && !DECL_EXTERNAL (decl))
    return true;

  /* When not reordering top level variables, we have to assume that
     we are going to keep everything.  */
  if (!flag_toplevel_reorder)
    return true;
  return false;
}
Exemple #22
0
symtab_node
symtab_nonoverwritable_alias (symtab_node node)
{
  tree new_decl;
  symtab_node new_node = NULL;
  symtab_for_node_and_aliases (node, symtab_nonoverwritable_alias_1,
		               (void *)&new_node, true);
  if (new_node)
    return new_node;

  new_decl = copy_node (node->symbol.decl);
  DECL_NAME (new_decl) = clone_function_name (node->symbol.decl, "localalias");
  if (TREE_CODE (new_decl) == FUNCTION_DECL)
    DECL_STRUCT_FUNCTION (new_decl) = NULL;
  DECL_INITIAL (new_decl) = NULL;
  SET_DECL_ASSEMBLER_NAME (new_decl, DECL_NAME (new_decl));
  SET_DECL_RTL (new_decl, NULL);

  /* Update the properties.  */
  DECL_EXTERNAL (new_decl) = 0;
  if (DECL_ONE_ONLY (node->symbol.decl))
    DECL_SECTION_NAME (new_decl) = NULL;
  DECL_COMDAT_GROUP (new_decl) = 0;
  TREE_PUBLIC (new_decl) = 0;
  DECL_COMDAT (new_decl) = 0;
  DECL_WEAK (new_decl) = 0;
  DECL_VIRTUAL_P (new_decl) = 0;
  if (TREE_CODE (new_decl) == FUNCTION_DECL)
    {
      DECL_STATIC_CONSTRUCTOR (new_decl) = 0;
      DECL_STATIC_DESTRUCTOR (new_decl) = 0;
      new_node = (symtab_node) cgraph_create_function_alias (new_decl, node->symbol.decl);
    }
  else
    new_node = (symtab_node) varpool_create_variable_alias (new_decl, node->symbol.decl);
  symtab_resolve_alias (new_node, node);  
  return new_node;
}
static void
pack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr)
{
  bp_pack_value (bp, DECL_DEFER_OUTPUT (expr), 1);
  bp_pack_value (bp, DECL_COMMON (expr), 1);
  bp_pack_value (bp, DECL_DLLIMPORT_P (expr), 1);
  bp_pack_value (bp, DECL_WEAK (expr), 1);
  bp_pack_value (bp, DECL_SEEN_IN_BIND_EXPR_P (expr),  1);
  bp_pack_value (bp, DECL_COMDAT (expr),  1);
  bp_pack_value (bp, DECL_VISIBILITY (expr),  2);
  bp_pack_value (bp, DECL_VISIBILITY_SPECIFIED (expr),  1);

  if (TREE_CODE (expr) == VAR_DECL)
    {
      bp_pack_value (bp, DECL_HARD_REGISTER (expr), 1);
      bp_pack_value (bp, DECL_IN_TEXT_SECTION (expr), 1);
      bp_pack_value (bp, DECL_IN_CONSTANT_POOL (expr), 1);
      bp_pack_value (bp, DECL_TLS_MODEL (expr),  3);
    }

  if (VAR_OR_FUNCTION_DECL_P (expr))
    bp_pack_var_len_unsigned (bp, DECL_INIT_PRIORITY (expr));
}
Exemple #24
0
void
cgraph_finalize_function (tree decl, bool nested)
{
  struct cgraph_node *node = cgraph_node (decl);

  if (node->local.finalized)
    cgraph_reset_node (node);

  node->pid = cgraph_max_pid ++;
  notice_global_symbol (decl);
  node->local.finalized = true;
  node->lowered = DECL_STRUCT_FUNCTION (decl)->cfg != NULL;
  record_cdtor_fn (node->decl);
  if (node->nested)
    lower_nested_functions (decl);
  gcc_assert (!node->nested);

  if (decide_is_function_needed (node, decl))
    cgraph_mark_needed_node (node);

  /* Since we reclaim unreachable nodes at the end of every language
     level unit, we need to be conservative about possible entry points
     there.  */
  if ((TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl)))
    cgraph_mark_reachable_node (node);

  /* If we've not yet emitted decl, tell the debug info about it.  */
  if (!TREE_ASM_WRITTEN (decl))
    (*debug_hooks->deferred_inline_function) (decl);

  /* Possibly warn about unused parameters.  */
  if (warn_unused_parameter)
    do_warn_unused_parameter (decl);

  if (!nested)
    ggc_collect ();
}
Exemple #25
0
static void
unpack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr)
{
  DECL_COMMON (expr) = (unsigned) bp_unpack_value (bp, 1);
  DECL_DLLIMPORT_P (expr) = (unsigned) bp_unpack_value (bp, 1);
  DECL_WEAK (expr) = (unsigned) bp_unpack_value (bp, 1);
  DECL_SEEN_IN_BIND_EXPR_P (expr) = (unsigned) bp_unpack_value (bp,  1);
  DECL_COMDAT (expr) = (unsigned) bp_unpack_value (bp,  1);
  DECL_VISIBILITY (expr) = (enum symbol_visibility) bp_unpack_value (bp,  2);
  DECL_VISIBILITY_SPECIFIED (expr) = (unsigned) bp_unpack_value (bp,  1);

  if (TREE_CODE (expr) == VAR_DECL)
    {
      DECL_HARD_REGISTER (expr) = (unsigned) bp_unpack_value (bp, 1);
      DECL_IN_CONSTANT_POOL (expr) = (unsigned) bp_unpack_value (bp, 1);
    }

  if (TREE_CODE (expr) == FUNCTION_DECL)
    {
      DECL_FINAL_P (expr) = (unsigned) bp_unpack_value (bp, 1);
      DECL_CXX_CONSTRUCTOR_P (expr) = (unsigned) bp_unpack_value (bp, 1);
      DECL_CXX_DESTRUCTOR_P (expr) = (unsigned) bp_unpack_value (bp, 1);
    }
}
Exemple #26
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;
}
Exemple #27
0
static void
lto_symtab_merge_decls_2 (symtab_node *first, bool diagnosed_p)
{
  symtab_node *prevailing;
  symtab_node *e;
  vec<tree> mismatches = vNULL;
  unsigned i;
  tree decl;
  bool tbaa_p = false;

  /* Nothing to do for a single entry.  */
  prevailing = first;
  if (!prevailing->next_sharing_asm_name)
    return;

  /* Try to merge each entry with the prevailing one.  */
  symtab_node *last_prevailing = prevailing, *next;
  for (e = prevailing->next_sharing_asm_name; e; e = next)
    {
      next = e->next_sharing_asm_name;

      /* Skip non-LTO symbols and symbols whose declaration we already
	 visited.  */
      if (lto_symtab_prevailing_decl (e->decl) != e->decl
	  || !lto_symtab_symbol_p (e)
          || e->decl == prevailing->decl)
	continue;

      if (!lto_symtab_merge (prevailing, e)
	  && !diagnosed_p
	  && !DECL_ARTIFICIAL (e->decl))
	mismatches.safe_push (e->decl);

      symtab_node *this_prevailing;
      for (this_prevailing = prevailing; ;
	   this_prevailing = this_prevailing->next_sharing_asm_name)
	{
	  if (this_prevailing->decl != e->decl
	      && lto_symtab_merge_p (this_prevailing->decl, e->decl))
	    break;
	  if (this_prevailing == last_prevailing)
	    {
	      this_prevailing = NULL;
	      break;
	    }
	}

      if (this_prevailing)
	lto_symtab_prevail_decl (this_prevailing->decl, e->decl);
      /* Maintain LRU list: relink the new prevaililng symbol
	 just after previaling node in the chain and update last_prevailing.
	 Since the number of possible declarations of a given symbol is
	 small, this should be faster than building a hash.  */
      else if (e == prevailing->next_sharing_asm_name)
	last_prevailing = e;
      else
	{
	  if (e->next_sharing_asm_name)
	    e->next_sharing_asm_name->previous_sharing_asm_name
	      = e->previous_sharing_asm_name;
	  e->previous_sharing_asm_name->next_sharing_asm_name
	    = e->next_sharing_asm_name;
	  e->previous_sharing_asm_name = prevailing;
	  e->next_sharing_asm_name = prevailing->next_sharing_asm_name;
	  prevailing->next_sharing_asm_name->previous_sharing_asm_name = e;
	  prevailing->next_sharing_asm_name = e;
	  if (last_prevailing == prevailing)
	    last_prevailing = e;
	}
    }
  if (mismatches.is_empty ())
    return;

  /* Diagnose all mismatched re-declarations.  */
  FOR_EACH_VEC_ELT (mismatches, i, decl)
    {
      int level = warn_type_compatibility_p (TREE_TYPE (prevailing->decl),
					     TREE_TYPE (decl),
					     DECL_COMDAT (decl));
      if (level)
	{
	  bool diag = false;
	  if (level & 2)
	    diag = warning_at (DECL_SOURCE_LOCATION (decl),
			       OPT_Wodr,
			       "%qD violates the C++ One Definition Rule ",
			       decl);
	  if (!diag && (level & 1))
	    diag = warning_at (DECL_SOURCE_LOCATION (decl),
			       OPT_Wlto_type_mismatch,
			       "type of %qD does not match original "
			       "declaration", decl);
	  if (diag)
	    {
	      warn_types_mismatch (TREE_TYPE (prevailing->decl),
				   TREE_TYPE (decl),
				   DECL_SOURCE_LOCATION (prevailing->decl),
				   DECL_SOURCE_LOCATION (decl));
	      if ((level & 4)
		  && !TREE_READONLY (prevailing->decl))
		tbaa_p = true;
	    }
	  diagnosed_p |= diag;
	}
      else if ((DECL_USER_ALIGN (prevailing->decl)
	        && DECL_USER_ALIGN (decl))
	       && DECL_ALIGN (prevailing->decl) < DECL_ALIGN (decl))
	{
	  diagnosed_p |= warning_at (DECL_SOURCE_LOCATION (decl),
				     OPT_Wlto_type_mismatch,
				     "alignment of %qD is bigger than "
				     "original declaration", decl);
	}
      else
	diagnosed_p |= warning_at (DECL_SOURCE_LOCATION (decl),
				   OPT_Wlto_type_mismatch,
				   "size of %qD differ from the size of "
				   "original declaration", decl);
    }
Exemple #28
0
/* Walk the decls we marked as necessary and see if they reference new
   variables or functions and add them into the worklists.  */
bool
varpool_analyze_pending_decls (void)
{
  bool changed = false;

  timevar_push (TV_VARPOOL);
  while (varpool_first_unanalyzed_node)
    {
      struct varpool_node *node = varpool_first_unanalyzed_node, *next;
      tree decl = node->decl;
      bool analyzed = node->analyzed;

      varpool_first_unanalyzed_node->analyzed = true;

      varpool_first_unanalyzed_node = varpool_first_unanalyzed_node->next_needed;

      /* When reading back varpool at LTO time, we re-construct the queue in order
         to have "needed" list right by inserting all needed nodes into varpool.
	 We however don't want to re-analyze already analyzed nodes.  */
      if (!analyzed)
	{
	  gcc_assert (!in_lto_p || cgraph_function_flags_ready);
          /* Compute the alignment early so function body expanders are
	     already informed about increased alignment.  */
          align_variable (decl, 0);
	}
      if (node->alias && node->alias_of)
	{
	  struct varpool_node *tgt = varpool_node (node->alias_of);
          struct varpool_node *n;

	  for (n = tgt; n && n->alias;
	       n = n->analyzed ? varpool_alias_aliased_node (n) : NULL)
	    if (n == node)
	      {
		error ("variable %q+D part of alias cycle", node->decl);
		node->alias = false;
		continue;
	      }
	  if (!VEC_length (ipa_ref_t, node->ref_list.references))
	    ipa_record_reference (NULL, node, NULL, tgt, IPA_REF_ALIAS, NULL);
	  /* C++ FE sometimes change linkage flags after producing same body aliases.  */
	  if (node->extra_name_alias)
	    {
	      DECL_WEAK (node->decl) = DECL_WEAK (node->alias_of);
	      TREE_PUBLIC (node->decl) = TREE_PUBLIC (node->alias_of);
	      DECL_EXTERNAL (node->decl) = DECL_EXTERNAL (node->alias_of);
	      DECL_VISIBILITY (node->decl) = DECL_VISIBILITY (node->alias_of);
	      if (TREE_PUBLIC (node->decl))
		{
		  DECL_COMDAT (node->decl) = DECL_COMDAT (node->alias_of);
		  DECL_COMDAT_GROUP (node->decl) = DECL_COMDAT_GROUP (node->alias_of);
		  if (DECL_ONE_ONLY (node->alias_of) && !node->same_comdat_group)
		    {
		      node->same_comdat_group = tgt;
		      if (!tgt->same_comdat_group)
			tgt->same_comdat_group = node;
		      else
			{
			  struct varpool_node *n;
			  for (n = tgt->same_comdat_group;
			       n->same_comdat_group != tgt;
			       n = n->same_comdat_group)
			    ;
			  n->same_comdat_group = node;
			}
		    }
		}
	    }
	}
      else if (DECL_INITIAL (decl))
	record_references_in_initializer (decl, analyzed);
      if (node->same_comdat_group)
	{
	  for (next = node->same_comdat_group;
	       next != node;
	       next = next->same_comdat_group)
	    varpool_mark_needed_node (next);
	}
      changed = true;
    }
  timevar_pop (TV_VARPOOL);
  return changed;
}
Exemple #29
0
void
emit_support_tinfos (void)
{
  static tree *const fundamentals[] =
  {
    &void_type_node,
    &boolean_type_node,
    &wchar_type_node,
    &char_type_node, &signed_char_type_node, &unsigned_char_type_node,
    &short_integer_type_node, &short_unsigned_type_node,
    &integer_type_node, &unsigned_type_node,
    &long_integer_type_node, &long_unsigned_type_node,
    &long_long_integer_type_node, &long_long_unsigned_type_node,
    &float_type_node, &double_type_node, &long_double_type_node,
    0
  };
  int ix;
  tree bltn_type, dtor;
  
  push_nested_namespace (abi_node);
  bltn_type = xref_tag (class_type,
			get_identifier ("__fundamental_type_info"), 
			/* APPLE LOCAL 4184203 */
			/*tag_scope=*/ts_global, false);
  pop_nested_namespace (abi_node);
  if (!COMPLETE_TYPE_P (bltn_type))
    return;
  dtor = CLASSTYPE_DESTRUCTORS (bltn_type);
  if (!dtor || DECL_EXTERNAL (dtor))
    return;
  doing_runtime = 1;
  for (ix = 0; fundamentals[ix]; ix++)
    {
      tree bltn = *fundamentals[ix];
      tree types[3];
      int i;

      types[0] = bltn;
      types[1] = build_pointer_type (bltn);
      types[2] = build_pointer_type (build_qualified_type (bltn, 
							   TYPE_QUAL_CONST));
 
      for (i = 0; i < 3; ++i)
	{
	  tree tinfo;

	  tinfo = get_tinfo_decl (types[i]);
	  TREE_USED (tinfo) = 1;
	  mark_needed (tinfo);
/* APPLE LOCAL begin mainline 4.3 2006-01-10 4871915 */
	  /* The C++ ABI requires that these objects be COMDAT.  But,
	     On systems without weak symbols, initialized COMDAT 
	     objects are emitted with internal linkage.  (See
	     comdat_linkage for details.)  Since we want these objects
	     to have external linkage so that copies do not have to be
	     emitted in code outside the runtime library, we make them
	     non-COMDAT here.  

	     It might also not be necessary to follow this detail of the
	     ABI.  */
	  if (!flag_weak || ! targetm.cxx.library_rtti_comdat ())
/* APPLE LOCAL end mainline 4.3 2006-01-10 4871915 */
	    {
	      gcc_assert (TREE_PUBLIC (tinfo) && !DECL_COMDAT (tinfo));
	      DECL_INTERFACE_KNOWN (tinfo) = 1;
	    }
	}
    }
}
Exemple #30
0
void
dump_symtab_base (FILE *f, symtab_node node)
{
  static const char * const visibility_types[] = {
    "default", "protected", "hidden", "internal"
  };

  fprintf (f, "%s/%i (%s)",
	   symtab_node_asm_name (node),
	   node->symbol.order,
	   symtab_node_name (node));
  dump_addr (f, " @", (void *)node);
  fprintf (f, "\n  Type: %s\n", symtab_type_names[node->symbol.type]);
  fprintf (f, "  Visibility:");

  if (node->symbol.in_other_partition)
    fprintf (f, " in_other_partition");
  if (node->symbol.used_from_other_partition)
    fprintf (f, " used_from_other_partition");
  if (node->symbol.force_output)
    fprintf (f, " force_output");
  if (node->symbol.resolution != LDPR_UNKNOWN)
    fprintf (f, " %s",
 	     ld_plugin_symbol_resolution_names[(int)node->symbol.resolution]);
  if (TREE_ASM_WRITTEN (node->symbol.decl))
    fprintf (f, " asm_written");
  if (DECL_EXTERNAL (node->symbol.decl))
    fprintf (f, " external");
  if (TREE_PUBLIC (node->symbol.decl))
    fprintf (f, " public");
  if (DECL_COMMON (node->symbol.decl))
    fprintf (f, " common");
  if (DECL_WEAK (node->symbol.decl))
    fprintf (f, " weak");
  if (DECL_DLLIMPORT_P (node->symbol.decl))
    fprintf (f, " dll_import");
  if (DECL_COMDAT (node->symbol.decl))
    fprintf (f, " comdat");
  if (DECL_COMDAT_GROUP (node->symbol.decl))
    fprintf (f, " comdat_group:%s",
	     IDENTIFIER_POINTER (DECL_COMDAT_GROUP (node->symbol.decl)));
  if (DECL_ONE_ONLY (node->symbol.decl))
    fprintf (f, " one_only");
  if (DECL_SECTION_NAME (node->symbol.decl))
    fprintf (f, " section_name:%s",
	     TREE_STRING_POINTER (DECL_SECTION_NAME (node->symbol.decl)));
  if (DECL_VISIBILITY_SPECIFIED (node->symbol.decl))
    fprintf (f, " visibility_specified");
  if (DECL_VISIBILITY (node->symbol.decl))
    fprintf (f, " visibility:%s",
	     visibility_types [DECL_VISIBILITY (node->symbol.decl)]);
  if (DECL_VIRTUAL_P (node->symbol.decl))
    fprintf (f, " virtual");
  if (DECL_ARTIFICIAL (node->symbol.decl))
    fprintf (f, " artificial");
  if (TREE_CODE (node->symbol.decl) == FUNCTION_DECL)
    {
      if (DECL_STATIC_CONSTRUCTOR (node->symbol.decl))
	fprintf (f, " constructor");
      if (DECL_STATIC_DESTRUCTOR (node->symbol.decl))
	fprintf (f, " destructor");
    }
  fprintf (f, "\n");
  
  if (node->symbol.same_comdat_group)
    fprintf (f, "  Same comdat group as: %s/%i\n",
	     symtab_node_asm_name (node->symbol.same_comdat_group),
	     node->symbol.same_comdat_group->symbol.order);
  if (node->symbol.next_sharing_asm_name)
    fprintf (f, "  next sharing asm name: %i\n",
	     node->symbol.next_sharing_asm_name->symbol.order);
  if (node->symbol.previous_sharing_asm_name)
    fprintf (f, "  previous sharing asm name: %i\n",
	     node->symbol.previous_sharing_asm_name->symbol.order);

  if (node->symbol.address_taken)
    fprintf (f, "  Address is taken.\n");
  if (node->symbol.aux)
    {
      fprintf (f, "  Aux:");
      dump_addr (f, " @", (void *)node->symbol.aux);
    }

  fprintf (f, "  References: ");
  ipa_dump_references (f, &node->symbol.ref_list);
  fprintf (f, "  Referring: ");
  ipa_dump_referring (f, &node->symbol.ref_list);
}