/* 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
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
This file is part of GCC.
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);
\f
/* Well-known sections, each one associated with some sort of *_ASM_OP. */
section *text_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. */
/* 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;
+
/* Helper routines for maintaining section_htab. */
static int
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 *
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;
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. */
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)
{
return (name
&& sect
- && (sect->common.flags & SECTION_NAMED) != 0
+ && SECTION_STYLE (sect) == SECTION_NAMED
&& strcmp (name, sect->named.name) == 0);
}
function_section (tree decl)
{
int reloc = 0;
-
+
if (first_function_block_is_cold)
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
}
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 ()
{
size_t len = strlen (name) + 3;
char* rname = alloca (len);
-
+
strcpy (rname, ".rodata");
strcat (rname, name + 5);
return get_section (rname, SECTION_LINKONCE, decl);
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 *
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)));
align = modesize;
str = TREE_STRING_POINTER (decl);
- len = TREE_STRING_LENGTH (decl);
unit = GET_MODE_SIZE (mode);
/* Check for embedded NUL characters. */
return -1;
}
\f
+/* Return true if DECL's initializer is suitable for a BSS section. */
+
+static bool
+bss_initializer_p (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
+ align = DATA_ALIGNMENT (TREE_TYPE (decl), align);
+#endif
+#ifdef CONSTANT_ALIGNMENT
+ if (DECL_INITIAL (decl) != 0 && DECL_INITIAL (decl) != error_mark_node)
+ align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl), align);
+#endif
+ }
+
+ /* Reset the alignment in case we have made it tighter, so we can benefit
+ from it in get_pointer_alignment. */
+ DECL_ALIGN (decl) = align;
+}
+
+/* Return the section into which the given VAR_DECL or CONST_DECL
+ should be placed. PREFER_NOSWITCH_P is true if a noswitch
+ section should be used wherever possible. */
+
+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;
+
+ 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.
|| TREE_PUBLIC (decl)
|| DECL_EXTERNAL (decl)
|| DECL_REGISTER (decl));
-
+
/* And that we were not given a type or a label. */
gcc_assert (TREE_CODE (decl) != TYPE_DECL
&& TREE_CODE (decl) != LABEL_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;
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);
}
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-
+
if (name[0] != '*' && TREE_CODE (decl) != FUNCTION_DECL
&& DECL_REGISTER (decl))
{
- error ("register name not specified for %q+D", decl);
+ error ("register name not specified for %q+D", decl);
}
else if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (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);
- SYMBOL_REF_DECL (x) = decl;
+ SET_SYMBOL_REF_DECL (x, decl);
x = gen_rtx_MEM (DECL_MODE (decl), x);
if (TREE_CODE (decl) != FUNCTION_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
bool hot_label_written = false;
cfun->unlikely_text_section_name = NULL;
-
+
first_function_block_is_cold = false;
if (flag_reorder_blocks_and_partition)
{
initialize_cold_section_name ();
- if (cfun->unlikely_text_section_name
+ if (cfun->unlikely_text_section_name
&& strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
cfun->unlikely_text_section_name) == 0)
first_function_block_is_cold = true;
/* Switch to the correct text section for the start of the function. */
switch_to_section (function_section (decl));
- if (flag_reorder_blocks_and_partition
+ if (flag_reorder_blocks_and_partition
&& !hot_label_written)
ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_label);
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. */
}
\f
-#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;
- switch (destination)
+ /* 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 */
+
+ 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.
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 (lang_hooks.decls.prepare_assemble_variable)
lang_hooks.decls.prepare_assemble_variable (decl);
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);
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);
}
}
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);
}
gcc_assert (!force);
-
+
return false;
}
\f
void
assemble_real (REAL_VALUE_TYPE d, enum machine_mode mode, unsigned int align)
{
- long data[4];
+ long data[4] = {0, 0, 0, 0};
int i;
int bitsize, nelts, nunits, units_per;
{
unsigned HOST_WIDE_INT idx;
tree value;
-
+
hi = 5 + int_size_in_bytes (TREE_TYPE (exp));
-
+
FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
if (value)
hi = hi * 603 + const_hash_1 (value);
-
+
return hi;
}
/* 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:
{
VEC(constructor_elt, gc) *v1, *v2;
unsigned HOST_WIDE_INT idx;
-
+
typecode = TREE_CODE (TREE_TYPE (t1));
if (typecode != TREE_CODE (TREE_TYPE (t2)))
return 0;
return 0;
}
}
-
+
return 1;
}
VEC(constructor_elt, gc) *v;
unsigned HOST_WIDE_INT idx;
tree purpose, value;
-
+
v = VEC_alloc(constructor_elt, gc, VEC_length(constructor_elt,
CONSTRUCTOR_ELTS (exp)));
FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (exp), idx, purpose, value)
default:
{
tree t = lang_hooks.expand_constant (exp);
-
- gcc_assert (t == exp);
+
+ gcc_assert (t != exp);
return copy_constant (t);
}
}
}
\f
+/* 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.
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;
- SYMBOL_REF_DECL (symbol) = desc->value;
+ 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;
rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)), symbol);
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);
}
constant addresses are restricted so that such constants must be stored
in memory. */
htab_t GTY((param_is (struct constant_descriptor_rtx))) const_rtx_htab;
- htab_t GTY((param_is (struct constant_descriptor_rtx))) const_rtx_sym_htab;
/* Current offset in constant pool (does not include any
machine-specific header). */
return rtx_equal_p (x->constant, y->constant);
}
-/* Hash and compare functions for const_rtx_sym_htab. */
-
-static hashval_t
-const_desc_rtx_sym_hash (const void *ptr)
-{
- const struct constant_descriptor_rtx *desc = ptr;
- return htab_hash_string (XSTR (desc->sym, 0));
-}
-
-static int
-const_desc_rtx_sym_eq (const void *a, const void *b)
-{
- const struct constant_descriptor_rtx *x = a;
- const struct constant_descriptor_rtx *y = b;
- return XSTR (x->sym, 0) == XSTR (y->sym, 0);
-}
-
/* This is the worker function for const_rtx_hash, called via for_each_rtx. */
static int
}
\f
+/* Create and return a new rtx constant pool. */
+
+static struct rtx_constant_pool *
+create_constant_pool (void)
+{
+ struct rtx_constant_pool *pool;
+
+ pool = ggc_alloc (sizeof (struct rtx_constant_pool));
+ pool->const_rtx_htab = htab_create_ggc (31, const_desc_rtx_hash,
+ const_desc_rtx_eq, NULL);
+ pool->first = NULL;
+ pool->last = NULL;
+ pool->offset = 0;
+ return pool;
+}
+
/* Initialize constant pool hashing for a new function. */
void
init_varasm_status (struct function *f)
{
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->pool = create_constant_pool ();
p->deferred_constants = 0;
-
- pool->const_rtx_htab = htab_create_ggc (31, const_desc_rtx_hash,
- const_desc_rtx_eq, NULL);
- pool->const_rtx_sym_htab = htab_create_ggc (31, const_desc_rtx_sym_hash,
- const_desc_rtx_sym_eq, NULL);
- pool->first = pool->last = NULL;
- pool->offset = 0;
}
\f
/* Given a MINUS expression, simplify it if both sides
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;
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
+ : cfun->varasm->pool);
+
/* Lookup the value in the hashtable. */
tmp.constant = x;
tmp.mode = mode;
hash = const_rtx_hash (x);
slot = htab_find_slot_with_hash (pool->const_rtx_htab, &tmp, hash, INSERT);
desc = *slot;
-
+
/* If the constant was already present, return its memory. */
if (desc)
return copy_rtx (desc->mem);
/* 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;
- current_function_uses_const_pool = 1;
-
- /* Insert the descriptor into the symbol cross-reference table too. */
- slot = htab_find_slot (pool->const_rtx_sym_htab, desc, INSERT);
- gcc_assert (!*slot);
- *slot = desc;
+ SET_SYMBOL_REF_CONSTANT (symbol, desc);
/* Construct the MEM. */
desc->mem = def = gen_const_mem (mode, symbol);
return copy_rtx (def);
}
\f
-/* Given a SYMBOL_REF with CONSTANT_POOL_ADDRESS_P true, return a pointer to
- the corresponding constant_descriptor_rtx structure. */
-
-static struct constant_descriptor_rtx *
-find_pool_constant (struct rtx_constant_pool *pool, rtx sym)
-{
- struct constant_descriptor_rtx tmp;
- tmp.sym = sym;
- return htab_find (pool->const_rtx_sym_htab, &tmp);
-}
-
/* Given a constant pool SYMBOL_REF, return the corresponding constant. */
rtx
get_pool_constant (rtx addr)
{
- return find_pool_constant (cfun->varasm->pool, addr)->constant;
+ return SYMBOL_REF_CONSTANT (addr)->constant;
}
/* Given a constant pool SYMBOL_REF, return the corresponding constant
{
struct constant_descriptor_rtx *desc;
- desc = find_pool_constant (cfun->varasm->pool, addr);
+ desc = SYMBOL_REF_CONSTANT (addr);
*pmarked = (desc->mark != 0);
return desc->constant;
}
-/* Likewise, but for the constant pool of a specific function. */
-
-rtx
-get_pool_constant_for_function (struct function *f, rtx addr)
-{
- return find_pool_constant (f->varasm->pool, addr)->constant;
-}
-
/* Similar, return the mode. */
enum machine_mode
get_pool_mode (rtx addr)
{
- return find_pool_constant (cfun->varasm->pool, addr)->mode;
+ return SYMBOL_REF_CONSTANT (addr)->mode;
}
/* Return the size of the constant pool. */
case MODE_DECIMAL_FLOAT:
{
REAL_VALUE_TYPE r;
-
+
gcc_assert (GET_CODE (x) == CONST_DOUBLE);
REAL_VALUE_FROM_CONST_DOUBLE (r, x);
assemble_real (r, mode, align);
break;
}
-
+
case MODE_INT:
case MODE_PARTIAL_INT:
assemble_integer (x, GET_MODE_SIZE (mode), align, 1);
}
}
-/* 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)
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:
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)
if (CONSTANT_POOL_ADDRESS_P (x))
{
- struct constant_descriptor_rtx *desc = find_pool_constant (pool, x);
+ struct constant_descriptor_rtx *desc = SYMBOL_REF_CONSTANT (x);
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))
}
return -1;
-}
+}
/* Look through appropriate parts of INSN, marking all entries in the
constant pool which are actually being used. Entries that are only
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;
{
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
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;
/* 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
}
\f
+/* Write the contents of the shared constant pool. */
+
+void
+output_shared_constant_pool (void)
+{
+ output_constant_pool_contents (shared_constant_pool);
+}
+\f
/* Determine what kind of relocations EXP may need. */
int
}
}
\f
+/* Whether a constructor CTOR is a valid static constant initializer if all
+ its elements are. This used to be internal to initializer_constant_valid_p
+ and has been exposed to let other functions like categorize_ctor_elements
+ evaluate the property while walking a constructor for other purposes. */
+
+bool
+constructor_static_from_elts_p (tree ctor)
+{
+ return (TREE_CONSTANT (ctor)
+ && (TREE_CODE (TREE_TYPE (ctor)) == UNION_TYPE
+ || TREE_CODE (TREE_TYPE (ctor)) == RECORD_TYPE)
+ && !VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (ctor)));
+}
+
/* Return nonzero if VALUE is a valid constant-valued expression
for use in initializing a static variable; one that can be an
element of a "constant" initializer.
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;
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_function_context (value)
&& !DECL_NO_STATIC_CHAIN (value))
|| DECL_DLLIMPORT_P (value)))
return NULL_TREE;
|| TREE_CODE (dest_type) == OFFSET_TYPE)
&& INTEGRAL_TYPE_P (src_type))
{
+ if (TREE_CODE (src) == INTEGER_CST
+ && TYPE_PRECISION (dest_type) >= TYPE_PRECISION (src_type))
+ return null_pointer_node;
if (integer_zerop (src))
return null_pointer_node;
else if (TYPE_PRECISION (dest_type) <= TYPE_PRECISION (src_type))
way. */
if (TREE_CODE (exp) == ADDR_EXPR)
exp = build1 (ADDR_EXPR, saved_type, TREE_OPERAND (exp, 0));
+ /* Likewise for constant ints. */
+ else if (TREE_CODE (exp) == INTEGER_CST)
+ exp = build_int_cst_wide (saved_type, TREE_INT_CST_LOW (exp),
+ TREE_INT_CST_HIGH (exp));
+
}
/* Eliminate any conversions since we'll be outputting the underlying
if (type_size > op_size
&& TREE_CODE (exp) != VIEW_CONVERT_EXPR
&& TREE_CODE (TREE_TYPE (exp)) != UNION_TYPE)
- internal_error ("no-op convert from %wd to %wd bytes in initializer",
- op_size, type_size);
-
- exp = TREE_OPERAND (exp, 0);
+ /* Keep the conversion. */
+ break;
+ else
+ exp = TREE_OPERAND (exp, 0);
}
code = TREE_CODE (TREE_TYPE (exp));
thissize = int_size_in_bytes (TREE_TYPE (exp));
+ /* Give the front end another chance to expand constants. */
+ exp = lang_hooks.expand_constant (exp);
+
/* Allow a constructor with no elements for any data type.
This means to fill the space with zeros. */
if (TREE_CODE (exp) == CONSTRUCTOR
Otherwise, break and ensure SIZE is the size written. */
switch (code)
{
- case CHAR_TYPE:
case BOOLEAN_TYPE:
case INTEGER_TYPE:
case ENUMERAL_TYPE:
tree link;
unsigned int nalign;
enum machine_mode inner;
-
+
inner = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
nalign = MIN (align, GET_MODE_ALIGNMENT (inner));
-
+
elt_size = GET_MODE_SIZE (inner);
-
+
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:
{
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
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. */
#ifdef ASM_COMMENT_START
if (field && flag_verbose_asm)
fprintf (asm_out_file, "%s %s:\n",
- ASM_COMMENT_START,
- DECL_NAME (field)
+ ASM_COMMENT_START,
+ DECL_NAME (field)
? IDENTIFIER_POINTER (DECL_NAME (field))
: "<anonymous>");
#endif
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;
}
cgraph_varpool_mark_needed_node (vnode);
return vnode->decl;
}
- else
+ else
return NULL_TREE;
}
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;
{
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,
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)
&& cfun->unlikely_text_section_name
&& strcmp (name, cfun->unlikely_text_section_name) == 0)
flags = SECTION_CODE;
- else if (!decl
+ else if (!decl
&& (!current_function_decl || !cfun)
&& strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0)
- flags = SECTION_CODE;
+ flags = SECTION_CODE;
else
flags = SECTION_WRITE;
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. */
if (flags & SECTION_ENTSIZE)
fprintf (asm_out_file, ",%d", flags & SECTION_ENTSIZE);
if (HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
- fprintf (asm_out_file, ",%s,comdat",
+ fprintf (asm_out_file, ",%s,comdat",
lang_hooks.decls.comdat_group (decl));
}
}
void
-default_coff_asm_named_section (const char *name, unsigned int flags,
+default_coff_asm_named_section (const char *name, unsigned int flags,
tree decl ATTRIBUTE_UNUSED)
{
char flagchars[8], *f = flagchars;
}
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)
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))
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 (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. */
local_p = true;
/* A variable is local if the user has said explicitly that it will
be. */
- else if (DECL_VISIBILITY_SPECIFIED (exp)
+ else if (DECL_VISIBILITY_SPECIFIED (exp)
&& DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
local_p = true;
/* Variables defined outside this object might not be local. */
tree decl ATTRIBUTE_UNUSED,
int for_eh ATTRIBUTE_UNUSED,
int empty ATTRIBUTE_UNUSED)
-{
+{
+}
+
+/* Default function to output a label to divide up the exception table.
+ The default is to do nothing. A target that needs/wants to divide
+ up the table must provide it's own function to do this. */
+void
+default_emit_except_table_label (FILE * stream ATTRIBUTE_UNUSED)
+{
}
/* This is how to output an internal numbered label where PREFIX is
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
&& strcmp (new_section->named.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);
+}
+
#include "gt-varasm.h"