X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fvarasm.c;h=cf880e83b16f08d2e9f6e00a4d8f9bd918b9f5b7;hp=2d8a6bfe81aa35ef2e7326878f12ae77ee227c18;hb=55d19f3617da01201772bfc2030ec7ab8b008734;hpb=535664e3ad516768f57ba0112323411554854745 diff --git a/gcc/varasm.c b/gcc/varasm.c index 2d8a6bfe81a..cf880e83b16 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -1,6 +1,6 @@ /* Output variables, constants and external declarations, for GNU compiler. Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, - 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. This file is part of GCC. @@ -53,6 +53,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "cgraph.h" #include "cfglayout.h" #include "basic-block.h" +#include "tree-iterator.h" #ifdef XCOFF_DEBUGGING_INFO #include "xcoffout.h" /* Needed for external data @@ -126,7 +127,6 @@ static unsigned HOST_WIDE_INT array_size_for_constructor (tree); static unsigned min_align (unsigned, unsigned); static void output_constructor (tree, unsigned HOST_WIDE_INT, unsigned int); static void globalize_decl (tree); -static void maybe_assemble_visibility (tree); #ifdef BSS_SECTION_ASM_OP #ifdef ASM_OUTPUT_BSS static void asm_output_bss (FILE *, tree, const char *, @@ -200,6 +200,242 @@ static GTY(()) int anchor_labelno; /* A pool of constants that can be shared between functions. */ static GTY(()) struct rtx_constant_pool *shared_constant_pool; +/* TLS emulation. */ + +static GTY ((if_marked ("tree_map_marked_p"), param_is (struct tree_map))) + htab_t emutls_htab; +static GTY (()) tree emutls_object_type; + +#ifndef NO_DOT_IN_LABEL +# define EMUTLS_VAR_PREFIX "__emutls_v." +# define EMUTLS_TMPL_PREFIX "__emutls_t." +#elif !defined NO_DOLLAR_IN_LABEL +# define EMUTLS_VAR_PREFIX "__emutls_v$" +# define EMUTLS_TMPL_PREFIX "__emutls_t$" +#else +# define EMUTLS_VAR_PREFIX "__emutls_v_" +# define EMUTLS_TMPL_PREFIX "__emutls_t_" +#endif + +/* Create an identifier for the struct __emutls_object, given an identifier + of the DECL_ASSEMBLY_NAME of the original object. */ + +static tree +get_emutls_object_name (tree name) +{ + char *toname = alloca (strlen (IDENTIFIER_POINTER (name)) + + sizeof (EMUTLS_VAR_PREFIX)); + strcpy (toname, EMUTLS_VAR_PREFIX); + strcpy (toname + sizeof (EMUTLS_VAR_PREFIX) - 1, IDENTIFIER_POINTER (name)); + + return get_identifier (toname); +} + +/* Create the structure for struct __emutls_object. This should match the + structure at the top of emutls.c, modulo the union there. */ + +static tree +get_emutls_object_type (void) +{ + tree type, type_name, field, next_field, word_type_node; + + type = emutls_object_type; + if (type) + return type; + + emutls_object_type = type = lang_hooks.types.make_type (RECORD_TYPE); + type_name = get_identifier ("__emutls_object"); + type_name = build_decl (TYPE_DECL, type_name, type); + TYPE_NAME (type) = type_name; + + field = build_decl (FIELD_DECL, get_identifier ("__templ"), ptr_type_node); + DECL_CONTEXT (field) = type; + next_field = field; + + field = build_decl (FIELD_DECL, get_identifier ("__offset"), ptr_type_node); + DECL_CONTEXT (field) = type; + TREE_CHAIN (field) = next_field; + next_field = field; + + word_type_node = lang_hooks.types.type_for_mode (word_mode, 1); + field = build_decl (FIELD_DECL, get_identifier ("__align"), word_type_node); + DECL_CONTEXT (field) = type; + TREE_CHAIN (field) = next_field; + next_field = field; + + field = build_decl (FIELD_DECL, get_identifier ("__size"), word_type_node); + DECL_CONTEXT (field) = type; + TREE_CHAIN (field) = next_field; + + TYPE_FIELDS (type) = field; + layout_type (type); + + return type; +} + +/* Create a read-only variable like DECL, with the same DECL_INITIAL. + This will be used for initializing the emulated tls data area. */ + +static tree +get_emutls_init_templ_addr (tree decl) +{ + tree name, to; + char *toname; + + if (!DECL_INITIAL (decl)) + return null_pointer_node; + + name = DECL_ASSEMBLER_NAME (decl); + toname = alloca (strlen (IDENTIFIER_POINTER (name)) + + sizeof (EMUTLS_TMPL_PREFIX)); + strcpy (toname, EMUTLS_TMPL_PREFIX); + strcpy (toname + sizeof (EMUTLS_TMPL_PREFIX) - 1, IDENTIFIER_POINTER (name)); + name = get_identifier (toname); + + to = build_decl (VAR_DECL, name, TREE_TYPE (decl)); + SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to)); + + DECL_ARTIFICIAL (to) = 1; + TREE_USED (to) = TREE_USED (decl); + TREE_READONLY (to) = 1; + DECL_IGNORED_P (to) = 1; + DECL_CONTEXT (to) = DECL_CONTEXT (decl); + DECL_WEAK (to) = DECL_WEAK (decl); + if (DECL_ONE_ONLY (decl)) + { + make_decl_one_only (to); + TREE_STATIC (to) = TREE_STATIC (decl); + TREE_PUBLIC (to) = TREE_PUBLIC (decl); + DECL_VISIBILITY (to) = DECL_VISIBILITY (decl); + } + else + TREE_STATIC (to) = 1; + + DECL_INITIAL (to) = DECL_INITIAL (decl); + DECL_INITIAL (decl) = NULL; + + varpool_finalize_decl (to); + return build_fold_addr_expr (to); +} + +/* When emulating tls, we use a control structure for use by the runtime. + Create and return this structure. */ + +tree +emutls_decl (tree decl) +{ + tree name, to; + struct tree_map *h, in; + void **loc; + + if (targetm.have_tls || decl == NULL || decl == error_mark_node + || TREE_CODE (decl) != VAR_DECL || ! DECL_THREAD_LOCAL_P (decl)) + return decl; + + /* Look up the object in the hash; return the control structure if + it has already been created. */ + if (! emutls_htab) + emutls_htab = htab_create_ggc (512, tree_map_hash, tree_map_eq, 0); + + name = DECL_ASSEMBLER_NAME (decl); + + /* Note that we use the hash of the decl's name, rather than a hash + of the decl's pointer. In emutls_finish we iterate through the + hash table, and we want this traversal to be predictable. */ + in.hash = htab_hash_string (IDENTIFIER_POINTER (name)); + in.base.from = decl; + loc = htab_find_slot_with_hash (emutls_htab, &in, in.hash, INSERT); + h = *loc; + if (h != NULL) + to = h->to; + else + { + to = build_decl (VAR_DECL, get_emutls_object_name (name), + get_emutls_object_type ()); + + h = ggc_alloc (sizeof (struct tree_map)); + h->hash = in.hash; + h->base.from = decl; + h->to = to; + *(struct tree_map **) loc = h; + + DECL_ARTIFICIAL (to) = 1; + DECL_IGNORED_P (to) = 1; + TREE_READONLY (to) = 0; + + SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to)); + if (DECL_ONE_ONLY (decl)) + make_decl_one_only (to); + DECL_CONTEXT (to) = DECL_CONTEXT (decl); + } + + /* Note that these fields may need to be updated from time to time from + the original decl. Consider: + extern __thread int i; + int foo() { return i; } + __thread int i = 1; + in which I goes from external to locally defined and initialized. */ + + TREE_STATIC (to) = TREE_STATIC (decl); + TREE_USED (to) = TREE_USED (decl); + TREE_PUBLIC (to) = TREE_PUBLIC (decl); + DECL_EXTERNAL (to) = DECL_EXTERNAL (decl); + DECL_COMMON (to) = DECL_COMMON (decl); + DECL_WEAK (to) = DECL_WEAK (decl); + DECL_VISIBILITY (to) = DECL_VISIBILITY (decl); + + return to; +} + +static int +emutls_common_1 (void **loc, void *xstmts) +{ + struct tree_map *h = *(struct tree_map **) loc; + tree args, x, *pstmts = (tree *) xstmts; + tree word_type_node; + + if (! DECL_COMMON (h->base.from) + || (DECL_INITIAL (h->base.from) + && DECL_INITIAL (h->base.from) != error_mark_node)) + return 1; + + word_type_node = lang_hooks.types.type_for_mode (word_mode, 1); + + /* The idea was to call get_emutls_init_templ_addr here, but if we + do this and there is an initializer, -fanchor_section loses, + because it would be too late to ensure the template is + output. */ + x = null_pointer_node; + args = tree_cons (NULL, x, NULL); + x = build_int_cst (word_type_node, DECL_ALIGN_UNIT (h->base.from)); + args = tree_cons (NULL, x, args); + x = fold_convert (word_type_node, DECL_SIZE_UNIT (h->base.from)); + args = tree_cons (NULL, x, args); + x = build_fold_addr_expr (h->to); + args = tree_cons (NULL, x, args); + + x = built_in_decls[BUILT_IN_EMUTLS_REGISTER_COMMON]; + x = build_function_call_expr (x, args); + + append_to_statement_list (x, pstmts); + return 1; +} + +void +emutls_finish (void) +{ + tree body = NULL_TREE; + + if (emutls_htab == NULL) + return; + + htab_traverse_noresize (emutls_htab, emutls_common_1, &body); + if (body == NULL_TREE) + return; + + cgraph_build_static_cdtor ('I', body, DEFAULT_INIT_PRIORITY); +} + /* Helper routines for maintaining section_htab. */ static int @@ -490,7 +726,8 @@ asm_output_bss (FILE *file, tree decl ATTRIBUTE_UNUSED, unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED, unsigned HOST_WIDE_INT rounded) { - targetm.asm_out.globalize_label (file, name); + gcc_assert (strcmp (XSTR (XEXP (DECL_RTL (decl), 0), 0), name) == 0); + targetm.asm_out.globalize_decl_name (file, decl); switch_to_section (bss_section); #ifdef ASM_DECLARE_OBJECT_NAME last_assemble_variable_decl = decl; @@ -655,16 +892,20 @@ mergeable_string_section (tree decl ATTRIBUTE_UNUSED, unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED, unsigned int flags ATTRIBUTE_UNUSED) { + HOST_WIDE_INT len; + if (HAVE_GAS_SHF_MERGE && flag_merge_constants && TREE_CODE (decl) == STRING_CST && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE && align <= 256 - && TREE_STRING_LENGTH (decl) >= int_size_in_bytes (TREE_TYPE (decl))) + && (len = int_size_in_bytes (TREE_TYPE (decl))) > 0 + && TREE_STRING_LENGTH (decl) >= len) { enum machine_mode mode; unsigned int modesize; const char *str; - int i, j, len, unit; + HOST_WIDE_INT i; + int j, unit; char name[30]; mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (decl))); @@ -676,7 +917,6 @@ mergeable_string_section (tree decl ATTRIBUTE_UNUSED, align = modesize; str = TREE_STRING_POINTER (decl); - len = TREE_STRING_LENGTH (decl); unit = GET_MODE_SIZE (mode); /* Check for embedded NUL characters. */ @@ -828,6 +1068,48 @@ bss_initializer_p (tree decl) && initializer_zerop (DECL_INITIAL (decl)))); } +/* Compute the alignment of variable specified by DECL. + DONT_OUTPUT_DATA is from assemble_variable. */ + +void +align_variable (tree decl, bool dont_output_data) +{ + unsigned int align = DECL_ALIGN (decl); + + /* In the case for initialing an array whose length isn't specified, + where we have not yet been able to do the layout, + figure out the proper alignment now. */ + if (dont_output_data && DECL_SIZE (decl) == 0 + && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) + align = MAX (align, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl)))); + + /* Some object file formats have a maximum alignment which they support. + In particular, a.out format supports a maximum alignment of 4. */ + if (align > MAX_OFILE_ALIGNMENT) + { + warning (0, "alignment of %q+D is greater than maximum object " + "file alignment. Using %d", decl, + MAX_OFILE_ALIGNMENT/BITS_PER_UNIT); + align = MAX_OFILE_ALIGNMENT; + } + + /* On some machines, it is good to increase alignment sometimes. */ + if (! DECL_USER_ALIGN (decl)) + { +#ifdef DATA_ALIGNMENT + align = DATA_ALIGNMENT (TREE_TYPE (decl), align); +#endif +#ifdef CONSTANT_ALIGNMENT + if (DECL_INITIAL (decl) != 0 && DECL_INITIAL (decl) != error_mark_node) + align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl), align); +#endif + } + + /* Reset the alignment in case we have made it tighter, so we can benefit + from it in get_pointer_alignment. */ + DECL_ALIGN (decl) = align; +} + /* Return the section into which the given VAR_DECL or CONST_DECL should be placed. PREFER_NOSWITCH_P is true if a noswitch section should be used wherever possible. */ @@ -899,6 +1181,8 @@ get_block_for_decl (tree decl) /* Find out which section should contain DECL. We cannot put it into an object block if it requires a standalone definition. */ + if (TREE_CODE (decl) == VAR_DECL) + align_variable (decl, 0); sect = get_variable_section (decl, true); if (SECTION_STYLE (sect) == SECTION_NOSWITCH) return NULL; @@ -934,6 +1218,10 @@ use_blocks_for_decl_p (tree decl) if (DECL_INITIAL (decl) == decl) return false; + /* If this decl is an alias, then we don't want to emit a definition. */ + if (lookup_attribute ("alias", DECL_ATTRIBUTES (decl))) + return false; + return true; } @@ -1115,17 +1403,6 @@ make_decl_rtl (tree decl) if (flag_mudflap && TREE_CODE (decl) == VAR_DECL) mudflap_enqueue_decl (decl); } - -/* Make the rtl for variable VAR be volatile. - Use this only for static variables. */ - -void -make_var_volatile (tree var) -{ - gcc_assert (MEM_P (DECL_RTL (var))); - - MEM_VOLATILE_P (DECL_RTL (var)) = 1; -} /* Output a string of literal assembler code for an `asm' keyword used between functions. */ @@ -1160,26 +1437,44 @@ default_stabs_asm_out_destructor (rtx symbol ATTRIBUTE_UNUSED, #endif } -void -default_named_section_asm_out_destructor (rtx symbol, int priority) +/* Write the address of the entity given by SYMBOL to SEC. */ +void +assemble_addr_to_section (rtx symbol, section *sec) +{ + switch_to_section (sec); + assemble_align (POINTER_SIZE); + assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1); +} + +/* Return the numbered .ctors.N (if CONSTRUCTOR_P) or .dtors.N (if + not) section for PRIORITY. */ +section * +get_cdtor_priority_section (int priority, bool constructor_p) { - const char *section = ".dtors"; char buf[16]; /* ??? This only works reliably with the GNU linker. */ + sprintf (buf, "%s.%.5u", + constructor_p ? ".ctors" : ".dtors", + /* Invert the numbering so the linker puts us in the proper + order; constructors are run from right to left, and the + linker sorts in increasing order. */ + MAX_INIT_PRIORITY - priority); + return get_section (buf, SECTION_WRITE, NULL); +} + +void +default_named_section_asm_out_destructor (rtx symbol, int priority) +{ + section *sec; + if (priority != DEFAULT_INIT_PRIORITY) - { - sprintf (buf, ".dtors.%.5u", - /* Invert the numbering so the linker puts us in the proper - order; constructors are run from right to left, and the - linker sorts in increasing order. */ - MAX_INIT_PRIORITY - priority); - section = buf; - } + sec = get_cdtor_priority_section (priority, + /*constructor_p=*/false); + else + sec = get_section (".dtors", SECTION_WRITE, NULL); - switch_to_section (get_section (section, SECTION_WRITE, NULL)); - assemble_align (POINTER_SIZE); - assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1); + assemble_addr_to_section (symbol, sec); } #ifdef DTORS_SECTION_ASM_OP @@ -1187,9 +1482,7 @@ void default_dtor_section_asm_out_destructor (rtx symbol, int priority ATTRIBUTE_UNUSED) { - switch_to_section (dtors_section); - assemble_align (POINTER_SIZE); - assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1); + assemble_addr_to_section (symbol, dtors_section); } #endif @@ -1213,23 +1506,15 @@ default_stabs_asm_out_constructor (rtx symbol ATTRIBUTE_UNUSED, void default_named_section_asm_out_constructor (rtx symbol, int priority) { - const char *section = ".ctors"; - char buf[16]; + section *sec; - /* ??? This only works reliably with the GNU linker. */ if (priority != DEFAULT_INIT_PRIORITY) - { - sprintf (buf, ".ctors.%.5u", - /* Invert the numbering so the linker puts us in the proper - order; constructors are run from right to left, and the - linker sorts in increasing order. */ - MAX_INIT_PRIORITY - priority); - section = buf; - } + sec = get_cdtor_priority_section (priority, + /*constructor_p=*/true); + else + sec = get_section (".ctors", SECTION_WRITE, NULL); - switch_to_section (get_section (section, SECTION_WRITE, NULL)); - assemble_align (POINTER_SIZE); - assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1); + assemble_addr_to_section (symbol, sec); } #ifdef CTORS_SECTION_ASM_OP @@ -1237,9 +1522,7 @@ void default_ctor_section_asm_out_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED) { - switch_to_section (ctors_section); - assemble_align (POINTER_SIZE); - assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1); + assemble_addr_to_section (symbol, ctors_section); } #endif @@ -1276,7 +1559,7 @@ notice_global_symbol (tree decl) /* We win when global object is found, but it is useful to know about weak symbol as well so we can produce nicer unique names. */ - if (DECL_WEAK (decl) || DECL_ONE_ONLY (decl)) + if (DECL_WEAK (decl) || DECL_ONE_ONLY (decl) || flag_shlib) type = &weak_global_object_name; if (!*type) @@ -1683,10 +1966,62 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED, int at_end ATTRIBUTE_UNUSED, int dont_output_data) { const char *name; - unsigned int align; rtx decl_rtl, symbol; section *sect; + if (! targetm.have_tls + && TREE_CODE (decl) == VAR_DECL + && DECL_THREAD_LOCAL_P (decl)) + { + tree to = emutls_decl (decl); + + /* If this variable is defined locally, then we need to initialize the + control structure with size and alignment information. We do this + at the last moment because tentative definitions can take a locally + defined but uninitialized variable and initialize it later, which + would result in incorrect contents. */ + if (! DECL_EXTERNAL (to) + && (! DECL_COMMON (to) + || (DECL_INITIAL (decl) + && DECL_INITIAL (decl) != error_mark_node))) + { + VEC(constructor_elt,gc) *v = VEC_alloc (constructor_elt, gc, 4); + constructor_elt *elt; + tree type = TREE_TYPE (to); + tree field = TYPE_FIELDS (type); + + elt = VEC_quick_push (constructor_elt, v, NULL); + elt->index = field; + elt->value = fold_convert (TREE_TYPE (field), DECL_SIZE_UNIT (decl)); + + elt = VEC_quick_push (constructor_elt, v, NULL); + field = TREE_CHAIN (field); + elt->index = field; + elt->value = build_int_cst (TREE_TYPE (field), + DECL_ALIGN_UNIT (decl)); + + elt = VEC_quick_push (constructor_elt, v, NULL); + field = TREE_CHAIN (field); + elt->index = field; + elt->value = null_pointer_node; + + elt = VEC_quick_push (constructor_elt, v, NULL); + field = TREE_CHAIN (field); + elt->index = field; + elt->value = get_emutls_init_templ_addr (decl); + + DECL_INITIAL (to) = build_constructor (type, v); + + /* Make sure the template is marked as needed early enough. + Without this, if the variable is placed in a + section-anchored block, the template will only be marked + when it's too late. */ + record_references_in_initializer (to); + } + + decl = to; + } + if (lang_hooks.decls.prepare_assemble_variable) lang_hooks.decls.prepare_assemble_variable (decl); @@ -1764,41 +2099,8 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED, /* Compute the alignment of this data. */ - align = DECL_ALIGN (decl); - - /* In the case for initialing an array whose length isn't specified, - where we have not yet been able to do the layout, - figure out the proper alignment now. */ - if (dont_output_data && DECL_SIZE (decl) == 0 - && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) - align = MAX (align, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl)))); - - /* Some object file formats have a maximum alignment which they support. - In particular, a.out format supports a maximum alignment of 4. */ - if (align > MAX_OFILE_ALIGNMENT) - { - warning (0, "alignment of %q+D is greater than maximum object " - "file alignment. Using %d", decl, - MAX_OFILE_ALIGNMENT/BITS_PER_UNIT); - align = MAX_OFILE_ALIGNMENT; - } - - /* On some machines, it is good to increase alignment sometimes. */ - if (! DECL_USER_ALIGN (decl)) - { -#ifdef DATA_ALIGNMENT - align = DATA_ALIGNMENT (TREE_TYPE (decl), align); -#endif -#ifdef CONSTANT_ALIGNMENT - if (DECL_INITIAL (decl) != 0 && DECL_INITIAL (decl) != error_mark_node) - align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl), align); -#endif - } - - /* Reset the alignment in case we have made it tighter, so we can benefit - from it in get_pointer_alignment. */ - DECL_ALIGN (decl) = align; - set_mem_align (decl_rtl, align); + align_variable (decl, dont_output_data); + set_mem_align (decl_rtl, DECL_ALIGN (decl)); if (TREE_PUBLIC (decl)) maybe_assemble_visibility (decl); @@ -1834,7 +2136,7 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED, else { switch_to_section (sect); - if (align > BITS_PER_UNIT) + if (DECL_ALIGN (decl) > BITS_PER_UNIT) ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl))); assemble_variable_contents (decl, name, dont_output_data); } @@ -1951,11 +2253,10 @@ assemble_external (tree decl ATTRIBUTE_UNUSED) if (!DECL_P (decl) || !DECL_EXTERNAL (decl) || !TREE_PUBLIC (decl)) return; - if (flag_unit_at_a_time) - pending_assemble_externals = tree_cons (0, decl, - pending_assemble_externals); - else - assemble_external_real (decl); + /* We want to output external symbols at very last to check if they + are references or not. */ + pending_assemble_externals = tree_cons (0, decl, + pending_assemble_externals); #endif } @@ -2005,8 +2306,8 @@ mark_decl_referenced (tree decl) } else if (TREE_CODE (decl) == VAR_DECL) { - struct cgraph_varpool_node *node = cgraph_varpool_node (decl); - cgraph_varpool_mark_needed_node (node); + struct varpool_node *node = varpool_node (decl); + varpool_mark_needed_node (node); /* C++ frontend use mark_decl_references to force COMDAT variables to be output that might appear dead otherwise. */ node->force_output = true; @@ -2736,7 +3037,7 @@ copy_constant (tree exp) { tree t = lang_hooks.expand_constant (exp); - gcc_assert (t == exp); + gcc_assert (t != exp); return copy_constant (t); } } @@ -3686,6 +3987,20 @@ output_addressed_constants (tree exp) } } +/* Whether a constructor CTOR is a valid static constant initializer if all + its elements are. This used to be internal to initializer_constant_valid_p + and has been exposed to let other functions like categorize_ctor_elements + evaluate the property while walking a constructor for other purposes. */ + +bool +constructor_static_from_elts_p (tree ctor) +{ + return (TREE_CONSTANT (ctor) + && (TREE_CODE (TREE_TYPE (ctor)) == UNION_TYPE + || TREE_CODE (TREE_TYPE (ctor)) == RECORD_TYPE) + && !VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (ctor))); +} + /* Return nonzero if VALUE is a valid constant-valued expression for use in initializing a static variable; one that can be an element of a "constant" initializer. @@ -3706,10 +4021,7 @@ initializer_constant_valid_p (tree value, tree endtype) switch (TREE_CODE (value)) { case CONSTRUCTOR: - if ((TREE_CODE (TREE_TYPE (value)) == UNION_TYPE - || TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE) - && TREE_CONSTANT (value) - && !VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (value))) + if (constructor_static_from_elts_p (value)) { unsigned HOST_WIDE_INT idx; tree elt; @@ -4015,15 +4327,18 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align) if (type_size > op_size && TREE_CODE (exp) != VIEW_CONVERT_EXPR && TREE_CODE (TREE_TYPE (exp)) != UNION_TYPE) - internal_error ("no-op convert from %wd to %wd bytes in initializer", - op_size, type_size); - - exp = TREE_OPERAND (exp, 0); + /* Keep the conversion. */ + break; + else + exp = TREE_OPERAND (exp, 0); } code = TREE_CODE (TREE_TYPE (exp)); thissize = int_size_in_bytes (TREE_TYPE (exp)); + /* Give the front end another chance to expand constants. */ + exp = lang_hooks.expand_constant (exp); + /* Allow a constructor with no elements for any data type. This means to fill the space with zeros. */ if (TREE_CODE (exp) == CONSTRUCTOR @@ -4101,8 +4416,12 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align) link = TREE_VECTOR_CST_ELTS (exp); output_constant (TREE_VALUE (link), elt_size, align); + thissize = elt_size; while ((link = TREE_CHAIN (link)) != NULL) - output_constant (TREE_VALUE (link), elt_size, nalign); + { + output_constant (TREE_VALUE (link), elt_size, nalign); + thissize += elt_size; + } break; } default: @@ -4710,11 +5029,11 @@ weak_finish (void) static void globalize_decl (tree decl) { - const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0); #if defined (ASM_WEAKEN_LABEL) || defined (ASM_WEAKEN_DECL) if (DECL_WEAK (decl)) { + const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0); tree *p, t; #ifdef ASM_WEAKEN_DECL @@ -4733,25 +5052,22 @@ globalize_decl (tree decl) p = &TREE_CHAIN (t); } - /* Remove weakrefs to the same target from the pending weakref - list, for the same reason. */ - for (p = &weakref_targets; (t = *p) ; ) - { - if (DECL_ASSEMBLER_NAME (decl) - == ultimate_transparent_alias_target (&TREE_VALUE (t))) - *p = TREE_CHAIN (t); - else - p = &TREE_CHAIN (t); - } + /* Remove weakrefs to the same target from the pending weakref + list, for the same reason. */ + for (p = &weakref_targets; (t = *p) ; ) + { + if (DECL_ASSEMBLER_NAME (decl) + == ultimate_transparent_alias_target (&TREE_VALUE (t))) + *p = TREE_CHAIN (t); + else + p = &TREE_CHAIN (t); + } return; } -#elif defined(ASM_MAKE_LABEL_LINKONCE) - if (DECL_ONE_ONLY (decl)) - ASM_MAKE_LABEL_LINKONCE (asm_out_file, name); #endif - targetm.asm_out.globalize_label (asm_out_file, name); + targetm.asm_out.globalize_decl_name (asm_out_file, decl); } /* We have to be able to tell cgraph about the needed-ness of the target @@ -4777,17 +5093,17 @@ static tree find_decl_and_mark_needed (tree decl, tree target) { struct cgraph_node *fnode = NULL; - struct cgraph_varpool_node *vnode = NULL; + struct varpool_node *vnode = NULL; if (TREE_CODE (decl) == FUNCTION_DECL) { fnode = cgraph_node_for_asm (target); if (fnode == NULL) - vnode = cgraph_varpool_node_for_asm (target); + vnode = varpool_node_for_asm (target); } else { - vnode = cgraph_varpool_node_for_asm (target); + vnode = varpool_node_for_asm (target); if (vnode == NULL) fnode = cgraph_node_for_asm (target); } @@ -4805,7 +5121,7 @@ find_decl_and_mark_needed (tree decl, tree target) } else if (vnode) { - cgraph_varpool_mark_needed_node (vnode); + varpool_mark_needed_node (vnode); return vnode->decl; } else @@ -4829,6 +5145,14 @@ do_assemble_alias (tree decl, tree target) { ultimate_transparent_alias_target (&target); + if (!targetm.have_tls + && TREE_CODE (decl) == VAR_DECL + && DECL_THREAD_LOCAL_P (decl)) + { + decl = emutls_decl (decl); + target = get_emutls_object_name (target); + } + if (!TREE_SYMBOL_REFERENCED (target)) weakref_targets = tree_cons (decl, target, weakref_targets); @@ -4846,6 +5170,14 @@ do_assemble_alias (tree decl, tree target) return; } + if (!targetm.have_tls + && TREE_CODE (decl) == VAR_DECL + && DECL_THREAD_LOCAL_P (decl)) + { + decl = emutls_decl (decl); + target = get_emutls_object_name (target); + } + #ifdef ASM_OUTPUT_DEF /* Make name accessible from other files, if appropriate. */ @@ -4998,7 +5330,7 @@ assemble_alias (tree decl, tree target) if (TREE_CODE (decl) == FUNCTION_DECL) cgraph_node (decl)->alias = true; else - cgraph_varpool_node (decl)->alias = true; + varpool_node (decl)->alias = true; /* If the target has already been emitted, we don't have to queue the alias. This saves a tad o memory. */ @@ -5020,7 +5352,7 @@ void default_assemble_visibility (tree decl, int vis) { static const char * const visibility_types[] = { - NULL, "internal", "hidden", "protected" + NULL, "protected", "hidden", "internal" }; const char *name, *type; @@ -5040,13 +5372,18 @@ default_assemble_visibility (tree decl, int vis) /* A helper function to call assemble_visibility when needed for a decl. */ -static void +int maybe_assemble_visibility (tree decl) { enum symbol_visibility vis = DECL_VISIBILITY (decl); if (vis != VISIBILITY_DEFAULT) - targetm.asm_out.visibility (decl, vis); + { + targetm.asm_out.visibility (decl, vis); + return 1; + } + else + return 0; } /* Returns 1 if the target configuration supports defining public symbols @@ -5200,18 +5537,11 @@ decl_default_tls_model (tree decl) unsigned int default_section_type_flags (tree decl, const char *name, int reloc) { - return default_section_type_flags_1 (decl, name, reloc, flag_pic); -} - -unsigned int -default_section_type_flags_1 (tree decl, const char *name, int reloc, - int shlib) -{ unsigned int flags; if (decl && TREE_CODE (decl) == FUNCTION_DECL) flags = SECTION_CODE; - else if (decl && decl_readonly_section_1 (decl, reloc, shlib)) + else if (decl && decl_readonly_section (decl, reloc)) flags = 0; else if (current_function_decl && cfun @@ -5411,7 +5741,7 @@ default_select_section (tree decl, int reloc, } enum section_category -categorize_decl_for_section (tree decl, int reloc, int shlib) +categorize_decl_for_section (tree decl, int reloc) { enum section_category ret; @@ -5432,17 +5762,17 @@ categorize_decl_for_section (tree decl, int reloc, int shlib) || TREE_SIDE_EFFECTS (decl) || ! TREE_CONSTANT (DECL_INITIAL (decl))) { - if (shlib && (reloc & 2)) - ret = SECCAT_DATA_REL; - else if (shlib && reloc) - ret = SECCAT_DATA_REL_LOCAL; + /* Here the reloc_rw_mask is not testing whether the section should + be read-only or not, but whether the dynamic link will have to + do something. If so, we wish to segregate the data in order to + minimize cache misses inside the dynamic linker. */ + if (reloc & targetm.asm_out.reloc_rw_mask ()) + ret = reloc == 1 ? SECCAT_DATA_REL_LOCAL : SECCAT_DATA_REL; else ret = SECCAT_DATA; } - else if (shlib && (reloc & 2)) - ret = SECCAT_DATA_REL_RO; - else if (shlib && reloc) - ret = SECCAT_DATA_REL_RO_LOCAL; + else if (reloc & targetm.asm_out.reloc_rw_mask ()) + ret = reloc == 1 ? SECCAT_DATA_REL_RO_LOCAL : SECCAT_DATA_REL_RO; else if (reloc || flag_merge_constants < 2) /* C and C++ don't allow different variables to share the same location. -fmerge-all-constants allows even that (at the @@ -5455,7 +5785,7 @@ categorize_decl_for_section (tree decl, int reloc, int shlib) } else if (TREE_CODE (decl) == CONSTRUCTOR) { - if ((shlib && reloc) + if ((reloc & targetm.asm_out.reloc_rw_mask ()) || TREE_SIDE_EFFECTS (decl) || ! TREE_CONSTANT (decl)) ret = SECCAT_DATA; @@ -5495,13 +5825,7 @@ categorize_decl_for_section (tree decl, int reloc, int shlib) bool decl_readonly_section (tree decl, int reloc) { - return decl_readonly_section_1 (decl, reloc, flag_pic); -} - -bool -decl_readonly_section_1 (tree decl, int reloc, int shlib) -{ - switch (categorize_decl_for_section (decl, reloc, shlib)) + switch (categorize_decl_for_section (decl, reloc)) { case SECCAT_RODATA: case SECCAT_RODATA_MERGE_STR: @@ -5522,15 +5846,8 @@ section * default_elf_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align) { - return default_elf_select_section_1 (decl, reloc, align, flag_pic); -} - -section * -default_elf_select_section_1 (tree decl, int reloc, - unsigned HOST_WIDE_INT align, int shlib) -{ const char *sname; - switch (categorize_decl_for_section (decl, reloc, shlib)) + switch (categorize_decl_for_section (decl, reloc)) { case SECCAT_TEXT: /* We're not supposed to be called on FUNCTION_DECLs. */ @@ -5592,19 +5909,13 @@ default_elf_select_section_1 (tree decl, int reloc, void default_unique_section (tree decl, int reloc) { - default_unique_section_1 (decl, reloc, flag_pic); -} - -void -default_unique_section_1 (tree decl, int reloc, int shlib) -{ /* We only need to use .gnu.linkonce if we don't have COMDAT groups. */ bool one_only = DECL_ONE_ONLY (decl) && !HAVE_COMDAT_GROUP; const char *prefix, *name; size_t nlen, plen; char *string; - switch (categorize_decl_for_section (decl, reloc, shlib)) + switch (categorize_decl_for_section (decl, reloc)) { case SECCAT_TEXT: prefix = one_only ? ".gnu.linkonce.t." : ".text."; @@ -5665,45 +5976,76 @@ default_unique_section_1 (tree decl, int reloc, int shlib) DECL_SECTION_NAME (decl) = build_string (nlen + plen, string); } +/* Like compute_reloc_for_constant, except for an RTX. The return value + is a mask for which bit 1 indicates a global relocation, and bit 0 + indicates a local relocation. */ + +static int +compute_reloc_for_rtx_1 (rtx *xp, void *data) +{ + int *preloc = data; + rtx x = *xp; + + switch (GET_CODE (x)) + { + case SYMBOL_REF: + *preloc |= SYMBOL_REF_LOCAL_P (x) ? 1 : 2; + break; + case LABEL_REF: + *preloc |= 1; + break; + default: + break; + } + + return 0; +} + +static int +compute_reloc_for_rtx (rtx x) +{ + int reloc; + + switch (GET_CODE (x)) + { + case CONST: + case SYMBOL_REF: + case LABEL_REF: + reloc = 0; + for_each_rtx (&x, compute_reloc_for_rtx_1, &reloc); + return reloc; + + default: + return 0; + } +} + section * default_select_rtx_section (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x, unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED) { - if (flag_pic) - switch (GET_CODE (x)) - { - case CONST: - case SYMBOL_REF: - case LABEL_REF: - return data_section; - - default: - break; - } - - return readonly_data_section; + if (compute_reloc_for_rtx (x) & targetm.asm_out.reloc_rw_mask ()) + return data_section; + else + return readonly_data_section; } section * default_elf_select_rtx_section (enum machine_mode mode, rtx x, unsigned HOST_WIDE_INT align) { - /* ??? Handle small data here somehow. */ + int reloc = compute_reloc_for_rtx (x); - if (flag_pic) - switch (GET_CODE (x)) - { - case CONST: - case SYMBOL_REF: - return get_named_section (NULL, ".data.rel.ro", 3); + /* ??? Handle small data here somehow. */ - case LABEL_REF: + if (reloc & targetm.asm_out.reloc_rw_mask ()) + { + if (reloc == 1) return get_named_section (NULL, ".data.rel.ro.local", 1); - - default: - break; - } + else + return get_named_section (NULL, ".data.rel.ro", 3); + } return mergeable_constant_section (mode, align, 0); } @@ -5728,7 +6070,8 @@ default_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED) flags |= SYMBOL_FLAG_FUNCTION; if (targetm.binds_local_p (decl)) flags |= SYMBOL_FLAG_LOCAL; - if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl)) + if (targetm.have_tls && TREE_CODE (decl) == VAR_DECL + && DECL_THREAD_LOCAL_P (decl)) flags |= DECL_TLS_MODEL (decl) << SYMBOL_FLAG_TLS_SHIFT; else if (targetm.in_small_data_p (decl)) flags |= SYMBOL_FLAG_SMALL; @@ -5759,7 +6102,7 @@ default_asm_output_anchor (rtx symbol) { char buffer[100]; - sprintf (buffer, ". + " HOST_WIDE_INT_PRINT_DEC, + sprintf (buffer, "*. + " HOST_WIDE_INT_PRINT_DEC, SYMBOL_REF_BLOCK_OFFSET (symbol)); ASM_OUTPUT_DEF (asm_out_file, XSTR (symbol, 0), buffer); } @@ -5882,6 +6225,14 @@ default_globalize_label (FILE * stream, const char *name) } #endif /* GLOBAL_ASM_OP */ +/* Default function to output code that will globalize a declaration. */ +void +default_globalize_decl_name (FILE * stream, tree decl) +{ + const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0); + targetm.asm_out.globalize_label (stream, name); +} + /* Default function to output a label for unwind information. The default is to do nothing. A target that needs nonlocal labels for unwind information must provide its own function to do this. */ @@ -6195,4 +6546,120 @@ output_object_blocks (void) htab_traverse (object_block_htab, output_object_block_htab, NULL); } +/* This function provides a possible implementation of the + TARGET_ASM_RECORD_GCC_SWITCHES target hook for ELF targets. When triggered + by -frecord-gcc-switches it creates a new mergeable, string section in the + assembler output file called TARGET_ASM_RECORD_GCC_SWITCHES_SECTION which + contains the switches in ASCII format. + + FIXME: This code does not correctly handle double quote characters + that appear inside strings, (it strips them rather than preserving them). + FIXME: ASM_OUTPUT_ASCII, as defined in config/elfos.h will not emit NUL + characters - instead it treats them as sub-string separators. Since + we want to emit NUL strings terminators into the object file we have to use + ASM_OUTPUT_SKIP. */ + +int +elf_record_gcc_switches (print_switch_type type, const char * name) +{ + static char buffer[1024]; + + /* This variable is used as part of a simplistic heuristic to detect + command line switches which take an argument: + + "If a command line option does not start with a dash then + it is an argument for the previous command line option." + + This fails in the case of the command line option which is the name + of the file to compile, but otherwise it is pretty reasonable. */ + static bool previous_name_held_back = FALSE; + + switch (type) + { + case SWITCH_TYPE_PASSED: + if (* name != '-') + { + if (previous_name_held_back) + { + unsigned int len = strlen (buffer); + + snprintf (buffer + len, sizeof buffer - len, " %s", name); + ASM_OUTPUT_ASCII (asm_out_file, buffer, strlen (buffer)); + ASM_OUTPUT_SKIP (asm_out_file, (unsigned HOST_WIDE_INT) 1); + previous_name_held_back = FALSE; + } + else + { + strncpy (buffer, name, sizeof buffer); + ASM_OUTPUT_ASCII (asm_out_file, buffer, strlen (buffer)); + ASM_OUTPUT_SKIP (asm_out_file, (unsigned HOST_WIDE_INT) 1); + } + } + else + { + if (previous_name_held_back) + { + ASM_OUTPUT_ASCII (asm_out_file, buffer, strlen (buffer)); + ASM_OUTPUT_SKIP (asm_out_file, (unsigned HOST_WIDE_INT) 1); + } + + strncpy (buffer, name, sizeof buffer); + previous_name_held_back = TRUE; + } + break; + + case SWITCH_TYPE_DESCRIPTIVE: + if (name == NULL) + { + /* Distinguish between invocations where name is NULL. */ + static bool started = false; + + if (started) + { + if (previous_name_held_back) + { + ASM_OUTPUT_ASCII (asm_out_file, buffer, strlen (buffer)); + ASM_OUTPUT_SKIP (asm_out_file, (unsigned HOST_WIDE_INT) 1); + } + } + else + { + section * sec; + + sec = get_section (targetm.asm_out.record_gcc_switches_section, + SECTION_DEBUG + | SECTION_MERGE + | SECTION_STRINGS + | (SECTION_ENTSIZE & 1), + NULL); + switch_to_section (sec); + started = true; + } + } + + default: + break; + } + + /* The return value is currently ignored by the caller, but must be 0. + For -fverbose-asm the return value would be the number of characters + emitted into the assembler file. */ + return 0; +} + +/* Emit text to declare externally defined symbols. It is needed to + properly support non-default visibility. */ +void +default_elf_asm_output_external (FILE *file ATTRIBUTE_UNUSED, + tree decl, + const char *name ATTRIBUTE_UNUSED) +{ + /* We output the name if and only if TREE_SYMBOL_REFERENCED is + set in order to avoid putting out names that are never really + used. */ + if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) + && targetm.binds_local_p (decl)) + maybe_assemble_visibility (decl); +} + #include "gt-varasm.h"