示例#1
0
文件: symtab.c 项目: Roffi/gcc
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;
}
示例#2
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;
}
示例#3
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);
}
示例#4
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;
}
示例#5
0
enum symbol_partitioning_class
symtab_get_symbol_partitioning_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;

  /* Linker discardable symbols are duplicated to every use unless they are
     keyed.
     Keyed symbols or those.  */
  if (DECL_ONE_ONLY (node->decl)
      && !node->force_output
      && !node->forced_by_abi
      && !symtab_used_from_object_file_p (node))
    return SYMBOL_DUPLICATE;

  return SYMBOL_PARTITION;
}
示例#6
0
文件: method.c 项目: Fokycnuk/gcc
static tree
make_alias_for_thunk (tree function)
{
  tree alias;
  char buf[256];

#if defined (TARGET_IS_PE_COFF)
  if (DECL_ONE_ONLY (function))
    return function;
#endif

  ASM_GENERATE_INTERNAL_LABEL (buf, "LTHUNK", thunk_labelno);
  thunk_labelno++;
  alias = build_decl (FUNCTION_DECL, get_identifier (buf),
		      TREE_TYPE (function));
  DECL_LANG_SPECIFIC (alias) = DECL_LANG_SPECIFIC (function);
  cxx_dup_lang_specific_decl (alias);
  DECL_CONTEXT (alias) = NULL;
  TREE_READONLY (alias) = TREE_READONLY (function);
  TREE_THIS_VOLATILE (alias) = TREE_THIS_VOLATILE (function);
  TREE_PUBLIC (alias) = 0;
  DECL_INTERFACE_KNOWN (alias) = 1;
  DECL_NOT_REALLY_EXTERN (alias) = 1;
  DECL_THIS_STATIC (alias) = 1;
  DECL_SAVED_FUNCTION_DATA (alias) = NULL;
  DECL_DESTRUCTOR_P (alias) = 0;
  DECL_CONSTRUCTOR_P (alias) = 0;
  DECL_CLONED_FUNCTION (alias) = NULL_TREE;
  DECL_EXTERNAL (alias) = 0;
  DECL_ARTIFICIAL (alias) = 1;
  DECL_NO_STATIC_CHAIN (alias) = 1;
  DECL_PENDING_INLINE_P (alias) = 0;
  DECL_INLINE (alias) = 0;
  DECL_DECLARED_INLINE_P (alias) = 0;
  DECL_DEFERRED_FN (alias) = 0;
  DECL_USE_TEMPLATE (alias) = 0;
  DECL_TEMPLATE_INSTANTIATED (alias) = 0;
  DECL_TEMPLATE_INFO (alias) = NULL;
  DECL_INITIAL (alias) = error_mark_node;
  TREE_ADDRESSABLE (alias) = 1;
  TREE_USED (alias) = 1;
  SET_DECL_ASSEMBLER_NAME (alias, DECL_NAME (alias));
  TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias)) = 1;
  if (!flag_syntax_only)
    assemble_alias (alias, DECL_ASSEMBLER_NAME (function));
  return alias;
}
示例#7
0
unsigned int
i386_pe_section_type_flags (tree decl, const char *name, int reloc)
{
  static htab_t htab;
  unsigned int flags;
  unsigned int **slot;

  /* The names we put in the hashtable will always be the unique
     versions given to us by the stringtable, so we can just use
     their addresses as the keys.  */
  if (!htab)
    htab = htab_create (31, htab_hash_pointer, htab_eq_pointer, NULL);

  if (decl && TREE_CODE (decl) == FUNCTION_DECL)
    flags = SECTION_CODE;
  else if (decl && decl_readonly_section (decl, reloc))
    flags = 0;
  else
    {
      flags = SECTION_WRITE;

      if (decl && TREE_CODE (decl) == VAR_DECL
 /* APPLE LOCAL begin mainline 2005-04-01 */
          && lookup_attribute ("shared", DECL_ATTRIBUTES (decl)))
        flags |= SECTION_PE_SHARED;
 /* APPLE LOCAL end mainline 2005-04-01 */
    }

  if (decl && DECL_ONE_ONLY (decl))
    flags |= SECTION_LINKONCE;

  /* See if we already have an entry for this section.  */
  slot = (unsigned int **) htab_find_slot (htab, name, INSERT);
  if (!*slot)
    {
      *slot = (unsigned int *) xmalloc (sizeof (unsigned int));
      **slot = flags;
    }
  else
    {
      if (decl && **slot != flags)
        error ("%J'%D' causes a section type conflict", decl, decl);
    }

  return flags;
}
示例#8
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);
}
示例#9
0
void
symtab_add_to_same_comdat_group (symtab_node new_node,
				 symtab_node old_node)
{
  gcc_assert (DECL_ONE_ONLY (old_node->symbol.decl));
  gcc_assert (!new_node->symbol.same_comdat_group);
  gcc_assert (new_node != old_node);

  DECL_COMDAT_GROUP (new_node->symbol.decl) = DECL_COMDAT_GROUP (old_node->symbol.decl);
  new_node->symbol.same_comdat_group = old_node;
  if (!old_node->symbol.same_comdat_group)
    old_node->symbol.same_comdat_group = new_node;
  else
    {
      symtab_node n;
      for (n = old_node->symbol.same_comdat_group;
	   n->symbol.same_comdat_group != old_node;
	   n = n->symbol.same_comdat_group)
	;
      n->symbol.same_comdat_group = new_node;
    }
}
示例#10
0
文件: symtab.c 项目: Roffi/gcc
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;
}
示例#11
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);
}
示例#12
0
DEBUG_FUNCTION bool
verify_symtab_base (symtab_node node)
{
  bool error_found = false;
  symtab_node hashed_node;

  if (symtab_function_p (node))
    {
      if (TREE_CODE (node->symbol.decl) != FUNCTION_DECL)
	{
          error ("function symbol is not function");
          error_found = true;
	}
    }
  else if (symtab_variable_p (node))
    {
      if (TREE_CODE (node->symbol.decl) != VAR_DECL)
	{
          error ("variable symbol is not variable");
          error_found = true;
	}
    }
  else
    {
      error ("node has unknown type");
      error_found = true;
    }
   
  hashed_node = symtab_get_node (node->symbol.decl);
  if (!hashed_node)
    {
      error ("node not found in symtab decl hashtable");
      error_found = true;
    }
  if (assembler_name_hash)
    {
      hashed_node = symtab_node_for_asm (DECL_ASSEMBLER_NAME (node->symbol.decl));
      if (hashed_node && hashed_node->symbol.previous_sharing_asm_name)
	{
          error ("assembler name hash list corrupted");
          error_found = true;
	}
      while (hashed_node)
	{
	  if (hashed_node == node)
	    break;
	  hashed_node = hashed_node->symbol.next_sharing_asm_name;
	}
      if (!hashed_node)
	{
          error ("node not found in symtab assembler name hash");
          error_found = true;
	}
    }
  if (node->symbol.previous_sharing_asm_name
      && node->symbol.previous_sharing_asm_name->symbol.next_sharing_asm_name != node)
    {
      error ("double linked list of assembler names corrupted");
    }
  if (node->symbol.same_comdat_group)
    {
      symtab_node n = node->symbol.same_comdat_group;

      if (!DECL_ONE_ONLY (n->symbol.decl))
	{
	  error ("non-DECL_ONE_ONLY node in a same_comdat_group list");
	  error_found = true;
	}
      if (n->symbol.type != node->symbol.type)
	{
	  error ("mixing different types of symbol in same comdat groups is not supported");
	  error_found = true;
	}
      if (n == node)
	{
	  error ("node is alone in a comdat group");
	  error_found = true;
	}
      do
	{
	  if (!n->symbol.same_comdat_group)
	    {
	      error ("same_comdat_group is not a circular list");
	      error_found = true;
	      break;
	    }
	  n = n->symbol.same_comdat_group;
	}
      while (n != node);
    }
  return error_found;
}
/// emit_global_to_llvm - Emit the specified VAR_DECL or aggregate CONST_DECL to
/// LLVM as a global variable.  This function implements the end of
/// assemble_variable.
void emit_global_to_llvm(tree decl) {
  if (errorcount || sorrycount) return;

  // FIXME: Support alignment on globals: DECL_ALIGN.
  // FIXME: DECL_PRESERVE_P indicates the var is marked with attribute 'used'.

  // Global register variables don't turn into LLVM GlobalVariables.
  if (TREE_CODE(decl) == VAR_DECL && DECL_REGISTER(decl))
    return;

  timevar_push(TV_LLVM_GLOBALS);

  // Get or create the global variable now.
  GlobalVariable *GV = cast<GlobalVariable>(DECL_LLVM(decl));
  
  // Convert the initializer over.
  Constant *Init;
  if (DECL_INITIAL(decl) == 0 || DECL_INITIAL(decl) == error_mark_node) {
    // This global should be zero initialized.  Reconvert the type in case the
    // forward def of the global and the real def differ in type (e.g. declared
    // as 'int A[]', and defined as 'int A[100]').
    Init = Constant::getNullValue(ConvertType(TREE_TYPE(decl)));
  } else {
    assert((TREE_CONSTANT(DECL_INITIAL(decl)) || 
            TREE_CODE(DECL_INITIAL(decl)) == STRING_CST) &&
           "Global initializer should be constant!");
    
    // Temporarily set an initializer for the global, so we don't infinitely
    // recurse.  If we don't do this, we can hit cases where we see "oh a global
    // with an initializer hasn't been initialized yet, call emit_global_to_llvm
    // on it".  When constructing the initializer it might refer to itself.
    // this can happen for things like void *G = &G;
    //
    GV->setInitializer(UndefValue::get(GV->getType()->getElementType()));
    Init = TreeConstantToLLVM::Convert(DECL_INITIAL(decl));
  }

  // If we had a forward definition that has a type that disagrees with our
  // initializer, insert a cast now.  This sort of thing occurs when we have a
  // global union, and the LLVM type followed a union initializer that is
  // different from the union element used for the type.
  if (GV->getType()->getElementType() != Init->getType()) {
    GV->removeFromParent();
    GlobalVariable *NGV = new GlobalVariable(Init->getType(), GV->isConstant(),
                                             GlobalValue::ExternalLinkage, 0,
                                             GV->getName(), TheModule);
    GV->replaceAllUsesWith(ConstantExpr::getBitCast(NGV, GV->getType()));
    delete GV;
    SET_DECL_LLVM(decl, NGV);
    GV = NGV;
  }
 
  // Set the initializer.
  GV->setInitializer(Init);

  // Set thread local (TLS)
  if (TREE_CODE(decl) == VAR_DECL && DECL_THREAD_LOCAL(decl))
    GV->setThreadLocal(true);

  // Set the linkage.
  if (!TREE_PUBLIC(decl)) {
    GV->setLinkage(GlobalValue::InternalLinkage);
  } else if (DECL_WEAK(decl) || DECL_ONE_ONLY(decl) ||
             (DECL_COMMON(decl) &&  // DECL_COMMON is only meaningful if no init
              (!DECL_INITIAL(decl) || DECL_INITIAL(decl) == error_mark_node))) {
    // llvm-gcc also includes DECL_VIRTUAL_P here.
    GV->setLinkage(GlobalValue::WeakLinkage);
  } else if (DECL_COMDAT(decl)) {
    GV->setLinkage(GlobalValue::LinkOnceLinkage);
  }

#ifdef TARGET_ADJUST_LLVM_LINKAGE
  TARGET_ADJUST_LLVM_LINKAGE(GV,decl);
#endif /* TARGET_ADJUST_LLVM_LINKAGE */

  // Handle visibility style
  if (TREE_PUBLIC(decl)) {
    if (DECL_VISIBILITY(decl) == VISIBILITY_HIDDEN)
      GV->setVisibility(GlobalValue::HiddenVisibility);
    else if (DECL_VISIBILITY(decl) == VISIBILITY_PROTECTED)
      GV->setVisibility(GlobalValue::ProtectedVisibility);
  }

  // Set the section for the global.
  if (TREE_CODE(decl) == VAR_DECL || TREE_CODE(decl) == CONST_DECL) {
    if (DECL_SECTION_NAME(decl)) {
      GV->setSection(TREE_STRING_POINTER(DECL_SECTION_NAME(decl)));
#ifdef LLVM_IMPLICIT_TARGET_GLOBAL_VAR_SECTION
    } else if (const char *Section = 
                LLVM_IMPLICIT_TARGET_GLOBAL_VAR_SECTION(decl)) {
      GV->setSection(Section);
#endif
    }
    
    // Set the alignment for the global if one of the following condition is met
    // 1) DECL_ALIGN_UNIT does not match alignment as per ABI specification
    // 2) DECL_ALIGN is set by user.
    if (DECL_ALIGN_UNIT(decl)) {
      unsigned TargetAlign = getTargetData().getABITypeAlignment(GV->getType()->getElementType());
      if (DECL_USER_ALIGN(decl) || TargetAlign != DECL_ALIGN_UNIT(decl))
        GV->setAlignment(DECL_ALIGN_UNIT(decl));
    }

    // Handle used decls
    if (DECL_PRESERVE_P (decl)) {
      const Type *SBP= PointerType::get(Type::Int8Ty);
      AttributeUsedGlobals.push_back(ConstantExpr::getBitCast(GV, SBP));
    }
  
    // Add annotate attributes for globals
    if (DECL_ATTRIBUTES(decl))
      AddAnnotateAttrsToGlobal(GV, decl);
  }
  
  if (TheDebugInfo) TheDebugInfo->EmitGlobalVariable(GV, decl); 
  
  timevar_pop(TV_LLVM_GLOBALS);
}
示例#14
0
文件: symtab.c 项目: lv88h/gcc
void
symtab_node::dump_base (FILE *f)
{
  static const char * const visibility_types[] = {
    "default", "protected", "hidden", "internal"
  };

  fprintf (f, "%s/%i (%s)", asm_name (), order, name ());
  dump_addr (f, " @", (void *)this);
  fprintf (f, "\n  Type: %s", symtab_type_names[type]);

  if (definition)
    fprintf (f, " definition");
  if (analyzed)
    fprintf (f, " analyzed");
  if (alias)
    fprintf (f, " alias");
  if (weakref)
    fprintf (f, " weakref");
  if (cpp_implicit_alias)
    fprintf (f, " cpp_implicit_alias");
  if (alias_target)
    fprintf (f, " target:%s",
	     DECL_P (alias_target)
	     ? IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME
				     (alias_target))
	     : IDENTIFIER_POINTER (alias_target));
  if (body_removed)
    fprintf (f, "\n  Body removed by symtab_remove_unreachable_nodes");
  fprintf (f, "\n  Visibility:");
  if (in_other_partition)
    fprintf (f, " in_other_partition");
  if (used_from_other_partition)
    fprintf (f, " used_from_other_partition");
  if (force_output)
    fprintf (f, " force_output");
  if (forced_by_abi)
    fprintf (f, " forced_by_abi");
  if (externally_visible)
    fprintf (f, " externally_visible");
  if (resolution != LDPR_UNKNOWN)
    fprintf (f, " %s",
 	     ld_plugin_symbol_resolution_names[(int)resolution]);
  if (TREE_ASM_WRITTEN (decl))
    fprintf (f, " asm_written");
  if (DECL_EXTERNAL (decl))
    fprintf (f, " external");
  if (TREE_PUBLIC (decl))
    fprintf (f, " public");
  if (DECL_COMMON (decl))
    fprintf (f, " common");
  if (DECL_WEAK (decl))
    fprintf (f, " weak");
  if (DECL_DLLIMPORT_P (decl))
    fprintf (f, " dll_import");
  if (DECL_COMDAT (decl))
    fprintf (f, " comdat");
  if (get_comdat_group ())
    fprintf (f, " comdat_group:%s",
	     IDENTIFIER_POINTER (get_comdat_group_id ()));
  if (DECL_ONE_ONLY (decl))
    fprintf (f, " one_only");
  if (get_section ())
    fprintf (f, " section:%s",
	     get_section ());
  if (implicit_section)
    fprintf (f," (implicit_section)");
  if (DECL_VISIBILITY_SPECIFIED (decl))
    fprintf (f, " visibility_specified");
  if (DECL_VISIBILITY (decl))
    fprintf (f, " visibility:%s",
	     visibility_types [DECL_VISIBILITY (decl)]);
  if (DECL_VIRTUAL_P (decl))
    fprintf (f, " virtual");
  if (DECL_ARTIFICIAL (decl))
    fprintf (f, " artificial");
  if (TREE_CODE (decl) == FUNCTION_DECL)
    {
      if (DECL_STATIC_CONSTRUCTOR (decl))
	fprintf (f, " constructor");
      if (DECL_STATIC_DESTRUCTOR (decl))
	fprintf (f, " destructor");
    }
  fprintf (f, "\n");
  
  if (same_comdat_group)
    fprintf (f, "  Same comdat group as: %s/%i\n",
	     same_comdat_group->asm_name (),
	     same_comdat_group->order);
  if (next_sharing_asm_name)
    fprintf (f, "  next sharing asm name: %i\n",
	     next_sharing_asm_name->order);
  if (previous_sharing_asm_name)
    fprintf (f, "  previous sharing asm name: %i\n",
	     previous_sharing_asm_name->order);

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

  fprintf (f, "  References: ");
  dump_references (f);
  fprintf (f, "  Referring: ");
  dump_referring (f);
  if (lto_file_data)
    fprintf (f, "  Read from file: %s\n",
	     lto_file_data->file_name);
}
示例#15
0
bool
maybe_clone_body (tree fn)
{
  tree clone;
  bool first = true;
/* APPLE LOCAL begin ARM structor thunks */
  tree clone_to_call;
  struct clone_info info;
/* APPLE LOCAL end ARM structor thunks */

  /* We only clone constructors and destructors.  */
  if (!DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn)
      && !DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn))
    return 0;

  /* Emit the DWARF1 abstract instance.  */
  (*debug_hooks->deferred_inline_function) (fn);

