X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fvarasm.c;h=b3d3bb1ce75f24bf165b5e9ece7ee08ce608288a;hb=abe32cceb59cc1e912e0ba48e9981ef3738e618a;hp=68bd026a2791f926b6d6dff6d8c608c1bd689b59;hpb=63bf54cf778c9f182a9fcaf64b8bfbad4399a6d8;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/varasm.c b/gcc/varasm.c index 68bd026a279..b3d3bb1ce75 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -1,13 +1,13 @@ /* 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. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later +Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY @@ -16,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +along with GCC; see the file COPYING3. If not see +. */ /* This file handles generation of all the assembler code @@ -53,6 +52,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 @@ -70,17 +70,7 @@ struct addr_const; struct constant_descriptor_rtx; struct rtx_constant_pool; -struct varasm_status GTY(()) -{ - /* If we're using a per-function constant pool, this is it. */ - struct rtx_constant_pool *pool; - - /* Number of tree-constants deferred during the expansion of this - function. */ - unsigned int deferred_constants; -}; - -#define n_deferred_constants (cfun->varasm->deferred_constants) +#define n_deferred_constants (crtl->varasm.deferred_constants) /* Number for making the label on the next constant that is stored in memory. */ @@ -107,7 +97,7 @@ bool first_function_block_is_cold; /* We give all constants their own alias set. Perhaps redundant with MEM_READONLY_P, but pre-dates it. */ -static HOST_WIDE_INT const_alias_set; +static alias_set_type const_alias_set; static const char *strip_reg_name (const char *); static int contains_pointers_p (tree); @@ -126,7 +116,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 *, @@ -138,10 +127,8 @@ static void asm_output_aligned_bss (FILE *, tree, const char *, ATTRIBUTE_UNUSED; #endif #endif /* BSS_SECTION_ASM_OP */ -static bool asm_emit_uninitialised (tree, const char*, - unsigned HOST_WIDE_INT, - unsigned HOST_WIDE_INT); static void mark_weak (tree); +static void output_constant_pool (const char *, tree); /* Well-known sections, each one associated with some sort of *_ASM_OP. */ section *text_section; @@ -153,6 +140,15 @@ section *dtors_section; section *bss_section; section *sbss_section; +/* Various forms of common section. All are guaranteed to be nonnull. */ +section *tls_comm_section; +section *comm_section; +section *lcomm_section; + +/* A SECTION_NOSWITCH section used for declaring global BSS variables. + May be null. */ +section *bss_noswitch_section; + /* The section that holds the main exception table, when known. The section is set either by the target's init_sections hook or by the first call to switch_to_exception_section. */ @@ -184,6 +180,251 @@ static GTY(()) section *unnamed_sections; /* Hash table of named sections. */ static GTY((param_is (section))) htab_t section_htab; +/* A table of object_blocks, indexed by section. */ +static GTY((param_is (struct object_block))) htab_t object_block_htab; + +/* The next number to use for internal anchor labels. */ +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 @@ -202,6 +443,34 @@ section_entry_hash (const void *p) return htab_hash_string (old->named.name); } +/* Return a hash value for section SECT. */ + +static hashval_t +hash_section (section *sect) +{ + if (sect->common.flags & SECTION_NAMED) + return htab_hash_string (sect->named.name); + return sect->common.flags; +} + +/* Helper routines for maintaining object_block_htab. */ + +static int +object_block_entry_eq (const void *p1, const void *p2) +{ + const struct object_block *old = p1; + const section *new = p2; + + return old->sect == new; +} + +static hashval_t +object_block_entry_hash (const void *p) +{ + const struct object_block *old = p; + return hash_section (old->sect); +} + /* Return a new unnamed section with the given fields. */ section * @@ -211,7 +480,7 @@ get_unnamed_section (unsigned int flags, void (*callback) (const void *), section *sect; sect = ggc_alloc (sizeof (struct unnamed_section)); - sect->unnamed.common.flags = flags; + sect->unnamed.common.flags = flags | SECTION_UNNAMED; sect->unnamed.callback = callback; sect->unnamed.data = data; sect->unnamed.next = unnamed_sections; @@ -220,6 +489,20 @@ get_unnamed_section (unsigned int flags, void (*callback) (const void *), return sect; } +/* Return a SECTION_NOSWITCH section with the given fields. */ + +static section * +get_noswitch_section (unsigned int flags, noswitch_section_callback callback) +{ + section *sect; + + sect = ggc_alloc (sizeof (struct unnamed_section)); + sect->noswitch.common.flags = flags | SECTION_NOSWITCH; + sect->noswitch.callback = callback; + + return sect; +} + /* Return the named section structure associated with NAME. Create a new section with the given fields if no such structure exists. */ @@ -256,6 +539,70 @@ get_section (const char *name, unsigned int flags, tree decl) return sect; } +/* Return true if the current compilation mode benefits from having + objects grouped into blocks. */ + +static bool +use_object_blocks_p (void) +{ + return flag_section_anchors; +} + +/* Return the object_block structure for section SECT. Create a new + structure if we haven't created one already. Return null if SECT + itself is null. */ + +static struct object_block * +get_block_for_section (section *sect) +{ + struct object_block *block; + void **slot; + + if (sect == NULL) + return NULL; + + slot = htab_find_slot_with_hash (object_block_htab, sect, + hash_section (sect), INSERT); + block = (struct object_block *) *slot; + if (block == NULL) + { + block = (struct object_block *) + ggc_alloc_cleared (sizeof (struct object_block)); + block->sect = sect; + *slot = block; + } + return block; +} + +/* Create a symbol with label LABEL and place it at byte offset + OFFSET in BLOCK. OFFSET can be negative if the symbol's offset + is not yet known. LABEL must be a garbage-collected string. */ + +static rtx +create_block_symbol (const char *label, struct object_block *block, + HOST_WIDE_INT offset) +{ + rtx symbol; + unsigned int size; + + /* Create the extended SYMBOL_REF. */ + size = RTX_HDR_SIZE + sizeof (struct block_symbol); + symbol = ggc_alloc_zone (size, &rtl_zone); + + /* Initialize the normal SYMBOL_REF fields. */ + memset (symbol, 0, size); + PUT_CODE (symbol, SYMBOL_REF); + PUT_MODE (symbol, Pmode); + XSTR (symbol, 0) = label; + SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_HAS_BLOCK_INFO; + + /* Initialize the block_symbol stuff. */ + SYMBOL_REF_BLOCK (symbol) = block; + SYMBOL_REF_BLOCK_OFFSET (symbol) = offset; + + return symbol; +} + static void initialize_cold_section_name (void) { @@ -264,7 +611,7 @@ initialize_cold_section_name (void) tree dsn; gcc_assert (cfun && current_function_decl); - if (cfun->unlikely_text_section_name) + if (crtl->subsections.unlikely_text_section_name) return; dsn = DECL_SECTION_NAME (current_function_decl); @@ -276,10 +623,10 @@ initialize_cold_section_name (void) stripped_name = targetm.strip_name_encoding (name); buffer = ACONCAT ((stripped_name, "_unlikely", NULL)); - cfun->unlikely_text_section_name = ggc_strdup (buffer); + crtl->subsections.unlikely_text_section_name = ggc_strdup (buffer); } else - cfun->unlikely_text_section_name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME; + crtl->subsections.unlikely_text_section_name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME; } /* Tell assembler to switch to unlikely-to-be-executed text section. */ @@ -289,10 +636,10 @@ unlikely_text_section (void) { if (cfun) { - if (!cfun->unlikely_text_section_name) + if (!crtl->subsections.unlikely_text_section_name) initialize_cold_section_name (); - return get_named_section (NULL, cfun->unlikely_text_section_name, 0); + return get_named_section (NULL, crtl->subsections.unlikely_text_section_name, 0); } else return get_named_section (NULL, UNLIKELY_EXECUTED_TEXT_SECTION_NAME, 0); @@ -309,13 +656,13 @@ unlikely_text_section_p (section *sect) const char *name; if (cfun) - name = cfun->unlikely_text_section_name; + name = crtl->subsections.unlikely_text_section_name; else name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME; return (name && sect - && (sect->common.flags & SECTION_NAMED) != 0 + && SECTION_STYLE (sect) == SECTION_NAMED && strcmp (name, sect->named.name) == 0); } @@ -368,7 +715,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; @@ -440,9 +788,14 @@ function_section (tree decl) reloc = 1; #ifdef USE_SELECT_SECTION_FOR_FUNCTIONS - return targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl)); + if (decl != NULL_TREE + && DECL_SECTION_NAME (decl) != NULL_TREE) + return reloc ? unlikely_text_section () + : get_named_section (decl, NULL, 0); + else + return targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl)); #else - return hot_function_section (decl); + return reloc ? unlikely_text_section () : hot_function_section (decl); #endif } @@ -450,9 +803,15 @@ section * current_function_section (void) { #ifdef USE_SELECT_SECTION_FOR_FUNCTIONS - return targetm.asm_out.select_section (current_function_decl, - in_cold_section_p, - DECL_ALIGN (current_function_decl)); + if (current_function_decl != NULL_TREE + && DECL_SECTION_NAME (current_function_decl) != NULL_TREE) + return in_cold_section_p ? unlikely_text_section () + : get_named_section (current_function_decl, + NULL, 0); + else + return targetm.asm_out.select_section (current_function_decl, + in_cold_section_p, + DECL_ALIGN (current_function_decl)); #else return (in_cold_section_p ? unlikely_text_section () @@ -515,19 +874,6 @@ default_no_function_rodata_section (tree decl ATTRIBUTE_UNUSED) return readonly_data_section; } -/* Switch to section for variable DECL. RELOC is the same as the - argument to SELECT_SECTION. */ - -void -variable_section (tree decl, int reloc) -{ - if (IN_NAMED_SECTION (decl)) - switch_to_section (get_named_section (decl, NULL, reloc)); - else - switch_to_section (targetm.asm_out.select_section (decl, reloc, - DECL_ALIGN (decl))); -} - /* Return the section to use for string merging. */ static section * @@ -535,16 +881,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))); @@ -556,7 +906,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. */ @@ -694,6 +1043,188 @@ decode_reg_name (const char *asmspec) return -1; } +/* Return true if DECL's initializer is suitable for a BSS section. */ + +static bool +bss_initializer_p (const_tree decl) +{ + return (DECL_INITIAL (decl) == NULL + || DECL_INITIAL (decl) == error_mark_node + || (flag_zero_initialized_in_bss + /* Leave constant zeroes in .rodata so they + can be shared. */ + && !TREE_READONLY (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 + unsigned int data_align = DATA_ALIGNMENT (TREE_TYPE (decl), align); + /* Don't increase alignment too much for TLS variables - TLS space + is too precious. */ + if (! DECL_THREAD_LOCAL_P (decl) || data_align <= BITS_PER_WORD) + align = data_align; +#endif +#ifdef CONSTANT_ALIGNMENT + if (DECL_INITIAL (decl) != 0 && DECL_INITIAL (decl) != error_mark_node) + { + unsigned int const_align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl), + align); + /* Don't increase alignment too much for TLS variables - TLS space + is too precious. */ + if (! DECL_THREAD_LOCAL_P (decl) || const_align <= BITS_PER_WORD) + align = const_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. */ + +static section * +get_variable_section (tree decl, bool prefer_noswitch_p) +{ + int reloc; + + /* If the decl has been given an explicit section name, then it + isn't common, and shouldn't be handled as such. */ + if (DECL_COMMON (decl) && DECL_SECTION_NAME (decl) == NULL) + { + if (DECL_THREAD_LOCAL_P (decl)) + return tls_comm_section; + if (TREE_PUBLIC (decl) && bss_initializer_p (decl)) + return comm_section; + } + + if (DECL_INITIAL (decl) == error_mark_node) + reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0; + else if (DECL_INITIAL (decl)) + reloc = compute_reloc_for_constant (DECL_INITIAL (decl)); + else + reloc = 0; + + resolve_unique_section (decl, reloc, flag_data_sections); + if (IN_NAMED_SECTION (decl)) + return get_named_section (decl, NULL, reloc); + + if (!DECL_THREAD_LOCAL_P (decl) + && !(prefer_noswitch_p && targetm.have_switchable_bss_sections) + && bss_initializer_p (decl)) + { + if (!TREE_PUBLIC (decl)) + return lcomm_section; + if (bss_noswitch_section) + return bss_noswitch_section; + } + + return targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl)); +} + +/* Return the block into which object_block DECL should be placed. */ + +static struct object_block * +get_block_for_decl (tree decl) +{ + section *sect; + + if (TREE_CODE (decl) == VAR_DECL) + { + /* The object must be defined in this translation unit. */ + if (DECL_EXTERNAL (decl)) + return NULL; + + /* There's no point using object blocks for something that is + isolated by definition. */ + if (DECL_ONE_ONLY (decl)) + return NULL; + } + + /* We can only calculate block offsets if the decl has a known + constant size. */ + if (DECL_SIZE_UNIT (decl) == NULL) + return NULL; + if (!host_integerp (DECL_SIZE_UNIT (decl), 1)) + return NULL; + + /* 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; + + return get_block_for_section (sect); +} + +/* Make sure block symbol SYMBOL is in block BLOCK. */ + +static void +change_symbol_block (rtx symbol, struct object_block *block) +{ + if (block != SYMBOL_REF_BLOCK (symbol)) + { + gcc_assert (SYMBOL_REF_BLOCK_OFFSET (symbol) < 0); + SYMBOL_REF_BLOCK (symbol) = block; + } +} + +/* Return true if it is possible to put DECL in an object_block. */ + +static bool +use_blocks_for_decl_p (tree decl) +{ + /* Only data DECLs can be placed into object blocks. */ + if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != CONST_DECL) + return false; + + /* Detect decls created by dw2_force_const_mem. Such decls are + special because DECL_INITIAL doesn't specify the decl's true value. + dw2_output_indirect_constants will instead call assemble_variable + with dont_output_data set to 1 and then print the contents itself. */ + 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; +} + /* Create the DECL_RTL for a VAR_DECL or FUNCTION_DECL. DECL should have static storage duration. In other words, it should not be an automatic variable, including PARM_DECLs. @@ -730,9 +1261,9 @@ make_decl_rtl (tree decl) if (DECL_RTL_SET_P (decl)) { /* If the old RTL had the wrong mode, fix the mode. */ - if (GET_MODE (DECL_RTL (decl)) != DECL_MODE (decl)) - SET_DECL_RTL (decl, adjust_address_nv (DECL_RTL (decl), - DECL_MODE (decl), 0)); + x = DECL_RTL (decl); + if (GET_MODE (x) != DECL_MODE (decl)) + SET_DECL_RTL (decl, adjust_address_nv (x, DECL_MODE (decl), 0)); if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl)) return; @@ -747,6 +1278,13 @@ make_decl_rtl (tree decl) decl attribute overrides another. */ targetm.encode_section_info (decl, DECL_RTL (decl), false); + /* If the symbol has a SYMBOL_REF_BLOCK field, update it based + on the new decl information. */ + if (MEM_P (x) + && GET_CODE (XEXP (x, 0)) == SYMBOL_REF + && SYMBOL_REF_HAS_BLOCK_INFO_P (XEXP (x, 0))) + change_symbol_block (XEXP (x, 0), get_block_for_decl (decl)); + /* Make this function static known to the mudflap runtime. */ if (flag_mudflap && TREE_CODE (decl) == VAR_DECL) mudflap_enqueue_decl (decl); @@ -843,7 +1381,10 @@ make_decl_rtl (tree decl) if (TREE_CODE (decl) == VAR_DECL && DECL_WEAK (decl)) DECL_COMMON (decl) = 0; - x = gen_rtx_SYMBOL_REF (Pmode, name); + if (use_object_blocks_p () && use_blocks_for_decl_p (decl)) + x = create_block_symbol (name, get_block_for_decl (decl), -1); + else + x = gen_rtx_SYMBOL_REF (Pmode, name); SYMBOL_REF_WEAK (x) = DECL_WEAK (decl); SET_SYMBOL_REF_DECL (x, decl); @@ -862,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. */ @@ -907,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 @@ -934,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 @@ -960,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 @@ -984,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 @@ -1010,7 +1546,8 @@ notice_global_symbol (tree decl) const char **type = &first_global_object_name; if (first_global_object_name - || !TREE_PUBLIC (decl) || DECL_EXTERNAL (decl) + || !TREE_PUBLIC (decl) + || DECL_EXTERNAL (decl) || !DECL_NAME (decl) || (TREE_CODE (decl) != FUNCTION_DECL && (TREE_CODE (decl) != VAR_DECL @@ -1022,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) @@ -1050,27 +1587,27 @@ assemble_start_function (tree decl, const char *fnname) char tmp_label[100]; bool hot_label_written = false; - cfun->unlikely_text_section_name = NULL; + crtl->subsections.unlikely_text_section_name = NULL; first_function_block_is_cold = false; if (flag_reorder_blocks_and_partition) { ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LHOTB", const_labelno); - cfun->hot_section_label = ggc_strdup (tmp_label); + crtl->subsections.hot_section_label = ggc_strdup (tmp_label); ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LCOLDB", const_labelno); - cfun->cold_section_label = ggc_strdup (tmp_label); + crtl->subsections.cold_section_label = ggc_strdup (tmp_label); ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LHOTE", const_labelno); - cfun->hot_section_end_label = ggc_strdup (tmp_label); + crtl->subsections.hot_section_end_label = ggc_strdup (tmp_label); ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LCOLDE", const_labelno); - cfun->cold_section_end_label = ggc_strdup (tmp_label); + crtl->subsections.cold_section_end_label = ggc_strdup (tmp_label); const_labelno++; } else { - cfun->hot_section_label = NULL; - cfun->cold_section_label = NULL; - cfun->hot_section_end_label = NULL; - cfun->cold_section_end_label = NULL; + crtl->subsections.hot_section_label = NULL; + crtl->subsections.cold_section_label = NULL; + crtl->subsections.hot_section_end_label = NULL; + crtl->subsections.cold_section_end_label = NULL; } /* The following code does not need preprocessing in the assembler. */ @@ -1090,8 +1627,8 @@ assemble_start_function (tree decl, const char *fnname) if (flag_reorder_blocks_and_partition) { switch_to_section (unlikely_text_section ()); - assemble_align (FUNCTION_BOUNDARY); - ASM_OUTPUT_LABEL (asm_out_file, cfun->cold_section_label); + assemble_align (DECL_ALIGN (decl)); + ASM_OUTPUT_LABEL (asm_out_file, crtl->subsections.cold_section_label); /* When the function starts with a cold section, we need to explicitly align the hot section and write out the hot section label. @@ -1100,8 +1637,8 @@ assemble_start_function (tree decl, const char *fnname) && BB_PARTITION (ENTRY_BLOCK_PTR->next_bb) == BB_COLD_PARTITION) { switch_to_section (text_section); - assemble_align (FUNCTION_BOUNDARY); - ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_label); + assemble_align (DECL_ALIGN (decl)); + ASM_OUTPUT_LABEL (asm_out_file, crtl->subsections.hot_section_label); hot_label_written = true; first_function_block_is_cold = true; } @@ -1115,9 +1652,9 @@ assemble_start_function (tree decl, const char *fnname) initialize_cold_section_name (); - if (cfun->unlikely_text_section_name + if (crtl->subsections.unlikely_text_section_name && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)), - cfun->unlikely_text_section_name) == 0) + crtl->subsections.unlikely_text_section_name) == 0) first_function_block_is_cold = true; } @@ -1128,21 +1665,20 @@ assemble_start_function (tree decl, const char *fnname) switch_to_section (function_section (decl)); if (flag_reorder_blocks_and_partition && !hot_label_written) - ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_label); + ASM_OUTPUT_LABEL (asm_out_file, crtl->subsections.hot_section_label); /* Tell assembler to move to target machine's alignment for functions. */ - align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT); - if (align < force_align_functions_log) - align = force_align_functions_log; + align = floor_log2 (DECL_ALIGN (decl) / BITS_PER_UNIT); if (align > 0) { ASM_OUTPUT_ALIGN (asm_out_file, align); } /* Handle a user-specified function alignment. - Note that we still need to align to FUNCTION_BOUNDARY, as above, + Note that we still need to align to DECL_ALIGN, as above, because ASM_OUTPUT_MAX_SKIP_ALIGN might not do any alignment at all. */ - if (align_functions_log > align + if (! DECL_USER_ALIGN (decl) + && align_functions_log > align && cfun->function_frequency != FUNCTION_FREQUENCY_UNLIKELY_EXECUTED) { #ifdef ASM_OUTPUT_MAX_SKIP_ALIGN @@ -1186,7 +1722,7 @@ assemble_start_function (tree decl, const char *fnname) function. DECL describes the function. NAME is the function's name. */ void -assemble_end_function (tree decl, const char *fnname) +assemble_end_function (tree decl, const char *fnname ATTRIBUTE_UNUSED) { #ifdef ASM_DECLARE_FUNCTION_SIZE /* We could have switched section in the middle of the function. */ @@ -1207,12 +1743,12 @@ assemble_end_function (tree decl, const char *fnname) save_text_section = in_section; switch_to_section (unlikely_text_section ()); - ASM_OUTPUT_LABEL (asm_out_file, cfun->cold_section_end_label); + ASM_OUTPUT_LABEL (asm_out_file, crtl->subsections.cold_section_end_label); if (first_function_block_is_cold) switch_to_section (text_section); else switch_to_section (function_section (decl)); - ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_end_label); + ASM_OUTPUT_LABEL (asm_out_file, crtl->subsections.hot_section_end_label); switch_to_section (save_text_section); } } @@ -1276,124 +1812,142 @@ assemble_string (const char *p, int size) } -#if defined ASM_OUTPUT_ALIGNED_DECL_LOCAL -#define ASM_EMIT_LOCAL(decl, name, size, rounded) \ - ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, decl, name, size, DECL_ALIGN (decl)) -#else -#if defined ASM_OUTPUT_ALIGNED_LOCAL -#define ASM_EMIT_LOCAL(decl, name, size, rounded) \ - ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, DECL_ALIGN (decl)) +/* A noswitch_section_callback for lcomm_section. */ + +static bool +emit_local (tree decl ATTRIBUTE_UNUSED, + const char *name ATTRIBUTE_UNUSED, + unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED, + unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED) +{ +#if defined ASM_OUTPUT_ALIGNED_DECL_LOCAL + ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, decl, name, + size, DECL_ALIGN (decl)); + return true; +#elif defined ASM_OUTPUT_ALIGNED_LOCAL + ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, DECL_ALIGN (decl)); + return true; #else -#define ASM_EMIT_LOCAL(decl, name, size, rounded) \ - ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded) -#endif + ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded); + return false; #endif +} +/* A noswitch_section_callback for bss_noswitch_section. */ + +#if defined ASM_OUTPUT_ALIGNED_BSS || defined ASM_OUTPUT_BSS +static bool +emit_bss (tree decl ATTRIBUTE_UNUSED, + const char *name ATTRIBUTE_UNUSED, + unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED, + unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED) +{ #if defined ASM_OUTPUT_ALIGNED_BSS -#define ASM_EMIT_BSS(decl, name, size, rounded) \ - ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size, DECL_ALIGN (decl)) -#else -#if defined ASM_OUTPUT_BSS -#define ASM_EMIT_BSS(decl, name, size, rounded) \ - ASM_OUTPUT_BSS (asm_out_file, decl, name, size, rounded) + ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size, DECL_ALIGN (decl)); + return true; #else -#undef ASM_EMIT_BSS + ASM_OUTPUT_BSS (asm_out_file, decl, name, size, rounded); + return false; #endif +} #endif +/* A noswitch_section_callback for comm_section. */ + +static bool +emit_common (tree decl ATTRIBUTE_UNUSED, + const char *name ATTRIBUTE_UNUSED, + unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED, + unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED) +{ #if defined ASM_OUTPUT_ALIGNED_DECL_COMMON -#define ASM_EMIT_COMMON(decl, name, size, rounded) \ - ASM_OUTPUT_ALIGNED_DECL_COMMON (asm_out_file, decl, name, size, DECL_ALIGN (decl)) -#else -#if defined ASM_OUTPUT_ALIGNED_COMMON -#define ASM_EMIT_COMMON(decl, name, size, rounded) \ - ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size, DECL_ALIGN (decl)) + ASM_OUTPUT_ALIGNED_DECL_COMMON (asm_out_file, decl, name, + size, DECL_ALIGN (decl)); + return true; +#elif defined ASM_OUTPUT_ALIGNED_COMMON + ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size, DECL_ALIGN (decl)); + return true; #else -#define ASM_EMIT_COMMON(decl, name, size, rounded) \ - ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded) -#endif + ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded); + return false; #endif +} + +/* A noswitch_section_callback for tls_comm_section. */ static bool -asm_emit_uninitialised (tree decl, const char *name, - unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED, - unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED) +emit_tls_common (tree decl ATTRIBUTE_UNUSED, + const char *name ATTRIBUTE_UNUSED, + unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED, + unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED) { - enum - { - asm_dest_common, - asm_dest_bss, - asm_dest_local - } - destination = asm_dest_local; - - /* ??? We should handle .bss via select_section mechanisms rather than - via special target hooks. That would eliminate this special case. */ - if (TREE_PUBLIC (decl)) - { - if (!DECL_COMMON (decl)) -#ifdef ASM_EMIT_BSS - destination = asm_dest_bss; +#ifdef ASM_OUTPUT_TLS_COMMON + ASM_OUTPUT_TLS_COMMON (asm_out_file, decl, name, size); + return true; #else - return false; + sorry ("thread-local COMMON data not implemented"); + return true; #endif - else - destination = asm_dest_common; - } +} - if (destination != asm_dest_common) - { - resolve_unique_section (decl, 0, flag_data_sections); - /* Custom sections don't belong here. */ - if (DECL_SECTION_NAME (decl)) - return false; - } +/* Assemble DECL given that it belongs in SECTION_NOSWITCH section SECT. + NAME is the name of DECL's SYMBOL_REF. */ - if (destination == asm_dest_bss) - globalize_decl (decl); +static void +assemble_noswitch_variable (tree decl, const char *name, section *sect) +{ + unsigned HOST_WIDE_INT size, rounded; - if (flag_shared_data) - { - switch (destination) - { -#ifdef ASM_OUTPUT_SHARED_BSS - case asm_dest_bss: - ASM_OUTPUT_SHARED_BSS (asm_out_file, decl, name, size, rounded); - return; -#endif -#ifdef ASM_OUTPUT_SHARED_COMMON - case asm_dest_common: - ASM_OUTPUT_SHARED_COMMON (asm_out_file, name, size, rounded); - return; -#endif -#ifdef ASM_OUTPUT_SHARED_LOCAL - case asm_dest_local: - ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded); - return; -#endif - default: - break; - } - } + size = tree_low_cst (DECL_SIZE_UNIT (decl), 1); + rounded = size; + + /* Don't allocate zero bytes of common, + since that means "undefined external" in the linker. */ + if (size == 0) + rounded = 1; + + /* Round size up to multiple of BIGGEST_ALIGNMENT bits + so that each uninitialized object starts on such a boundary. */ + rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1; + rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT) + * (BIGGEST_ALIGNMENT / BITS_PER_UNIT)); + + if (!sect->noswitch.callback (decl, name, size, rounded) + && (unsigned HOST_WIDE_INT) DECL_ALIGN_UNIT (decl) > rounded) + warning (0, "requested alignment for %q+D is greater than " + "implemented alignment of %wu", decl, rounded); +} + +/* A subroutine of assemble_variable. Output the label and contents of + DECL, whose address is a SYMBOL_REF with name NAME. DONT_OUTPUT_DATA + is as for assemble_variable. */ + +static void +assemble_variable_contents (tree decl, const char *name, + bool dont_output_data) +{ + /* Do any machine/system dependent processing of the object. */ +#ifdef ASM_DECLARE_OBJECT_NAME + last_assemble_variable_decl = decl; + ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl); +#else + /* Standard thing is just output label for the object. */ + ASM_OUTPUT_LABEL (asm_out_file, name); +#endif /* ASM_DECLARE_OBJECT_NAME */ - switch (destination) + if (!dont_output_data) { -#ifdef ASM_EMIT_BSS - case asm_dest_bss: - ASM_EMIT_BSS (decl, name, size, rounded); - break; -#endif - case asm_dest_common: - ASM_EMIT_COMMON (decl, name, size, rounded); - break; - case asm_dest_local: - ASM_EMIT_LOCAL (decl, name, size, rounded); - break; - default: - gcc_unreachable (); + if (DECL_INITIAL (decl) + && DECL_INITIAL (decl) != error_mark_node + && !initializer_zerop (DECL_INITIAL (decl))) + /* Output the actual data. */ + output_constant (DECL_INITIAL (decl), + tree_low_cst (DECL_SIZE_UNIT (decl), 1), + DECL_ALIGN (decl)); + else + /* Leave space for it. */ + assemble_zeros (tree_low_cst (DECL_SIZE_UNIT (decl), 1)); } - - return true; } /* Assemble everything that is needed for a variable or function declaration. @@ -1411,12 +1965,61 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED, int at_end ATTRIBUTE_UNUSED, int dont_output_data) { const char *name; - unsigned int align; - int reloc = 0; - rtx decl_rtl; + 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); + } - if (lang_hooks.decls.prepare_assemble_variable) - lang_hooks.decls.prepare_assemble_variable (decl); + decl = to; + } last_assemble_variable_decl = 0; @@ -1483,47 +2086,17 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED, return; } - name = XSTR (XEXP (decl_rtl, 0), 0); + gcc_assert (MEM_P (decl_rtl)); + gcc_assert (GET_CODE (XEXP (decl_rtl, 0)) == SYMBOL_REF); + symbol = XEXP (decl_rtl, 0); + name = XSTR (symbol, 0); if (TREE_PUBLIC (decl) && DECL_NAME (decl)) notice_global_symbol (decl); /* 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); @@ -1531,110 +2104,37 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED, if (DECL_PRESERVE_P (decl)) targetm.asm_out.mark_decl_preserved (name); - /* Handle uninitialized definitions. */ - - /* If the decl has been given an explicit section name, then it - isn't common, and shouldn't be handled as such. */ - if (DECL_SECTION_NAME (decl) || dont_output_data) - ; - else if (DECL_THREAD_LOCAL_P (decl)) - { - if (DECL_COMMON (decl)) - { -#ifdef ASM_OUTPUT_TLS_COMMON - unsigned HOST_WIDE_INT size; - - size = tree_low_cst (DECL_SIZE_UNIT (decl), 1); - ASM_OUTPUT_TLS_COMMON (asm_out_file, decl, name, size); - return; -#else - sorry ("thread-local COMMON data not implemented"); -#endif - } - } - else if (DECL_INITIAL (decl) == 0 - || DECL_INITIAL (decl) == error_mark_node - || (flag_zero_initialized_in_bss - /* Leave constant zeroes in .rodata so they can be shared. */ - && !TREE_READONLY (decl) - && initializer_zerop (DECL_INITIAL (decl)))) - { - unsigned HOST_WIDE_INT size = tree_low_cst (DECL_SIZE_UNIT (decl), 1); - unsigned HOST_WIDE_INT rounded = size; - - /* Don't allocate zero bytes of common, - since that means "undefined external" in the linker. */ - if (size == 0) - rounded = 1; - - /* Round size up to multiple of BIGGEST_ALIGNMENT bits - so that each uninitialized object starts on such a boundary. */ - rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1; - rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - * (BIGGEST_ALIGNMENT / BITS_PER_UNIT)); - -#if !defined(ASM_OUTPUT_ALIGNED_COMMON) && !defined(ASM_OUTPUT_ALIGNED_DECL_COMMON) && !defined(ASM_OUTPUT_ALIGNED_BSS) - if ((unsigned HOST_WIDE_INT) DECL_ALIGN_UNIT (decl) > rounded) - warning (0, "requested alignment for %q+D is greater than " - "implemented alignment of %wu", decl, rounded); -#endif - - /* If the target cannot output uninitialized but not common global data - in .bss, then we have to use .data, so fall through. */ - if (asm_emit_uninitialised (decl, name, size, rounded)) - return; - } - - /* Handle initialized definitions. - Also handle uninitialized global definitions if -fno-common and the - target doesn't support ASM_OUTPUT_BSS. */ - /* First make the assembler name(s) global if appropriate. */ - if (TREE_PUBLIC (decl) && DECL_NAME (decl)) + sect = get_variable_section (decl, false); + if (TREE_PUBLIC (decl) + && DECL_NAME (decl) + && (sect->common.flags & SECTION_COMMON) == 0) globalize_decl (decl); /* Output any data that we will need to use the address of. */ - if (DECL_INITIAL (decl) == error_mark_node) - reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0; - else if (DECL_INITIAL (decl)) - { - reloc = compute_reloc_for_constant (DECL_INITIAL (decl)); - output_addressed_constants (DECL_INITIAL (decl)); - } - - /* Switch to the appropriate section. */ - resolve_unique_section (decl, reloc, flag_data_sections); - variable_section (decl, reloc); + if (DECL_INITIAL (decl) && DECL_INITIAL (decl) != error_mark_node) + output_addressed_constants (DECL_INITIAL (decl)); /* dbxout.c needs to know this. */ - if (in_section && (in_section->common.flags & SECTION_CODE) != 0) + if (sect && (sect->common.flags & SECTION_CODE) != 0) DECL_IN_TEXT_SECTION (decl) = 1; - /* Output the alignment of this data. */ - if (align > BITS_PER_UNIT) - ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl))); - - /* Do any machine/system dependent processing of the object. */ -#ifdef ASM_DECLARE_OBJECT_NAME - last_assemble_variable_decl = decl; - ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl); -#else - /* Standard thing is just output label for the object. */ - ASM_OUTPUT_LABEL (asm_out_file, name); -#endif /* ASM_DECLARE_OBJECT_NAME */ - - if (!dont_output_data) + /* If the decl is part of an object_block, make sure that the decl + has been positioned within its block, but do not write out its + definition yet. output_object_blocks will do that later. */ + if (SYMBOL_REF_HAS_BLOCK_INFO_P (symbol) && SYMBOL_REF_BLOCK (symbol)) { - if (DECL_INITIAL (decl) - && DECL_INITIAL (decl) != error_mark_node - && !initializer_zerop (DECL_INITIAL (decl))) - /* Output the actual data. */ - output_constant (DECL_INITIAL (decl), - tree_low_cst (DECL_SIZE_UNIT (decl), 1), - align); - else - /* Leave space for it. */ - assemble_zeros (tree_low_cst (DECL_SIZE_UNIT (decl), 1)); + gcc_assert (!dont_output_data); + place_block_symbol (symbol); + } + else if (SECTION_STYLE (sect) == SECTION_NOSWITCH) + assemble_noswitch_variable (decl, name, sect); + else + { + switch_to_section (sect); + 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); } } @@ -1749,11 +2249,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 } @@ -1803,8 +2302,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; @@ -1890,11 +2389,6 @@ assemble_static_space (unsigned HOST_WIDE_INT size) const char *namestring; rtx x; -#if 0 - if (flag_shared_data) - switch_to_section (data_section); -#endif - ASM_GENERATE_INTERNAL_LABEL (name, "LF", const_labelno); ++const_labelno; namestring = ggc_strdup (name); @@ -2066,11 +2560,17 @@ assemble_integer (rtx x, unsigned int size, unsigned int align, int force) enum machine_mode omode, imode; unsigned int subalign; unsigned int subsize, i; + unsigned char mclass; subsize = size > UNITS_PER_WORD? UNITS_PER_WORD : 1; subalign = MIN (align, subsize * BITS_PER_UNIT); - omode = mode_for_size (subsize * BITS_PER_UNIT, MODE_INT, 0); - imode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0); + if (GET_CODE (x) == CONST_FIXED) + mclass = GET_MODE_CLASS (GET_MODE (x)); + else + mclass = MODE_INT; + + omode = mode_for_size (subsize * BITS_PER_UNIT, mclass, 0); + imode = mode_for_size (size * BITS_PER_UNIT, mclass, 0); for (i = 0; i < size; i += subsize) { @@ -2182,6 +2682,7 @@ decode_addr_const (tree exp, struct addr_const *value) break; case REAL_CST: + case FIXED_CST: case STRING_CST: case COMPLEX_CST: case CONSTRUCTOR: @@ -2229,7 +2730,7 @@ static void maybe_output_constant_def_contents (struct constant_descriptor_tree static hashval_t const_desc_hash (const void *ptr) { - return ((struct constant_descriptor_tree *)ptr)->hash; + return ((const struct constant_descriptor_tree *)ptr)->hash; } static hashval_t @@ -2253,6 +2754,9 @@ const_hash_1 (const tree exp) case REAL_CST: return real_hash (TREE_REAL_CST_PTR (exp)); + case FIXED_CST: + return fixed_hash (TREE_FIXED_CST_PTR (exp)); + case STRING_CST: p = TREE_STRING_POINTER (exp); len = TREE_STRING_LENGTH (exp); @@ -2304,6 +2808,7 @@ const_hash_1 (const tree exp) return hi; case PLUS_EXPR: + case POINTER_PLUS_EXPR: case MINUS_EXPR: return (const_hash_1 (TREE_OPERAND (exp, 0)) * 9 + const_hash_1 (TREE_OPERAND (exp, 1))); @@ -2359,6 +2864,8 @@ compare_constant (const tree t1, const tree t2) /* Integer constants are the same only if the same width of type. */ if (TYPE_PRECISION (TREE_TYPE (t1)) != TYPE_PRECISION (TREE_TYPE (t2))) return 0; + if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2))) + return 0; return tree_int_cst_equal (t1, t2); case REAL_CST: @@ -2368,6 +2875,13 @@ compare_constant (const tree t1, const tree t2) return REAL_VALUES_IDENTICAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2)); + case FIXED_CST: + /* Fixed constants are the same only if the same width of type. */ + if (TYPE_PRECISION (TREE_TYPE (t1)) != TYPE_PRECISION (TREE_TYPE (t2))) + return 0; + + return FIXED_VALUES_IDENTICAL (TREE_FIXED_CST (t1), TREE_FIXED_CST (t2)); + case STRING_CST: if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2))) return 0; @@ -2448,6 +2962,7 @@ compare_constant (const tree t1, const tree t2) } case PLUS_EXPR: + case POINTER_PLUS_EXPR: case MINUS_EXPR: case RANGE_EXPR: return (compare_constant (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)) @@ -2460,15 +2975,7 @@ compare_constant (const tree t1, const tree t2) return compare_constant (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)); default: - { - tree nt1, nt2; - nt1 = lang_hooks.expand_constant (t1); - nt2 = lang_hooks.expand_constant (t2); - if (nt1 != t1 || nt2 != t2) - return compare_constant (nt1, nt2); - else - return 0; - } + return 0; } gcc_unreachable (); @@ -2493,6 +3000,7 @@ copy_constant (tree exp) case INTEGER_CST: case REAL_CST: + case FIXED_CST: case STRING_CST: return copy_node (exp); @@ -2502,6 +3010,7 @@ copy_constant (tree exp) copy_constant (TREE_IMAGPART (exp))); case PLUS_EXPR: + case POINTER_PLUS_EXPR: case MINUS_EXPR: return build2 (TREE_CODE (exp), TREE_TYPE (exp), copy_constant (TREE_OPERAND (exp, 0)), @@ -2534,15 +3043,50 @@ copy_constant (tree exp) } default: - { - tree t = lang_hooks.expand_constant (exp); - - gcc_assert (t == exp); - return copy_constant (t); - } + gcc_unreachable (); } } +/* Return the alignment of constant EXP in bits. */ + +static unsigned int +get_constant_alignment (tree exp) +{ + unsigned int align; + + align = TYPE_ALIGN (TREE_TYPE (exp)); +#ifdef CONSTANT_ALIGNMENT + align = CONSTANT_ALIGNMENT (exp, align); +#endif + return align; +} + +/* Return the section into which constant EXP should be placed. */ + +static section * +get_constant_section (tree exp) +{ + if (IN_NAMED_SECTION (exp)) + return get_named_section (exp, NULL, compute_reloc_for_constant (exp)); + else + return targetm.asm_out.select_section (exp, + compute_reloc_for_constant (exp), + get_constant_alignment (exp)); +} + +/* Return the size of constant EXP in bytes. */ + +static HOST_WIDE_INT +get_constant_size (tree exp) +{ + HOST_WIDE_INT size; + + size = int_size_in_bytes (TREE_TYPE (exp)); + if (TREE_CODE (exp) == STRING_CST) + size = MAX (TREE_STRING_LENGTH (exp), size); + return size; +} + /* Subroutine of output_constant_def: No constant equal to EXP is known to have been output. Make a constant descriptor to enter EXP in the hash table. @@ -2571,8 +3115,15 @@ build_constant_desc (tree exp) ASM_GENERATE_INTERNAL_LABEL (label, "LC", labelno); /* We have a symbol name; construct the SYMBOL_REF and the MEM. */ - symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label)); - SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOCAL; + if (use_object_blocks_p ()) + { + section *sect = get_constant_section (exp); + symbol = create_block_symbol (ggc_strdup (label), + get_block_for_section (sect), -1); + } + else + symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label)); + SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_LOCAL; SET_SYMBOL_REF_DECL (symbol, desc->value); TREE_CONSTANT_POOL_ADDRESS_P (symbol) = 1; @@ -2665,54 +3216,57 @@ maybe_output_constant_def_contents (struct constant_descriptor_tree *desc, output_constant_def_contents (symbol); } +/* Subroutine of output_constant_def_contents. Output the definition + of constant EXP, which is pointed to by label LABEL. ALIGN is the + constant's alignment in bits. */ + +static void +assemble_constant_contents (tree exp, const char *label, unsigned int align) +{ + HOST_WIDE_INT size; + + size = get_constant_size (exp); + + /* Do any machine/system dependent processing of the constant. */ +#ifdef ASM_DECLARE_CONSTANT_NAME + ASM_DECLARE_CONSTANT_NAME (asm_out_file, label, exp, size); +#else + /* Standard thing is just output label for the constant. */ + ASM_OUTPUT_LABEL (asm_out_file, label); +#endif /* ASM_DECLARE_CONSTANT_NAME */ + + /* Output the value of EXP. */ + output_constant (exp, size, align); +} + /* We must output the constant data referred to by SYMBOL; do so. */ static void output_constant_def_contents (rtx symbol) { tree exp = SYMBOL_REF_DECL (symbol); - const char *label = XSTR (symbol, 0); - HOST_WIDE_INT size; + unsigned int align; /* Make sure any other constants whose addresses appear in EXP are assigned label numbers. */ - int reloc = compute_reloc_for_constant (exp); - - /* Align the location counter as required by EXP's data type. */ - unsigned int align = TYPE_ALIGN (TREE_TYPE (exp)); -#ifdef CONSTANT_ALIGNMENT - align = CONSTANT_ALIGNMENT (exp, align); -#endif - output_addressed_constants (exp); /* We are no longer deferring this constant. */ TREE_ASM_WRITTEN (exp) = 1; - if (IN_NAMED_SECTION (exp)) - switch_to_section (get_named_section (exp, NULL, reloc)); + /* If the constant is part of an object block, make sure that the + decl has been positioned within its block, but do not write out + its definition yet. output_object_blocks will do that later. */ + if (SYMBOL_REF_HAS_BLOCK_INFO_P (symbol) && SYMBOL_REF_BLOCK (symbol)) + place_block_symbol (symbol); else - switch_to_section (targetm.asm_out.select_section (exp, reloc, align)); - - if (align > BITS_PER_UNIT) { - ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT)); + switch_to_section (get_constant_section (exp)); + align = get_constant_alignment (exp); + if (align > BITS_PER_UNIT) + ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT)); + assemble_constant_contents (exp, XSTR (symbol, 0), align); } - - size = int_size_in_bytes (TREE_TYPE (exp)); - if (TREE_CODE (exp) == STRING_CST) - size = MAX (TREE_STRING_LENGTH (exp), size); - - /* Do any machine/system dependent processing of the constant. */ -#ifdef ASM_DECLARE_CONSTANT_NAME - ASM_DECLARE_CONSTANT_NAME (asm_out_file, label, exp, size); -#else - /* Standard thing is just output label for the constant. */ - ASM_OUTPUT_LABEL (asm_out_file, label); -#endif /* ASM_DECLARE_CONSTANT_NAME */ - - /* Output the value of EXP. */ - output_constant (exp, size, align); if (flag_mudflap) mudflap_enqueue_constant (exp); } @@ -2836,6 +3390,10 @@ const_rtx_hash_1 (rtx *xp, void *data) h ^= real_hash (CONST_DOUBLE_REAL_VALUE (x)); break; + case CONST_FIXED: + h ^= fixed_hash (CONST_FIXED_VALUE (x)); + break; + case CONST_VECTOR: { int i; @@ -2877,25 +3435,29 @@ const_rtx_hash (rtx x) } -/* Initialize constant pool hashing for a new function. */ +/* Create and return a new rtx constant pool. */ -void -init_varasm_status (struct function *f) +static struct rtx_constant_pool * +create_constant_pool (void) { - struct varasm_status *p; struct rtx_constant_pool *pool; - p = ggc_alloc (sizeof (struct varasm_status)); - f->varasm = p; - pool = ggc_alloc (sizeof (struct rtx_constant_pool)); - p->pool = pool; - p->deferred_constants = 0; - pool->const_rtx_htab = htab_create_ggc (31, const_desc_rtx_hash, const_desc_rtx_eq, NULL); - pool->first = pool->last = NULL; + pool->first = NULL; + pool->last = NULL; pool->offset = 0; + return pool; +} + +/* Initialize constant pool hashing for a new function. */ + +void +init_varasm_status (void) +{ + crtl->varasm.pool = create_constant_pool (); + crtl->varasm.deferred_constants = 0; } /* Given a MINUS expression, simplify it if both sides @@ -2915,7 +3477,7 @@ rtx force_const_mem (enum machine_mode mode, rtx x) { struct constant_descriptor_rtx *desc, tmp; - struct rtx_constant_pool *pool = cfun->varasm->pool; + struct rtx_constant_pool *pool; char label[256]; rtx def, symbol; hashval_t hash; @@ -2926,6 +3488,14 @@ force_const_mem (enum machine_mode mode, rtx x) if (targetm.cannot_force_const_mem (x)) return NULL_RTX; + /* Record that this function has used a constant pool entry. */ + current_function_uses_const_pool = 1; + + /* Decide which pool to use. */ + pool = (targetm.use_blocks_for_constant_p (mode, x) + ? shared_constant_pool + : crtl->varasm.pool); + /* Lookup the value in the hashtable. */ tmp.constant = x; tmp.mode = mode; @@ -2976,11 +3546,18 @@ force_const_mem (enum machine_mode mode, rtx x) /* Construct the SYMBOL_REF. Make sure to mark it as belonging to the constants pool. */ - desc->sym = symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label)); - SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOCAL; + if (use_object_blocks_p () && targetm.use_blocks_for_constant_p (mode, x)) + { + section *sect = targetm.asm_out.select_rtx_section (mode, x, align); + symbol = create_block_symbol (ggc_strdup (label), + get_block_for_section (sect), -1); + } + else + symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label)); + desc->sym = symbol; + SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_LOCAL; CONSTANT_POOL_ADDRESS_P (symbol) = 1; SET_SYMBOL_REF_CONSTANT (symbol, desc); - current_function_uses_const_pool = 1; /* Construct the MEM. */ desc->mem = def = gen_const_mem (mode, symbol); @@ -3019,7 +3596,7 @@ get_pool_constant_mark (rtx addr, bool *pmarked) /* Similar, return the mode. */ enum machine_mode -get_pool_mode (rtx addr) +get_pool_mode (const_rtx addr) { return SYMBOL_REF_CONSTANT (addr)->mode; } @@ -3029,7 +3606,7 @@ get_pool_mode (rtx addr) int get_pool_size (void) { - return cfun->varasm->pool->offset; + return crtl->varasm.pool->offset; } /* Worker function for output_constant_pool_1. Emit assembly for X @@ -3053,11 +3630,19 @@ output_constant_pool_2 (enum machine_mode mode, rtx x, unsigned int align) case MODE_INT: case MODE_PARTIAL_INT: + case MODE_FRACT: + case MODE_UFRACT: + case MODE_ACCUM: + case MODE_UACCUM: assemble_integer (x, GET_MODE_SIZE (mode), align, 1); break; case MODE_VECTOR_FLOAT: case MODE_VECTOR_INT: + case MODE_VECTOR_FRACT: + case MODE_VECTOR_UFRACT: + case MODE_VECTOR_ACCUM: + case MODE_VECTOR_UACCUM: { int i, units; enum machine_mode submode = GET_MODE_INNER (mode); @@ -3079,15 +3664,15 @@ output_constant_pool_2 (enum machine_mode mode, rtx x, unsigned int align) } } -/* Worker function for output_constant_pool. Emit POOL. */ +/* Worker function for output_constant_pool. Emit constant DESC, + giving it ALIGN bits of alignment. */ static void -output_constant_pool_1 (struct constant_descriptor_rtx *desc) +output_constant_pool_1 (struct constant_descriptor_rtx *desc, + unsigned int align) { rtx x, tmp; - if (!desc->mark) - return; x = desc->constant; /* See if X is a LABEL_REF (or a CONST referring to a LABEL_REF) @@ -3100,49 +3685,45 @@ output_constant_pool_1 (struct constant_descriptor_rtx *desc) functioning even with INSN_DELETED_P and friends. */ tmp = x; - switch (GET_CODE (x)) + switch (GET_CODE (tmp)) { case CONST: - if (GET_CODE (XEXP (x, 0)) != PLUS - || GET_CODE (XEXP (XEXP (x, 0), 0)) != LABEL_REF) + if (GET_CODE (XEXP (tmp, 0)) != PLUS + || GET_CODE (XEXP (XEXP (tmp, 0), 0)) != LABEL_REF) break; - tmp = XEXP (XEXP (x, 0), 0); + tmp = XEXP (XEXP (tmp, 0), 0); /* FALLTHRU */ case LABEL_REF: - tmp = XEXP (x, 0); + tmp = XEXP (tmp, 0); gcc_assert (!INSN_DELETED_P (tmp)); gcc_assert (!NOTE_P (tmp) - || NOTE_LINE_NUMBER (tmp) != NOTE_INSN_DELETED); + || NOTE_KIND (tmp) != NOTE_INSN_DELETED); break; default: break; } - /* First switch to correct section. */ - switch_to_section (targetm.asm_out.select_rtx_section (desc->mode, x, - desc->align)); - #ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY ASM_OUTPUT_SPECIAL_POOL_ENTRY (asm_out_file, x, desc->mode, - desc->align, desc->labelno, done); + align, desc->labelno, done); #endif - assemble_align (desc->align); + assemble_align (align); /* Output the label. */ targetm.asm_out.internal_label (asm_out_file, "LC", desc->labelno); /* Output the data. */ - output_constant_pool_2 (desc->mode, x, desc->align); + output_constant_pool_2 (desc->mode, x, align); /* Make sure all constants in SECTION_MERGE and not SECTION_STRINGS sections have proper size. */ - if (desc->align > GET_MODE_BITSIZE (desc->mode) + if (align > GET_MODE_BITSIZE (desc->mode) && in_section && (in_section->common.flags & SECTION_MERGE)) - assemble_align (desc->align); + assemble_align (align); #ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY done: @@ -3155,9 +3736,8 @@ output_constant_pool_1 (struct constant_descriptor_rtx *desc) be used with for_each_rtx to mark all SYMBOL_REFs in an rtx. */ static int -mark_constant (rtx *current_rtx, void *data) +mark_constant (rtx *current_rtx, void *data ATTRIBUTE_UNUSED) { - struct rtx_constant_pool *pool = data; rtx x = *current_rtx; if (x == NULL_RTX || GET_CODE (x) != SYMBOL_REF) @@ -3169,7 +3749,7 @@ mark_constant (rtx *current_rtx, void *data) if (desc->mark == 0) { desc->mark = 1; - for_each_rtx (&desc->constant, mark_constant, pool); + for_each_rtx (&desc->constant, mark_constant, NULL); } } else if (TREE_CONSTANT_POOL_ADDRESS_P (x)) @@ -3191,7 +3771,7 @@ mark_constant (rtx *current_rtx, void *data) deferred strings that are used. */ static void -mark_constants (struct rtx_constant_pool *pool, rtx insn) +mark_constants (rtx insn) { if (!INSN_P (insn)) return; @@ -3207,11 +3787,11 @@ mark_constants (struct rtx_constant_pool *pool, rtx insn) { rtx subinsn = XVECEXP (seq, 0, i); if (INSN_P (subinsn)) - for_each_rtx (&PATTERN (subinsn), mark_constant, pool); + for_each_rtx (&PATTERN (subinsn), mark_constant, NULL); } } else - for_each_rtx (&PATTERN (insn), mark_constant, pool); + for_each_rtx (&PATTERN (insn), mark_constant, NULL); } /* Look through the instructions for this function, and mark all the @@ -3219,48 +3799,81 @@ mark_constants (struct rtx_constant_pool *pool, rtx insn) which have indeed been used. */ static void -mark_constant_pool (struct rtx_constant_pool *pool) +mark_constant_pool (void) { rtx insn, link; - if (pool->first == 0 && n_deferred_constants == 0) + if (!current_function_uses_const_pool && n_deferred_constants == 0) return; for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - mark_constants (pool, insn); + mark_constants (insn); for (link = current_function_epilogue_delay_list; link; link = XEXP (link, 1)) - mark_constants (pool, XEXP (link, 0)); + mark_constants (XEXP (link, 0)); } -/* Write all the constants in the constant pool. */ +/* Write all the constants in POOL. */ -void +static void +output_constant_pool_contents (struct rtx_constant_pool *pool) +{ + struct constant_descriptor_rtx *desc; + + for (desc = pool->first; desc ; desc = desc->next) + if (desc->mark) + { + /* If the constant is part of an object_block, make sure that + the constant has been positioned within its block, but do not + write out its definition yet. output_object_blocks will do + that later. */ + if (SYMBOL_REF_HAS_BLOCK_INFO_P (desc->sym) + && SYMBOL_REF_BLOCK (desc->sym)) + place_block_symbol (desc->sym); + else + { + switch_to_section (targetm.asm_out.select_rtx_section + (desc->mode, desc->constant, desc->align)); + output_constant_pool_1 (desc, desc->align); + } + } +} + +/* Mark all constants that are used in the current function, then write + out the function's private constant pool. */ + +static void output_constant_pool (const char *fnname ATTRIBUTE_UNUSED, tree fndecl ATTRIBUTE_UNUSED) { - struct rtx_constant_pool *pool = cfun->varasm->pool; - struct constant_descriptor_rtx *desc; + struct rtx_constant_pool *pool = crtl->varasm.pool; /* It is possible for gcc to call force_const_mem and then to later discard the instructions which refer to the constant. In such a case we do not need to output the constant. */ - mark_constant_pool (pool); + mark_constant_pool (); #ifdef ASM_OUTPUT_POOL_PROLOGUE ASM_OUTPUT_POOL_PROLOGUE (asm_out_file, fnname, fndecl, pool->offset); #endif - for (desc = pool->first; desc ; desc = desc->next) - output_constant_pool_1 (desc); + output_constant_pool_contents (pool); #ifdef ASM_OUTPUT_POOL_EPILOGUE ASM_OUTPUT_POOL_EPILOGUE (asm_out_file, fnname, fndecl, pool->offset); #endif } +/* Write the contents of the shared constant pool. */ + +void +output_shared_constant_pool (void) +{ + output_constant_pool_contents (shared_constant_pool); +} + /* Determine what kind of relocations EXP may need. */ int @@ -3269,10 +3882,6 @@ compute_reloc_for_constant (tree exp) int reloc = 0, reloc2; tree tem; - /* Give the front-end a chance to convert VALUE to something that - looks more like a constant to the back-end. */ - exp = lang_hooks.expand_constant (exp); - switch (TREE_CODE (exp)) { case ADDR_EXPR: @@ -3291,6 +3900,7 @@ compute_reloc_for_constant (tree exp) break; case PLUS_EXPR: + case POINTER_PLUS_EXPR: reloc = compute_reloc_for_constant (TREE_OPERAND (exp, 0)); reloc |= compute_reloc_for_constant (TREE_OPERAND (exp, 1)); break; @@ -3336,10 +3946,6 @@ output_addressed_constants (tree exp) { tree tem; - /* Give the front-end a chance to convert VALUE to something that - looks more like a constant to the back-end. */ - exp = lang_hooks.expand_constant (exp); - switch (TREE_CODE (exp)) { case ADDR_EXPR: @@ -3360,6 +3966,7 @@ output_addressed_constants (tree exp) break; case PLUS_EXPR: + case POINTER_PLUS_EXPR: case MINUS_EXPR: output_addressed_constants (TREE_OPERAND (exp, 1)); /* Fall through. */ @@ -3385,6 +3992,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 (const_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. @@ -3398,17 +4019,10 @@ output_addressed_constants (tree exp) tree initializer_constant_valid_p (tree value, tree endtype) { - /* Give the front-end a chance to convert VALUE to something that - looks more like a constant to the back-end. */ - value = lang_hooks.expand_constant (value); - 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; @@ -3434,6 +4048,7 @@ initializer_constant_valid_p (tree value, tree endtype) case INTEGER_CST: case VECTOR_CST: case REAL_CST: + case FIXED_CST: case STRING_CST: case COMPLEX_CST: return null_pointer_node; @@ -3450,9 +4065,8 @@ initializer_constant_valid_p (tree value, tree endtype) return null_pointer_node; /* Taking the address of a nested function involves a trampoline. */ if (TREE_CODE (value) == FUNCTION_DECL - && ((decl_function_context (value) - && !DECL_NO_STATIC_CHAIN (value)) - || DECL_DLLIMPORT_P (value))) + && decl_function_context (value) + && !DECL_NO_STATIC_CHAIN (value)) return NULL_TREE; /* "&{...}" requires a temporary to hold the constructed object. */ @@ -3527,6 +4141,7 @@ initializer_constant_valid_p (tree value, tree endtype) } break; + case POINTER_PLUS_EXPR: case PLUS_EXPR: if (! INTEGRAL_TYPE_P (endtype) || TYPE_PRECISION (endtype) >= POINTER_SIZE) @@ -3535,7 +4150,7 @@ initializer_constant_valid_p (tree value, tree endtype) endtype); tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1), endtype); - /* If either term is absolute, use the other terms relocation. */ + /* If either term is absolute, use the other term's relocation. */ if (valid0 == null_pointer_node) return valid1; if (valid1 == null_pointer_node) @@ -3662,11 +4277,6 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align) enum tree_code code; unsigned HOST_WIDE_INT thissize; - /* Some front-ends use constants other than the standard language-independent - varieties, but which may still be output directly. Give the front-end a - chance to convert EXP to a language-independent representation. */ - exp = lang_hooks.expand_constant (exp); - if (size == 0 || flag_syntax_only) return; @@ -3714,10 +4324,10 @@ 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)); @@ -3754,10 +4364,11 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align) case POINTER_TYPE: case REFERENCE_TYPE: case OFFSET_TYPE: + case FIXED_POINT_TYPE: if (! assemble_integer (expand_expr (exp, NULL_RTX, VOIDmode, EXPAND_INITIALIZER), MIN (size, thissize), align, 0)) - error ("initializer for integer value is too complicated"); + error ("initializer for integer/fixed-point value is too complicated"); break; case REAL_TYPE: @@ -3800,8 +4411,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: @@ -3836,7 +4451,7 @@ array_size_for_constructor (tree val) { tree max_index, i; unsigned HOST_WIDE_INT cnt; - tree index, value; + tree index, value, tmp; /* This code used to attempt to handle string constants that are not arrays of single-bytes, but nothing else does, so there's no point in @@ -3857,9 +4472,9 @@ array_size_for_constructor (tree val) return 0; /* Compute the total number of array elements. */ - i = size_binop (MINUS_EXPR, convert (sizetype, max_index), - convert (sizetype, - TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (val))))); + tmp = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (val))); + i = size_binop (MINUS_EXPR, fold_convert (sizetype, max_index), + fold_convert (sizetype, tmp)); i = size_binop (PLUS_EXPR, i, build_int_cst (sizetype, 1)); /* Multiply by the array element unit size to find number of bytes. */ @@ -4227,7 +4842,7 @@ merge_weak (tree newdecl, tree olddecl) /* NEWDECL is weak, but OLDDECL is not. */ /* If we already output the OLDDECL, we're in trouble; we can't - go back and make it weak. This error cannot caught in + go back and make it weak. This error cannot be caught in declare_weak because the NEWDECL and OLDDECL was not yet been merged; therefore, TREE_ASM_WRITTEN was not set. */ if (TREE_ASM_WRITTEN (olddecl)) @@ -4345,7 +4960,7 @@ weak_finish (void) else if (! TREE_SYMBOL_REFERENCED (target)) { /* Use ASM_WEAKEN_LABEL only if ASM_WEAKEN_DECL is not - defined, otherwise we and weak_finish_1 would use a + defined, otherwise we and weak_finish_1 would use different macros. */ # if defined ASM_WEAKEN_LABEL && ! defined ASM_WEAKEN_DECL ASM_WEAKEN_LABEL (asm_out_file, IDENTIFIER_POINTER (target)); @@ -4409,11 +5024,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 @@ -4426,31 +5041,28 @@ globalize_decl (tree decl) we do not emit multiple .weak directives for it. */ for (p = &weak_decls; (t = *p) ; ) { - if (DECL_ASSEMBLER_NAME (decl) == DECL_ASSEMBLER_NAME (TREE_VALUE (t))) + if (DECL_ASSEMBLER_NAME (decl) == DECL_ASSEMBLER_NAME (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); } - /* 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 @@ -4476,17 +5088,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); } @@ -4504,7 +5116,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 @@ -4528,6 +5140,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); @@ -4545,6 +5165,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. */ @@ -4697,10 +5325,10 @@ 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. */ + alias. This saves a tad of memory. */ target_decl = find_decl_and_mark_needed (decl, target); if (target_decl && TREE_ASM_WRITTEN (target_decl)) do_assemble_alias (decl, target); @@ -4719,7 +5347,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; @@ -4739,13 +5367,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 @@ -4794,10 +5427,13 @@ init_varasm_once (void) { section_htab = htab_create_ggc (31, section_entry_hash, section_entry_eq, NULL); + object_block_htab = htab_create_ggc (31, object_block_entry_hash, + object_block_entry_eq, NULL); const_desc_htab = htab_create_ggc (1009, const_desc_hash, const_desc_eq, NULL); const_alias_set = new_alias_set (); + shared_constant_pool = create_constant_pool (); #ifdef TEXT_SECTION_ASM_OP text_section = get_unnamed_section (SECTION_CODE, output_section_asm_op, @@ -4841,6 +5477,18 @@ init_varasm_once (void) SBSS_SECTION_ASM_OP); #endif + tls_comm_section = get_noswitch_section (SECTION_WRITE | SECTION_BSS + | SECTION_COMMON, emit_tls_common); + lcomm_section = get_noswitch_section (SECTION_WRITE | SECTION_BSS + | SECTION_COMMON, emit_local); + comm_section = get_noswitch_section (SECTION_WRITE | SECTION_BSS + | SECTION_COMMON, emit_common); + +#if defined ASM_OUTPUT_ALIGNED_BSS || defined ASM_OUTPUT_BSS + bss_noswitch_section = get_noswitch_section (SECTION_WRITE | SECTION_BSS, + emit_bss); +#endif + targetm.asm_out.init_sections (); if (readonly_data_section == NULL) @@ -4848,7 +5496,7 @@ init_varasm_once (void) } enum tls_model -decl_default_tls_model (tree decl) +decl_default_tls_model (const_tree decl) { enum tls_model kind; bool is_local; @@ -4884,23 +5532,16 @@ 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 - && cfun->unlikely_text_section_name - && strcmp (name, cfun->unlikely_text_section_name) == 0) + && crtl->subsections.unlikely_text_section_name + && strcmp (name, crtl->subsections.unlikely_text_section_name) == 0) flags = SECTION_CODE; else if (!decl && (!current_function_decl || !cfun) @@ -4947,6 +5588,16 @@ default_section_type_flags_1 (tree decl, const char *name, int reloc, return flags; } +/* Return true if the target supports some form of global BSS, + either through bss_noswitch_section, or by selecting a BSS + section in TARGET_ASM_SELECT_SECTION. */ + +bool +have_global_bss_p (void) +{ + return bss_noswitch_section || targetm.have_switchable_bss_sections; +} + /* Output assembly to switch to section NAME with attribute FLAGS. Four variants for common object file formats. */ @@ -5085,7 +5736,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 (const_tree decl, int reloc) { enum section_category ret; @@ -5100,28 +5751,23 @@ categorize_decl_for_section (tree decl, int reloc, int shlib) } else if (TREE_CODE (decl) == VAR_DECL) { - if (DECL_INITIAL (decl) == NULL - || DECL_INITIAL (decl) == error_mark_node - || (flag_zero_initialized_in_bss - /* Leave constant zeroes in .rodata so they can be shared. */ - && !TREE_READONLY (decl) - && initializer_zerop (DECL_INITIAL (decl)))) + if (bss_initializer_p (decl)) ret = SECCAT_BSS; else if (! TREE_READONLY (decl) || 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 @@ -5134,7 +5780,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; @@ -5172,15 +5818,9 @@ 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) +decl_readonly_section (const_tree decl, int reloc) { - switch (categorize_decl_for_section (decl, reloc, shlib)) + switch (categorize_decl_for_section (decl, reloc)) { case SECCAT_RODATA: case SECCAT_RODATA_MERGE_STR: @@ -5201,15 +5841,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. */ @@ -5271,19 +5904,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."; @@ -5344,45 +5971,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); } @@ -5402,12 +6060,13 @@ default_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED) if (GET_CODE (symbol) != SYMBOL_REF) return; - flags = 0; + flags = SYMBOL_REF_FLAGS (symbol) & SYMBOL_FLAG_HAS_BLOCK_INFO; if (TREE_CODE (decl) == FUNCTION_DECL) 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; @@ -5429,17 +6088,70 @@ default_strip_name_encoding (const char *str) return str + (*str == '*'); } +#ifdef ASM_OUTPUT_DEF +/* The default implementation of TARGET_ASM_OUTPUT_ANCHOR. Define the + anchor relative to ".", the current section position. */ + +void +default_asm_output_anchor (rtx symbol) +{ + char buffer[100]; + + sprintf (buffer, "*. + " HOST_WIDE_INT_PRINT_DEC, + SYMBOL_REF_BLOCK_OFFSET (symbol)); + ASM_OUTPUT_DEF (asm_out_file, XSTR (symbol, 0), buffer); +} +#endif + +/* The default implementation of TARGET_USE_ANCHORS_FOR_SYMBOL_P. */ + +bool +default_use_anchors_for_symbol_p (const_rtx symbol) +{ + section *sect; + tree decl; + + /* Don't use anchors for mergeable sections. The linker might move + the objects around. */ + sect = SYMBOL_REF_BLOCK (symbol)->sect; + if (sect->common.flags & SECTION_MERGE) + return false; + + /* Don't use anchors for small data sections. The small data register + acts as an anchor for such sections. */ + if (sect->common.flags & SECTION_SMALL) + return false; + + decl = SYMBOL_REF_DECL (symbol); + if (decl && DECL_P (decl)) + { + /* Don't use section anchors for decls that might be defined by + other modules. */ + if (!targetm.binds_local_p (decl)) + return false; + + /* Don't use section anchors for decls that will be placed in a + small data section. */ + /* ??? Ideally, this check would be redundant with the SECTION_SMALL + one above. The problem is that we only use SECTION_SMALL for + sections that should be marked as small in the section directive. */ + if (targetm.in_small_data_p (decl)) + return false; + } + return true; +} + /* Assume ELF-ish defaults, since that's pretty much the most liberal wrt cross-module name binding. */ bool -default_binds_local_p (tree exp) +default_binds_local_p (const_tree exp) { return default_binds_local_p_1 (exp, flag_shlib); } bool -default_binds_local_p_1 (tree exp, int shlib) +default_binds_local_p_1 (const_tree exp, int shlib) { bool local_p; @@ -5470,9 +6182,10 @@ default_binds_local_p_1 (tree exp, int shlib) else if (DECL_WEAK (exp)) local_p = false; /* If PIC, then assume that any global name can be overridden by - symbols resolved from other modules. */ + symbols resolved from other modules, unless we are compiling with + -fwhole-program, which assumes that names are local. */ else if (shlib) - local_p = false; + local_p = flag_whole_program; /* Uninitialized COMMON variable may be unified with symbols resolved from other modules. */ else if (DECL_COMMON (exp) @@ -5508,6 +6221,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. */ @@ -5591,22 +6312,350 @@ switch_to_section (section *new_section) else in_section = new_section; - if (new_section->common.flags & SECTION_NAMED) + switch (SECTION_STYLE (new_section)) { + case SECTION_NAMED: if (cfun - && !cfun->unlikely_text_section_name + && !crtl->subsections.unlikely_text_section_name && strcmp (new_section->named.name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0) - cfun->unlikely_text_section_name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME; + crtl->subsections.unlikely_text_section_name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME; targetm.asm_out.named_section (new_section->named.name, new_section->named.common.flags, new_section->named.decl); + break; + + case SECTION_UNNAMED: + new_section->unnamed.callback (new_section->unnamed.data); + break; + + case SECTION_NOSWITCH: + gcc_unreachable (); + break; } - else - new_section->unnamed.callback (new_section->unnamed.data); new_section->common.flags |= SECTION_DECLARED; } +/* If block symbol SYMBOL has not yet been assigned an offset, place + it at the end of its block. */ + +void +place_block_symbol (rtx symbol) +{ + unsigned HOST_WIDE_INT size, mask, offset; + struct constant_descriptor_rtx *desc; + unsigned int alignment; + struct object_block *block; + tree decl; + + gcc_assert (SYMBOL_REF_BLOCK (symbol)); + if (SYMBOL_REF_BLOCK_OFFSET (symbol) >= 0) + return; + + /* Work out the symbol's size and alignment. */ + if (CONSTANT_POOL_ADDRESS_P (symbol)) + { + desc = SYMBOL_REF_CONSTANT (symbol); + alignment = desc->align; + size = GET_MODE_SIZE (desc->mode); + } + else if (TREE_CONSTANT_POOL_ADDRESS_P (symbol)) + { + decl = SYMBOL_REF_DECL (symbol); + alignment = get_constant_alignment (decl); + size = get_constant_size (decl); + } + else + { + decl = SYMBOL_REF_DECL (symbol); + alignment = DECL_ALIGN (decl); + size = tree_low_cst (DECL_SIZE_UNIT (decl), 1); + } + + /* Calculate the object's offset from the start of the block. */ + block = SYMBOL_REF_BLOCK (symbol); + mask = alignment / BITS_PER_UNIT - 1; + offset = (block->size + mask) & ~mask; + SYMBOL_REF_BLOCK_OFFSET (symbol) = offset; + + /* Record the block's new alignment and size. */ + block->alignment = MAX (block->alignment, alignment); + block->size = offset + size; + + VEC_safe_push (rtx, gc, block->objects, symbol); +} + +/* Return the anchor that should be used to address byte offset OFFSET + from the first object in BLOCK. MODEL is the TLS model used + to access it. */ + +rtx +get_section_anchor (struct object_block *block, HOST_WIDE_INT offset, + enum tls_model model) +{ + char label[100]; + unsigned int begin, middle, end; + unsigned HOST_WIDE_INT min_offset, max_offset, range, bias, delta; + rtx anchor; + + /* Work out the anchor's offset. Use an offset of 0 for the first + anchor so that we don't pessimize the case where we take the address + of a variable at the beginning of the block. This is particularly + useful when a block has only one variable assigned to it. + + We try to place anchors RANGE bytes apart, so there can then be + anchors at +/-RANGE, +/-2 * RANGE, and so on, up to the limits of + a ptr_mode offset. With some target settings, the lowest such + anchor might be out of range for the lowest ptr_mode offset; + likewise the highest anchor for the highest offset. Use anchors + at the extreme ends of the ptr_mode range in such cases. + + All arithmetic uses unsigned integers in order to avoid + signed overflow. */ + max_offset = (unsigned HOST_WIDE_INT) targetm.max_anchor_offset; + min_offset = (unsigned HOST_WIDE_INT) targetm.min_anchor_offset; + range = max_offset - min_offset + 1; + if (range == 0) + offset = 0; + else + { + bias = 1 << (GET_MODE_BITSIZE (ptr_mode) - 1); + if (offset < 0) + { + delta = -(unsigned HOST_WIDE_INT) offset + max_offset; + delta -= delta % range; + if (delta > bias) + delta = bias; + offset = (HOST_WIDE_INT) (-delta); + } + else + { + delta = (unsigned HOST_WIDE_INT) offset - min_offset; + delta -= delta % range; + if (delta > bias - 1) + delta = bias - 1; + offset = (HOST_WIDE_INT) delta; + } + } + + /* Do a binary search to see if there's already an anchor we can use. + Set BEGIN to the new anchor's index if not. */ + begin = 0; + end = VEC_length (rtx, block->anchors); + while (begin != end) + { + middle = (end + begin) / 2; + anchor = VEC_index (rtx, block->anchors, middle); + if (SYMBOL_REF_BLOCK_OFFSET (anchor) > offset) + end = middle; + else if (SYMBOL_REF_BLOCK_OFFSET (anchor) < offset) + begin = middle + 1; + else if (SYMBOL_REF_TLS_MODEL (anchor) > model) + end = middle; + else if (SYMBOL_REF_TLS_MODEL (anchor) < model) + begin = middle + 1; + else + return anchor; + } + + /* Create a new anchor with a unique label. */ + ASM_GENERATE_INTERNAL_LABEL (label, "LANCHOR", anchor_labelno++); + anchor = create_block_symbol (ggc_strdup (label), block, offset); + SYMBOL_REF_FLAGS (anchor) |= SYMBOL_FLAG_LOCAL | SYMBOL_FLAG_ANCHOR; + SYMBOL_REF_FLAGS (anchor) |= model << SYMBOL_FLAG_TLS_SHIFT; + + /* Insert it at index BEGIN. */ + VEC_safe_insert (rtx, gc, block->anchors, begin, anchor); + return anchor; +} + +/* Output the objects in BLOCK. */ + +static void +output_object_block (struct object_block *block) +{ + struct constant_descriptor_rtx *desc; + unsigned int i; + HOST_WIDE_INT offset; + tree decl; + rtx symbol; + + if (block->objects == NULL) + return; + + /* Switch to the section and make sure that the first byte is + suitably aligned. */ + switch_to_section (block->sect); + assemble_align (block->alignment); + + /* Define the values of all anchors relative to the current section + position. */ + for (i = 0; VEC_iterate (rtx, block->anchors, i, symbol); i++) + targetm.asm_out.output_anchor (symbol); + + /* Output the objects themselves. */ + offset = 0; + for (i = 0; VEC_iterate (rtx, block->objects, i, symbol); i++) + { + /* Move to the object's offset, padding with zeros if necessary. */ + assemble_zeros (SYMBOL_REF_BLOCK_OFFSET (symbol) - offset); + offset = SYMBOL_REF_BLOCK_OFFSET (symbol); + if (CONSTANT_POOL_ADDRESS_P (symbol)) + { + desc = SYMBOL_REF_CONSTANT (symbol); + output_constant_pool_1 (desc, 1); + offset += GET_MODE_SIZE (desc->mode); + } + else if (TREE_CONSTANT_POOL_ADDRESS_P (symbol)) + { + decl = SYMBOL_REF_DECL (symbol); + assemble_constant_contents (decl, XSTR (symbol, 0), + get_constant_alignment (decl)); + offset += get_constant_size (decl); + } + else + { + decl = SYMBOL_REF_DECL (symbol); + assemble_variable_contents (decl, XSTR (symbol, 0), false); + offset += tree_low_cst (DECL_SIZE_UNIT (decl), 1); + } + } +} + +/* A htab_traverse callback used to call output_object_block for + each member of object_block_htab. */ + +static int +output_object_block_htab (void **slot, void *data ATTRIBUTE_UNUSED) +{ + output_object_block ((struct object_block *) (*slot)); + return 1; +} + +/* Output the definitions of all object_blocks. */ + +void +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"