/* APPLE LOCAL begin ARM structor thunks */
  /* Figure out whether we can use the 'thunk' implementation,
     and if so on which clones. */
  info.next_clone = 0;
  info.which_thunks_ok = compute_use_thunks (fn);
/* APPLE LOCAL end ARM structor thunks */

  /* We know that any clones immediately follow FN in the TYPE_METHODS
     list.  */
  push_to_top_level ();
  FOR_EACH_CLONE (clone, fn)
    {
      tree parm;
      tree clone_parm;
      int parmno;
      splay_tree decl_map;

      /* Update CLONE's source position information to match FN's.  */
      DECL_SOURCE_LOCATION (clone) = DECL_SOURCE_LOCATION (fn);
      DECL_INLINE (clone) = DECL_INLINE (fn);
      DECL_DECLARED_INLINE_P (clone) = DECL_DECLARED_INLINE_P (fn);
      /* LLVM LOCAL begin inlinehint attribute */
      DECL_EXPLICIT_INLINE_P (clone) = DECL_EXPLICIT_INLINE_P (fn);
      /* LLVM LOCAL end inlinehint attribute */
      DECL_COMDAT (clone) = DECL_COMDAT (fn);
      DECL_WEAK (clone) = DECL_WEAK (fn);
      DECL_ONE_ONLY (clone) = DECL_ONE_ONLY (fn);
      DECL_SECTION_NAME (clone) = DECL_SECTION_NAME (fn);
      DECL_USE_TEMPLATE (clone) = DECL_USE_TEMPLATE (fn);
      DECL_EXTERNAL (clone) = DECL_EXTERNAL (fn);
      DECL_INTERFACE_KNOWN (clone) = DECL_INTERFACE_KNOWN (fn);
      DECL_NOT_REALLY_EXTERN (clone) = DECL_NOT_REALLY_EXTERN (fn);
      TREE_PUBLIC (clone) = TREE_PUBLIC (fn);
      DECL_VISIBILITY (clone) = DECL_VISIBILITY (fn);
      DECL_VISIBILITY_SPECIFIED (clone) = DECL_VISIBILITY_SPECIFIED (fn);

      /* Adjust the parameter names and locations.  */
      parm = DECL_ARGUMENTS (fn);
      clone_parm = DECL_ARGUMENTS (clone);
      /* Update the `this' parameter, which is always first.  */
      update_cloned_parm (parm, clone_parm, first);
      parm = TREE_CHAIN (parm);
      clone_parm = TREE_CHAIN (clone_parm);
      if (DECL_HAS_IN_CHARGE_PARM_P (fn))
	parm = TREE_CHAIN (parm);
      if (DECL_HAS_VTT_PARM_P (fn))
	parm = TREE_CHAIN (parm);
      if (DECL_HAS_VTT_PARM_P (clone))
	clone_parm = TREE_CHAIN (clone_parm);
      for (; parm;
	   parm = TREE_CHAIN (parm), clone_parm = TREE_CHAIN (clone_parm))
	/* Update this parameter.  */
	update_cloned_parm (parm, clone_parm, first);

      /* Start processing the function.  */
      start_preparsed_function (clone, NULL_TREE, SF_PRE_PARSED);

      /* Remap the parameters.  */
      decl_map = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
      for (parmno = 0,
	     parm = DECL_ARGUMENTS (fn),
	     clone_parm = DECL_ARGUMENTS (clone);
	   parm;
	   ++parmno,
	     parm = TREE_CHAIN (parm))
	{
	  /* Map the in-charge parameter to an appropriate constant.  */
	  if (DECL_HAS_IN_CHARGE_PARM_P (fn) && parmno == 1)
	    {
	      tree in_charge;
	      in_charge = in_charge_arg_for_name (DECL_NAME (clone));
	      splay_tree_insert (decl_map,
				 (splay_tree_key) parm,
				 (splay_tree_value) in_charge);
	      /* APPLE LOCAL ARM structor thunks */
	      info.in_charge_value [info.next_clone] = in_charge;
	    }
	  else if (DECL_ARTIFICIAL (parm)
		   && DECL_NAME (parm) == vtt_parm_identifier)
	    {
	      /* For a subobject constructor or destructor, the next
		 argument is the VTT parameter.  Remap the VTT_PARM
		 from the CLONE to this parameter.  */
	      if (DECL_HAS_VTT_PARM_P (clone))
		{
		  DECL_ABSTRACT_ORIGIN (clone_parm) = parm;
		  splay_tree_insert (decl_map,
				     (splay_tree_key) parm,
				     (splay_tree_value) clone_parm);
		  clone_parm = TREE_CHAIN (clone_parm);
		}
	      /* Otherwise, map the VTT parameter to `NULL'.  */
	      else
		{
		  splay_tree_insert (decl_map,
				     (splay_tree_key) parm,
				     (splay_tree_value) null_pointer_node);
		}
	    }
	  /* Map other parameters to their equivalents in the cloned
	     function.  */
	  else
	    {
	      splay_tree_insert (decl_map,
				 (splay_tree_key) parm,
				 (splay_tree_value) clone_parm);
	      clone_parm = TREE_CHAIN (clone_parm);
	    }
	}

      if (targetm.cxx.cdtor_returns_this ())
	{
	  parm = DECL_RESULT (fn);
	  clone_parm = DECL_RESULT (clone);
	  splay_tree_insert (decl_map, (splay_tree_key) parm,
			     (splay_tree_value) clone_parm);
	}
      /* APPLE LOCAL begin ARM structor thunks */
      clone_to_call = find_earlier_clone (&info);
      if (clone_to_call)
	/* Bodies are identical; replace later one with call to an
	   earlier one. */
	thunk_body (clone, fn, clone_to_call);
      else
	/* Clone the body.  */
	clone_body (clone, fn, decl_map);
      /* APPLE LOCAL end ARM structor thunks */

      /* The clone can throw iff the original function can throw.  */
      cp_function_chain->can_throw = !TREE_NOTHROW (fn);

      /* Now, expand this function into RTL, if appropriate.  */
      finish_function (0);
      BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn);
      expand_or_defer_fn (clone);
      first = false;
      /* APPLE LOCAL begin ARM structor thunks */
      info.clones [info.next_clone] = clone;
      info.next_clone++;
      /* APPLE LOCAL end ARM structor thunks */
    }
示例#16
0
文件: symtab.c 项目: Roffi/gcc
DEBUG_FUNCTION bool
verify_symtab_base (symtab_node node)
{
  bool error_found = false;
  symtab_node hashed_node;

  if (is_a <cgraph_node> (node))
    {
      if (TREE_CODE (node->symbol.decl) != FUNCTION_DECL)
	{
          error ("function symbol is not function");
          error_found = true;
	}
    }
  else if (is_a <varpool_node> (node))
    {
      if (TREE_CODE (node->symbol.decl) != VAR_DECL)
	{
          error ("variable symbol is not variable");
          error_found = true;
	}
    }
  else
    {
      error ("node has unknown type");
      error_found = true;
    }
   
  if (cgraph_state != CGRAPH_LTO_STREAMING)
    {
      hashed_node = symtab_get_node (node->symbol.decl);
      if (!hashed_node)
	{
	  error ("node not found in symtab decl hashtable");
	  error_found = true;
	}
      if (hashed_node != node
	  && (!is_a <cgraph_node> (node)
	      || !dyn_cast <cgraph_node> (node)->clone_of
	      || dyn_cast <cgraph_node> (node)->clone_of->symbol.decl
		 != node->symbol.decl))
	{
	  error ("node differs from symtab decl hashtable");
	  error_found = true;
	}
    }
  if (assembler_name_hash)
    {
      hashed_node = symtab_node_for_asm (DECL_ASSEMBLER_NAME (node->symbol.decl));
      if (hashed_node && hashed_node->symbol.previous_sharing_asm_name)
	{
          error ("assembler name hash list corrupted");
          error_found = true;
	}
      while (hashed_node)
	{
	  if (hashed_node == node)
	    break;
	  hashed_node = hashed_node->symbol.next_sharing_asm_name;
	}
      if (!hashed_node
          && !(is_a <varpool_node> (node)
	       || DECL_HARD_REGISTER (node->symbol.decl)))
	{
          error ("node not found in symtab assembler name hash");
          error_found = true;
	}
    }
  if (node->symbol.previous_sharing_asm_name
      && node->symbol.previous_sharing_asm_name->symbol.next_sharing_asm_name != node)
    {
      error ("double linked list of assembler names corrupted");
      error_found = true;
    }
  if (node->symbol.analyzed && !node->symbol.definition)
    {
      error ("node is analyzed byt it is not a definition");
      error_found = true;
    }
  if (node->symbol.cpp_implicit_alias && !node->symbol.alias)
    {
      error ("node is alias but not implicit alias");
      error_found = true;
    }
  if (node->symbol.alias && !node->symbol.definition
      && !node->symbol.weakref)
    {
      error ("node is alias but not definition");
      error_found = true;
    }
  if (node->symbol.weakref && !node->symbol.alias)
    {
      error ("node is weakref but not an alias");
      error_found = true;
    }
  if (node->symbol.same_comdat_group)
    {
      symtab_node n = node->symbol.same_comdat_group;

      if (!DECL_ONE_ONLY (n->symbol.decl))
	{
	  error ("non-DECL_ONE_ONLY node in a same_comdat_group list");
	  error_found = true;
	}
      if (n->symbol.type != node->symbol.type)
	{
	  error ("mixing different types of symbol in same comdat groups is not supported");
	  error_found = true;
	}
      if (n == node)
	{
	  error ("node is alone in a comdat group");
	  error_found = true;
	}
      do
	{
	  if (!n->symbol.same_comdat_group)
	    {
	      error ("same_comdat_group is not a circular list");
	      error_found = true;
	      break;
	    }
	  n = n->symbol.same_comdat_group;
	}
      while (n != node);
    }
  return error_found;
}
示例#17
0
文件: method.c 项目: asdlei00/freebsd
void
use_thunk (tree thunk_fndecl, bool emit_p)
{
    tree a, t, function, alias;
    tree virtual_offset;
    HOST_WIDE_INT fixed_offset, virtual_value;
    bool this_adjusting = DECL_THIS_THUNK_P (thunk_fndecl);

    /* We should have called finish_thunk to give it a name.  */
    gcc_assert (DECL_NAME (thunk_fndecl));

    /* We should never be using an alias, always refer to the
       aliased thunk.  */
    gcc_assert (!THUNK_ALIAS (thunk_fndecl));

    if (TREE_ASM_WRITTEN (thunk_fndecl))
        return;

    function = THUNK_TARGET (thunk_fndecl);
    if (DECL_RESULT (thunk_fndecl))
        /* We already turned this thunk into an ordinary function.
           There's no need to process this thunk again.  */
        return;

    if (DECL_THUNK_P (function))
        /* The target is itself a thunk, process it now.  */
        use_thunk (function, emit_p);

    /* Thunks are always addressable; they only appear in vtables.  */
    TREE_ADDRESSABLE (thunk_fndecl) = 1;

    /* Figure out what function is being thunked to.  It's referenced in
       this translation unit.  */
    TREE_ADDRESSABLE (function) = 1;
    mark_used (function);
    if (!emit_p)
        return;

    if (TARGET_USE_LOCAL_THUNK_ALIAS_P (function))
        alias = make_alias_for_thunk (function);
    else
        alias = function;

    fixed_offset = THUNK_FIXED_OFFSET (thunk_fndecl);
    virtual_offset = THUNK_VIRTUAL_OFFSET (thunk_fndecl);

    if (virtual_offset)
    {
        if (!this_adjusting)
            virtual_offset = BINFO_VPTR_FIELD (virtual_offset);
        virtual_value = tree_low_cst (virtual_offset, /*pos=*/0);
        gcc_assert (virtual_value);
    }
    else
        virtual_value = 0;

    /* And, if we need to emit the thunk, it's used.  */
    mark_used (thunk_fndecl);
    /* This thunk is actually defined.  */
    DECL_EXTERNAL (thunk_fndecl) = 0;
    /* The linkage of the function may have changed.  FIXME in linkage
       rewrite.  */
    TREE_PUBLIC (thunk_fndecl) = TREE_PUBLIC (function);
    DECL_VISIBILITY (thunk_fndecl) = DECL_VISIBILITY (function);
    DECL_VISIBILITY_SPECIFIED (thunk_fndecl)
        = DECL_VISIBILITY_SPECIFIED (function);
    if (DECL_ONE_ONLY (function))
        make_decl_one_only (thunk_fndecl);

    if (flag_syntax_only)
    {
        TREE_ASM_WRITTEN (thunk_fndecl) = 1;
        return;
    }

    push_to_top_level ();

    if (TARGET_USE_LOCAL_THUNK_ALIAS_P (function)
            && targetm.have_named_sections)
    {
        resolve_unique_section (function, 0, flag_function_sections);

        if (DECL_SECTION_NAME (function) != NULL && DECL_ONE_ONLY (function))
        {
            resolve_unique_section (thunk_fndecl, 0, flag_function_sections);

            /* Output the thunk into the same section as function.  */
            DECL_SECTION_NAME (thunk_fndecl) = DECL_SECTION_NAME (function);
        }
    }

    /* The back-end expects DECL_INITIAL to contain a BLOCK, so we
       create one.  */
    DECL_INITIAL (thunk_fndecl) = make_node (BLOCK);

    /* Set up cloned argument trees for the thunk.  */
    t = NULL_TREE;
    for (a = DECL_ARGUMENTS (function); a; a = TREE_CHAIN (a))
    {
        tree x = copy_node (a);
        TREE_CHAIN (x) = t;
        DECL_CONTEXT (x) = thunk_fndecl;
        SET_DECL_RTL (x, NULL_RTX);
        DECL_HAS_VALUE_EXPR_P (x) = 0;
        t = x;
    }
    a = nreverse (t);
    DECL_ARGUMENTS (thunk_fndecl) = a;
    BLOCK_VARS (DECL_INITIAL (thunk_fndecl)) = a;

    if (this_adjusting
            && targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset,
                    virtual_value, alias))
    {
        const char *fnname;
        current_function_decl = thunk_fndecl;
        DECL_RESULT (thunk_fndecl)
            = build_decl (RESULT_DECL, 0, integer_type_node);
        fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0);
        init_function_start (thunk_fndecl);
        current_function_is_thunk = 1;
        assemble_start_function (thunk_fndecl, fnname);

        targetm.asm_out.output_mi_thunk (asm_out_file, thunk_fndecl,
                                         fixed_offset, virtual_value, alias);

        assemble_end_function (thunk_fndecl, fnname);
        init_insn_lengths ();
        current_function_decl = 0;
        cfun = 0;
        TREE_ASM_WRITTEN (thunk_fndecl) = 1;
    }
    else
    {
        /* If this is a covariant thunk, or we don't have the necessary
        code for efficient thunks, generate a thunk function that
         just makes a call to the real function.  Unfortunately, this
         doesn't work for varargs.  */

        if (varargs_function_p (function))
            error ("generic thunk code fails for method %q#D which uses %<...%>",
                   function);

        DECL_RESULT (thunk_fndecl) = NULL_TREE;

        start_preparsed_function (thunk_fndecl, NULL_TREE, SF_PRE_PARSED);
        /* We don't bother with a body block for thunks.  */

        /* There's no need to check accessibility inside the thunk body.  */
        push_deferring_access_checks (dk_no_check);

        t = a;
        if (this_adjusting)
            t = thunk_adjust (t, /*this_adjusting=*/1,
                              fixed_offset, virtual_offset);

        /* Build up the call to the real function.  */
        t = tree_cons (NULL_TREE, t, NULL_TREE);
        for (a = TREE_CHAIN (a); a; a = TREE_CHAIN (a))
            t = tree_cons (NULL_TREE, a, t);
        t = nreverse (t);
        t = build_call (alias, t);
        CALL_FROM_THUNK_P (t) = 1;

        if (VOID_TYPE_P (TREE_TYPE (t)))
            finish_expr_stmt (t);
        else
        {
            if (!this_adjusting)
            {
                tree cond = NULL_TREE;

                if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE)
                {
                    /* If the return type is a pointer, we need to
                       protect against NULL.  We know there will be an
                       adjustment, because that's why we're emitting a
                       thunk.  */
                    t = save_expr (t);
                    cond = cp_convert (boolean_type_node, t);
                }

                t = thunk_adjust (t, /*this_adjusting=*/0,
                                  fixed_offset, virtual_offset);
                if (cond)
                    t = build3 (COND_EXPR, TREE_TYPE (t), cond, t,
                                cp_convert (TREE_TYPE (t), integer_zero_node));
            }
            if (IS_AGGR_TYPE (TREE_TYPE (t)))
                t = build_cplus_new (TREE_TYPE (t), t);
            finish_return_stmt (t);
        }

        /* Since we want to emit the thunk, we explicitly mark its name as
        referenced.  */
        mark_decl_referenced (thunk_fndecl);

        /* But we don't want debugging information about it.  */
        DECL_IGNORED_P (thunk_fndecl) = 1;

        /* Re-enable access control.  */
        pop_deferring_access_checks ();

        thunk_fndecl = finish_function (0);
        tree_lowering_passes (thunk_fndecl);
        expand_body (thunk_fndecl);
    }

    pop_from_top_level ();
}
示例#18
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;
}
示例#19
0
DEBUG_FUNCTION bool
verify_symtab_base (symtab_node *node)
{
  bool error_found = false;
  symtab_node *hashed_node;

  if (is_a <cgraph_node> (node))
    {
      if (TREE_CODE (node->decl) != FUNCTION_DECL)
	{
          error ("function symbol is not function");
          error_found = true;
	}
    }
  else if (is_a <varpool_node> (node))
    {
      if (TREE_CODE (node->decl) != VAR_DECL)
	{
          error ("variable symbol is not variable");
          error_found = true;
	}
    }
  else
    {
      error ("node has unknown type");
      error_found = true;
    }
   
  if (cgraph_state != CGRAPH_LTO_STREAMING)
    {
      hashed_node = symtab_get_node (node->decl);
      if (!hashed_node)
	{
	  error ("node not found in symtab decl hashtable");
	  error_found = true;
	}
      if (hashed_node != node
	  && (!is_a <cgraph_node> (node)
	      || !dyn_cast <cgraph_node> (node)->clone_of
	      || dyn_cast <cgraph_node> (node)->clone_of->decl
		 != node->decl))
	{
	  error ("node differs from symtab decl hashtable");
	  error_found = true;
	}
    }
  if (assembler_name_hash)
    {
      hashed_node = symtab_node_for_asm (DECL_ASSEMBLER_NAME (node->decl));
      if (hashed_node && hashed_node->previous_sharing_asm_name)
	{
          error ("assembler name hash list corrupted");
          error_found = true;
	}
      while (hashed_node)
	{
	  if (hashed_node == node)
	    break;
	  hashed_node = hashed_node->next_sharing_asm_name;
	}
      if (!hashed_node
          && !(is_a <varpool_node> (node)
	       || DECL_HARD_REGISTER (node->decl)))
	{
          error ("node not found in symtab assembler name hash");
          error_found = true;
	}
    }
  if (node->previous_sharing_asm_name
      && node->previous_sharing_asm_name->next_sharing_asm_name != node)
    {
      error ("double linked list of assembler names corrupted");
      error_found = true;
    }
  if (node->analyzed && !node->definition)
    {
      error ("node is analyzed byt it is not a definition");
      error_found = true;
    }
  if (node->cpp_implicit_alias && !node->alias)
    {
      error ("node is alias but not implicit alias");
      error_found = true;
    }
  if (node->alias && !node->definition
      && !node->weakref)
    {
      error ("node is alias but not definition");
      error_found = true;
    }
  if (node->weakref && !node->alias)
    {
      error ("node is weakref but not an alias");
      error_found = true;
    }
  if (node->same_comdat_group)
    {
      symtab_node *n = node->same_comdat_group;

      if (!DECL_ONE_ONLY (n->decl))
	{
	  error ("non-DECL_ONE_ONLY node in a same_comdat_group list");
	  error_found = true;
	}
      if (n->type != node->type)
	{
	  error ("mixing different types of symbol in same comdat groups is not supported");
	  error_found = true;
	}
      if (n == node)
	{
	  error ("node is alone in a comdat group");
	  error_found = true;
	}
      do
	{
	  if (!n->same_comdat_group)
	    {
	      error ("same_comdat_group is not a circular list");
	      error_found = true;
	      break;
	    }
	  n = n->same_comdat_group;
	}
      while (n != node);
      if (symtab_comdat_local_p (node))
	{
	  struct ipa_ref_list *refs = &node->ref_list;
	  struct ipa_ref *ref;
	  for (int i = 0; ipa_ref_list_referring_iterate (refs, i, ref); ++i)
	    {
	      if (!symtab_in_same_comdat_p (ref->referring, node))
		{
		  error ("comdat-local symbol referred to by %s outside its "
			 "comdat",
			 identifier_to_locale (ref->referring->name()));
		  error_found = true;
		}
	    }
	}
    }
  return error_found;
}
示例#20
0
文件: lambda.c 项目: nguyentu1602/gcc
void
maybe_add_lambda_conv_op (tree type)
{
  bool nested = (cfun != NULL);
  bool nested_def = decl_function_context (TYPE_MAIN_DECL (type));
  tree callop = lambda_function (type);

  if (LAMBDA_EXPR_CAPTURE_LIST (CLASSTYPE_LAMBDA_EXPR (type)) != NULL_TREE)
    return;

  if (processing_template_decl)
    return;

  bool const generic_lambda_p
    = (DECL_TEMPLATE_INFO (callop)
    && DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (callop)) == callop);

  if (!generic_lambda_p && DECL_INITIAL (callop) == NULL_TREE)
    {
      /* If the op() wasn't instantiated due to errors, give up.  */
      gcc_assert (errorcount || sorrycount);
      return;
    }

  /* Non-template conversion operators are defined directly with build_call_a
     and using DIRECT_ARGVEC for arguments (including 'this').  Templates are
     deferred and the CALL is built in-place.  In the case of a deduced return
     call op, the decltype expression, DECLTYPE_CALL, used as a substitute for
     the return type is also built in-place.  The arguments of DECLTYPE_CALL in
     the return expression may differ in flags from those in the body CALL.  In
     particular, parameter pack expansions are marked PACK_EXPANSION_LOCAL_P in
     the body CALL, but not in DECLTYPE_CALL.  */

  vec<tree, va_gc> *direct_argvec = 0;
  tree decltype_call = 0, call = 0;
  tree fn_result = TREE_TYPE (TREE_TYPE (callop));

  if (generic_lambda_p)
    {
      /* Prepare the dependent member call for the static member function
	 '_FUN' and, potentially, prepare another call to be used in a decltype
	 return expression for a deduced return call op to allow for simple
	 implementation of the conversion operator.  */

      tree instance = build_nop (type, null_pointer_node);
      tree objfn = build_min (COMPONENT_REF, NULL_TREE,
			      instance, DECL_NAME (callop), NULL_TREE);
      int nargs = list_length (DECL_ARGUMENTS (callop)) - 1;

      call = prepare_op_call (objfn, nargs);
      if (type_uses_auto (fn_result))
	decltype_call = prepare_op_call (objfn, nargs);
    }
  else
    {
      direct_argvec = make_tree_vector ();
      direct_argvec->quick_push (build1 (NOP_EXPR,
					 TREE_TYPE (DECL_ARGUMENTS (callop)),
					 null_pointer_node));
    }

  /* Copy CALLOP's argument list (as per 'copy_list') as FN_ARGS in order to
     declare the static member function "_FUN" below.  For each arg append to
     DIRECT_ARGVEC (for the non-template case) or populate the pre-allocated
     call args (for the template case).  If a parameter pack is found, expand
     it, flagging it as PACK_EXPANSION_LOCAL_P for the body call.  */

  tree fn_args = NULL_TREE;
  {
    int ix = 0;
    tree src = DECL_CHAIN (DECL_ARGUMENTS (callop));
    tree tgt;

    while (src)
      {
	tree new_node = copy_node (src);

	if (!fn_args)
	  fn_args = tgt = new_node;
	else
	  {
	    TREE_CHAIN (tgt) = new_node;
	    tgt = new_node;
	  }

	mark_exp_read (tgt);

	if (generic_lambda_p)
	  {
	    if (DECL_PACK_P (tgt))
	      {
		tree a = make_pack_expansion (tgt);
		if (decltype_call)
		  CALL_EXPR_ARG (decltype_call, ix) = copy_node (a);
		PACK_EXPANSION_LOCAL_P (a) = true;
		CALL_EXPR_ARG (call, ix) = a;
	      }
	    else
	      {
		tree a = convert_from_reference (tgt);
		CALL_EXPR_ARG (call, ix) = a;
		if (decltype_call)
		  CALL_EXPR_ARG (decltype_call, ix) = copy_node (a);
	      }
	    ++ix;
	  }
	else
	  vec_safe_push (direct_argvec, tgt);

	src = TREE_CHAIN (src);
      }
  }


  if (generic_lambda_p)
    {
      if (decltype_call)
	{
	  ++processing_template_decl;
	  fn_result = finish_decltype_type
	    (decltype_call, /*id_expression_or_member_access_p=*/false,
	     tf_warning_or_error);
	  --processing_template_decl;
	}
    }
  else
    call = build_call_a (callop,
			 direct_argvec->length (),
			 direct_argvec->address ());

  CALL_FROM_THUNK_P (call) = 1;

  tree stattype = build_function_type (fn_result, FUNCTION_ARG_CHAIN (callop));

  /* First build up the conversion op.  */

  tree rettype = build_pointer_type (stattype);
  tree name = mangle_conv_op_name_for_type (rettype);
  tree thistype = cp_build_qualified_type (type, TYPE_QUAL_CONST);
  tree fntype = build_method_type_directly (thistype, rettype, void_list_node);
  tree convfn = build_lang_decl (FUNCTION_DECL, name, fntype);
  tree fn = convfn;
  DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (callop);

  if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn
      && DECL_ALIGN (fn) < 2 * BITS_PER_UNIT)
    DECL_ALIGN (fn) = 2 * BITS_PER_UNIT;

  SET_OVERLOADED_OPERATOR_CODE (fn, TYPE_EXPR);
  grokclassfn (type, fn, NO_SPECIAL);
  set_linkage_according_to_type (type, fn);
  rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof);
  DECL_IN_AGGR_P (fn) = 1;
  DECL_ARTIFICIAL (fn) = 1;
  DECL_NOT_REALLY_EXTERN (fn) = 1;
  DECL_DECLARED_INLINE_P (fn) = 1;
  DECL_ARGUMENTS (fn) = build_this_parm (fntype, TYPE_QUAL_CONST);
  if (nested_def)
    DECL_INTERFACE_KNOWN (fn) = 1;

  if (generic_lambda_p)
    fn = add_inherited_template_parms (fn, DECL_TI_TEMPLATE (callop));

  add_method (type, fn, NULL_TREE);

  /* Generic thunk code fails for varargs; we'll complain in mark_used if
     the conversion op is used.  */
  if (varargs_function_p (callop))
    {
      DECL_DELETED_FN (fn) = 1;
      return;
    }

  /* Now build up the thunk to be returned.  */

  name = get_identifier ("_FUN");
  tree statfn = build_lang_decl (FUNCTION_DECL, name, stattype);
  fn = statfn;
  DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (callop);
  if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn
      && DECL_ALIGN (fn) < 2 * BITS_PER_UNIT)
    DECL_ALIGN (fn) = 2 * BITS_PER_UNIT;
  grokclassfn (type, fn, NO_SPECIAL);
  set_linkage_according_to_type (type, fn);
  rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof);
  DECL_IN_AGGR_P (fn) = 1;
  DECL_ARTIFICIAL (fn) = 1;
  DECL_NOT_REALLY_EXTERN (fn) = 1;
  DECL_DECLARED_INLINE_P (fn) = 1;
  DECL_STATIC_FUNCTION_P (fn) = 1;
  DECL_ARGUMENTS (fn) = fn_args;
  for (tree arg = fn_args; arg; arg = DECL_CHAIN (arg))
    {
      /* Avoid duplicate -Wshadow warnings.  */
      DECL_NAME (arg) = NULL_TREE;
      DECL_CONTEXT (arg) = fn;
    }
  if (nested_def)
    DECL_INTERFACE_KNOWN (fn) = 1;

  if (generic_lambda_p)
    fn = add_inherited_template_parms (fn, DECL_TI_TEMPLATE (callop));

  add_method (type, fn, NULL_TREE);

  if (nested)
    push_function_context ();
  else
    /* Still increment function_depth so that we don't GC in the
       middle of an expression.  */
    ++function_depth;

  /* Generate the body of the thunk.  */

  start_preparsed_function (statfn, NULL_TREE,
			    SF_PRE_PARSED | SF_INCLASS_INLINE);
  if (DECL_ONE_ONLY (statfn))
    {
      /* Put the thunk in the same comdat group as the call op.  */
      cgraph_node::get_create (statfn)->add_to_same_comdat_group
	(cgraph_node::get_create (callop));
    }
  tree body = begin_function_body ();
  tree compound_stmt = begin_compound_stmt (0);
  if (!generic_lambda_p)
    {
      set_flags_from_callee (call);
      if (MAYBE_CLASS_TYPE_P (TREE_TYPE (call)))
	call = build_cplus_new (TREE_TYPE (call), call, tf_warning_or_error);
    }
  call = convert_from_reference (call);
  finish_return_stmt (call);

  finish_compound_stmt (compound_stmt);
  finish_function_body (body);

  fn = finish_function (/*inline*/2);
  if (!generic_lambda_p)
    expand_or_defer_fn (fn);

  /* Generate the body of the conversion op.  */

  start_preparsed_function (convfn, NULL_TREE,
			    SF_PRE_PARSED | SF_INCLASS_INLINE);
  body = begin_function_body ();
  compound_stmt = begin_compound_stmt (0);

  /* decl_needed_p needs to see that it's used.  */
  TREE_USED (statfn) = 1;
  finish_return_stmt (decay_conversion (statfn, tf_warning_or_error));

  finish_compound_stmt (compound_stmt);
  finish_function_body (body);

  fn = finish_function (/*inline*/2);
  if (!generic_lambda_p)
    expand_or_defer_fn (fn);

  if (nested)
    pop_function_context ();
  else
    --function_depth;
}
示例#21
0
void
use_thunk (tree thunk_fndecl, bool emit_p)
{
  tree a, t, function, alias;
  tree virtual_offset;
  HOST_WIDE_INT fixed_offset, virtual_value;
  bool this_adjusting = DECL_THIS_THUNK_P (thunk_fndecl);

  /* We should have called finish_thunk to give it a name.  */
  gcc_assert (DECL_NAME (thunk_fndecl));

  /* We should never be using an alias, always refer to the
     aliased thunk.  */
  gcc_assert (!THUNK_ALIAS (thunk_fndecl));

  if (TREE_ASM_WRITTEN (thunk_fndecl))
    return;

  function = THUNK_TARGET (thunk_fndecl);
  if (DECL_RESULT (thunk_fndecl))
    /* We already turned this thunk into an ordinary function.
       There's no need to process this thunk again.  */
    return;

  if (DECL_THUNK_P (function))
    /* The target is itself a thunk, process it now.  */
    use_thunk (function, emit_p);

  /* Thunks are always addressable; they only appear in vtables.  */
  TREE_ADDRESSABLE (thunk_fndecl) = 1;

  /* Figure out what function is being thunked to.  It's referenced in
     this translation unit.  */
  TREE_ADDRESSABLE (function) = 1;
  mark_used (function);
  if (!emit_p)
    return;

  if (0 && TARGET_USE_LOCAL_THUNK_ALIAS_P (function))
   alias = make_alias_for_thunk (function);
  else
   alias = function;

  fixed_offset = THUNK_FIXED_OFFSET (thunk_fndecl);
  virtual_offset = THUNK_VIRTUAL_OFFSET (thunk_fndecl);

  if (virtual_offset)
    {
      if (!this_adjusting)
	virtual_offset = BINFO_VPTR_FIELD (virtual_offset);
      virtual_value = tree_low_cst (virtual_offset, /*pos=*/0);
      gcc_assert (virtual_value);
    }
  else
    virtual_value = 0;

  /* And, if we need to emit the thunk, it's used.  */
  mark_used (thunk_fndecl);
  /* This thunk is actually defined.  */
  DECL_EXTERNAL (thunk_fndecl) = 0;
  /* The linkage of the function may have changed.  FIXME in linkage
     rewrite.  */
  TREE_PUBLIC (thunk_fndecl) = TREE_PUBLIC (function);
  DECL_VISIBILITY (thunk_fndecl) = DECL_VISIBILITY (function);
  DECL_VISIBILITY_SPECIFIED (thunk_fndecl)
    = DECL_VISIBILITY_SPECIFIED (function);
  if (DECL_ONE_ONLY (function) || DECL_WEAK (function))
    make_decl_one_only (thunk_fndecl, cxx_comdat_group (thunk_fndecl));

  if (flag_syntax_only)
    {
      TREE_ASM_WRITTEN (thunk_fndecl) = 1;
      return;
    }

  push_to_top_level ();

  if (TARGET_USE_LOCAL_THUNK_ALIAS_P (function)
      && targetm.have_named_sections)
    {
      resolve_unique_section (function, 0, flag_function_sections);

      if (DECL_SECTION_NAME (function) != NULL && DECL_ONE_ONLY (function))
	{
	  resolve_unique_section (thunk_fndecl, 0, flag_function_sections);

	  /* Output the thunk into the same section as function.  */
	  DECL_SECTION_NAME (thunk_fndecl) = DECL_SECTION_NAME (function);
	}
    }

  /* Set up cloned argument trees for the thunk.  */
  t = NULL_TREE;
  for (a = DECL_ARGUMENTS (function); a; a = TREE_CHAIN (a))
    {
      tree x = copy_node (a);
      TREE_CHAIN (x) = t;
      DECL_CONTEXT (x) = thunk_fndecl;
      SET_DECL_RTL (x, NULL_RTX);
      DECL_HAS_VALUE_EXPR_P (x) = 0;
      t = x;
    }
  a = nreverse (t);
  DECL_ARGUMENTS (thunk_fndecl) = a;
  TREE_ASM_WRITTEN (thunk_fndecl) = 1;
  cgraph_add_thunk (thunk_fndecl, function,
		    this_adjusting, fixed_offset, virtual_value,
		    virtual_offset, alias);

  if (!this_adjusting
      || !targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset,
					       virtual_value, alias))
    {
      /* If this is a covariant thunk, or we don't have the necessary
	 code for efficient thunks, generate a thunk function that
	 just makes a call to the real function.  Unfortunately, this
	 doesn't work for varargs.  */

      if (varargs_function_p (function))
	error ("generic thunk code fails for method %q#D which uses %<...%>",
	       function);
    }

  pop_from_top_level ();
}