#endif
/* The (assembler) name of the first globally-visible object output. */
+extern GTY(()) const char *first_global_object_name;
+extern GTY(()) const char *weak_global_object_name;
+
const char *first_global_object_name;
const char *weak_global_object_name;
static void output_constructor (tree, unsigned HOST_WIDE_INT, unsigned int);
static void globalize_decl (tree);
static void maybe_assemble_visibility (tree);
-static int in_named_entry_eq (const void *, const void *);
-static hashval_t in_named_entry_hash (const void *);
-static void initialize_cold_section_name (void);
#ifdef BSS_SECTION_ASM_OP
#ifdef ASM_OUTPUT_BSS
static void asm_output_bss (FILE *, tree, const char *,
unsigned HOST_WIDE_INT);
static void mark_weak (tree);
\f
-static GTY(()) enum in_section in_section = no_section;
-enum in_section last_text_section;
+/* Well-known sections, each one associated with some sort of *_ASM_OP. */
+section *text_section;
+section *data_section;
+section *readonly_data_section;
+section *sdata_section;
+section *ctors_section;
+section *dtors_section;
+section *bss_section;
+section *sbss_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. */
+section *exception_section;
+
+/* The section that holds the DWARF2 frame unwind information, when known.
+ The section is set either by the target's init_sections hook or by the
+ first call to switch_to_eh_frame_section. */
+section *eh_frame_section;
+
+/* asm_out_file's current section. This is NULL if no section has yet
+ been selected or if we lose track of what the current section is. */
+section *in_section;
+
+/* True if code for the current function is currently being directed
+ at the cold section. */
+bool in_cold_section_p;
+
+/* A linked list of all the unnamed sections. */
+static GTY(()) section *unnamed_sections;
/* Return a nonzero value if DECL has a section attribute. */
#ifndef IN_NAMED_SECTION
&& DECL_SECTION_NAME (DECL) != NULL_TREE)
#endif
-/* Text of section name when in_section == in_named. */
-static GTY(()) const char *in_named_name;
-const char *last_text_section_name;
+/* Hash table of named sections. */
+static GTY((param_is (section))) htab_t section_htab;
-/* Hash table of flags that have been used for a particular named section. */
+/* Helper routines for maintaining section_htab. */
-struct in_named_entry GTY(())
+static int
+section_entry_eq (const void *p1, const void *p2)
{
- const char *name;
- unsigned int flags;
- bool declared;
-};
+ const section *old = p1;
+ const char *new = p2;
+
+ return strcmp (old->named.name, new) == 0;
+}
-static GTY((param_is (struct in_named_entry))) htab_t in_named_htab;
+static hashval_t
+section_entry_hash (const void *p)
+{
+ const section *old = p;
+ return htab_hash_string (old->named.name);
+}
-/* Define functions like text_section for any extra sections. */
-#ifdef EXTRA_SECTION_FUNCTIONS
-EXTRA_SECTION_FUNCTIONS
-#endif
+/* Return a new unnamed section with the given fields. */
+
+section *
+get_unnamed_section (unsigned int flags, void (*callback) (const void *),
+ const void *data)
+{
+ section *sect;
+
+ sect = ggc_alloc (sizeof (struct unnamed_section));
+ sect->unnamed.common.flags = flags;
+ sect->unnamed.callback = callback;
+ sect->unnamed.data = data;
+ sect->unnamed.next = unnamed_sections;
+
+ unnamed_sections = sect;
+ return sect;
+}
+
+/* Return the named section structure associated with NAME. Create
+ a new section with the given fields if no such structure exists. */
+
+section *
+get_section (const char *name, unsigned int flags, tree decl)
+{
+ section *sect, **slot;
+
+ slot = (section **)
+ htab_find_slot_with_hash (section_htab, name,
+ htab_hash_string (name), INSERT);
+ flags |= SECTION_NAMED;
+ if (*slot == NULL)
+ {
+ sect = ggc_alloc (sizeof (struct named_section));
+ sect->named.common.flags = flags;
+ sect->named.name = ggc_strdup (name);
+ sect->named.decl = decl;
+ *slot = sect;
+ }
+ else
+ {
+ sect = *slot;
+ if ((sect->common.flags & ~SECTION_DECLARED) != flags
+ && ((sect->common.flags | flags) & SECTION_OVERRIDE) == 0)
+ {
+ /* Sanity check user variables for flag changes. */
+ if (decl == 0)
+ decl = sect->named.decl;
+ gcc_assert (decl);
+ error ("%+D causes a section type conflict", decl);
+ }
+ }
+ return sect;
+}
static void
initialize_cold_section_name (void)
cfun->unlikely_text_section_name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
}
-/* Tell assembler to switch to text section. */
-
-void
-text_section (void)
-{
- if (in_section != in_text)
- {
- in_section = in_text;
- last_text_section = in_text;
- fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
- }
-}
-
/* Tell assembler to switch to unlikely-to-be-executed text section. */
-void
+section *
unlikely_text_section (void)
{
if (cfun)
if (!cfun->unlikely_text_section_name)
initialize_cold_section_name ();
- if (flag_function_sections
- || ((in_section != in_unlikely_executed_text)
- && (in_section != in_named
- || (strcmp (in_named_name, cfun->unlikely_text_section_name)
- != 0))))
- {
- named_section (NULL_TREE, cfun->unlikely_text_section_name, 0);
- in_section = in_unlikely_executed_text;
- last_text_section = in_unlikely_executed_text;
- }
+ return get_named_section (NULL, cfun->unlikely_text_section_name, 0);
}
else
- {
- named_section (NULL_TREE, UNLIKELY_EXECUTED_TEXT_SECTION_NAME, 0);
- in_section = in_unlikely_executed_text;
- last_text_section = in_unlikely_executed_text;
- }
-}
-
-/* Tell assembler to switch to data section. */
-
-void
-data_section (void)
-{
- if (in_section != in_data)
- {
- in_section = in_data;
- fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
- }
+ return get_named_section (NULL, UNLIKELY_EXECUTED_TEXT_SECTION_NAME, 0);
}
-/* Tell assembler to switch to read-only data section. This is normally
- the text section. */
-
-void
-readonly_data_section (void)
-{
-#ifdef READONLY_DATA_SECTION
- READONLY_DATA_SECTION (); /* Note this can call data_section. */
-#else
-#ifdef READONLY_DATA_SECTION_ASM_OP
- if (in_section != in_readonly_data)
- {
- in_section = in_readonly_data;
- fputs (READONLY_DATA_SECTION_ASM_OP, asm_out_file);
- fputc ('\n', asm_out_file);
- }
-#else
- text_section ();
-#endif
-#endif
-}
-
-/* Determine if we're in the text section. */
-
-int
-in_text_section (void)
-{
- return in_section == in_text;
-}
-
-/* Determine if we're in the unlikely-to-be-executed text section. */
-
-int
-in_unlikely_text_section (void)
-{
- bool ret_val;
-
- if (cfun)
- {
- ret_val = ((in_section == in_unlikely_executed_text)
- || (in_section == in_named
- && cfun->unlikely_text_section_name
- && strcmp (in_named_name,
- cfun->unlikely_text_section_name) == 0));
- }
- else
- {
- ret_val = ((in_section == in_unlikely_executed_text)
- || (in_section == in_named
- && strcmp (in_named_name,
- UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0));
- }
-
- return ret_val;
-}
-
-/* Determine if we're in the data section. */
-
-int
-in_data_section (void)
-{
- return in_section == in_data;
-}
-
-/* Helper routines for maintaining in_named_htab. */
-
-static int
-in_named_entry_eq (const void *p1, const void *p2)
-{
- const struct in_named_entry *old = p1;
- const char *new = p2;
-
- return strcmp (old->name, new) == 0;
-}
-
-static hashval_t
-in_named_entry_hash (const void *p)
-{
- const struct in_named_entry *old = p;
- return htab_hash_string (old->name);
-}
-
-/* If SECTION has been seen before as a named section, return the flags
- that were used. Otherwise, return 0. Note, that 0 is a perfectly valid
- set of flags for a section to have, so 0 does not mean that the section
- has not been seen. */
-
-static unsigned int
-get_named_section_flags (const char *section)
-{
- struct in_named_entry **slot;
-
- slot = (struct in_named_entry **)
- htab_find_slot_with_hash (in_named_htab, section,
- htab_hash_string (section), NO_INSERT);
-
- return slot ? (*slot)->flags : 0;
-}
-
-/* Returns true if the section has been declared before. Sets internal
- flag on this section in in_named_hash so subsequent calls on this
- section will return false. */
+/* When called within a function context, return true if the function
+ has been assigned a cold text section and if SECT is that section.
+ When called outside a function context, return true if SECT is the
+ default cold section. */
bool
-named_section_first_declaration (const char *name)
+unlikely_text_section_p (section *sect)
{
- struct in_named_entry **slot;
+ const char *name;
- slot = (struct in_named_entry **)
- htab_find_slot_with_hash (in_named_htab, name,
- htab_hash_string (name), NO_INSERT);
- if (! (*slot)->declared)
- {
- (*slot)->declared = true;
- return true;
- }
+ if (cfun)
+ name = cfun->unlikely_text_section_name;
else
- {
- return false;
- }
-}
-
-
-/* Record FLAGS for SECTION. If SECTION was previously recorded with a
- different set of flags, return false. */
+ name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
-bool
-set_named_section_flags (const char *section, unsigned int flags)
-{
- struct in_named_entry **slot, *entry;
-
- slot = (struct in_named_entry **)
- htab_find_slot_with_hash (in_named_htab, section,
- htab_hash_string (section), INSERT);
- entry = *slot;
-
- if (!entry)
- {
- entry = ggc_alloc (sizeof (*entry));
- *slot = entry;
- entry->name = ggc_strdup (section);
- entry->flags = flags;
- entry->declared = false;
- }
- else if (entry->flags != flags)
- return false;
-
- return true;
-}
-
-/* Tell assembler to change to section NAME with attributes FLAGS. If
- DECL is non-NULL, it is the VAR_DECL or FUNCTION_DECL with which
- this section is associated. */
-
-void
-named_section_real (const char *name, unsigned int flags, tree decl)
-{
- if (in_section != in_named || strcmp (name, in_named_name) != 0)
- {
- bool unchanged = set_named_section_flags (name, flags);
-
- gcc_assert (unchanged);
-
- targetm.asm_out.named_section (name, flags, decl);
-
- if (flags & SECTION_FORGET)
- in_section = no_section;
- else
- {
- in_named_name = ggc_strdup (name);
- in_section = in_named;
- }
- }
-
- if (in_text_section () || in_unlikely_text_section ())
- {
- last_text_section = in_section;
- last_text_section_name = name;
- }
+ return (name
+ && sect
+ && (sect->common.flags & SECTION_NAMED) != 0
+ && strcmp (name, sect->named.name) == 0);
}
-/* Tell assembler to change to section NAME for DECL.
- If DECL is NULL, just switch to section NAME.
- If NAME is NULL, get the name from DECL.
- If RELOC is 1, the initializer for DECL contains relocs. */
+/* Return a section with a particular name and with whatever SECTION_*
+ flags section_type_flags deems appropriate. The name of the section
+ is taken from NAME if nonnull, otherwise it is taken from DECL's
+ DECL_SECTION_NAME. DECL is the decl associated with the section
+ (see the section comment for details) and RELOC is as for
+ section_type_flags. */
-void
-named_section (tree decl, const char *name, int reloc)
+section *
+get_named_section (tree decl, const char *name, int reloc)
{
unsigned int flags;
if (name == NULL)
name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
- if (strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0
- && cfun
- && ! cfun->unlikely_text_section_name)
- cfun->unlikely_text_section_name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
-
flags = targetm.section_type_flags (decl, name, reloc);
- /* Sanity check user variables for flag changes. Non-user
- section flag changes will die in named_section_flags.
- However, don't complain if SECTION_OVERRIDE is set.
- We trust that the setter knows that it is safe to ignore
- the default flags for this decl. */
- if (decl && ! set_named_section_flags (name, flags))
- {
- flags = get_named_section_flags (name);
- if ((flags & SECTION_OVERRIDE) == 0)
- error ("%+D causes a section type conflict", decl);
- }
-
- named_section_real (name, flags, decl);
+ return get_section (name, flags, decl);
}
/* If required, set DECL_SECTION_NAME to a unique name. */
#ifdef BSS_SECTION_ASM_OP
-/* Tell the assembler to switch to the bss section. */
-
-void
-bss_section (void)
-{
- if (in_section != in_bss)
- {
- fprintf (asm_out_file, "%s\n", BSS_SECTION_ASM_OP);
- in_section = in_bss;
- }
-}
-
#ifdef ASM_OUTPUT_BSS
/* Utility function for ASM_OUTPUT_BSS for targets to use if
unsigned HOST_WIDE_INT rounded)
{
targetm.asm_out.globalize_label (file, name);
- bss_section ();
+ switch_to_section (bss_section);
#ifdef ASM_DECLARE_OBJECT_NAME
last_assemble_variable_decl = decl;
ASM_DECLARE_OBJECT_NAME (file, name, decl);
const char *name, unsigned HOST_WIDE_INT size,
int align)
{
- bss_section ();
+ switch_to_section (bss_section);
ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
#ifdef ASM_DECLARE_OBJECT_NAME
last_assemble_variable_decl = decl;
#endif /* BSS_SECTION_ASM_OP */
-/* Switch to the section for function DECL.
+#ifndef USE_SELECT_SECTION_FOR_FUNCTIONS
+/* Return the hot section for function DECL. Return text_section for
+ null DECLs. */
+
+static section *
+hot_function_section (tree decl)
+{
+ if (decl != NULL_TREE
+ && DECL_SECTION_NAME (decl) != NULL_TREE
+ && targetm.have_named_sections)
+ return get_named_section (decl, NULL, 0);
+ else
+ return text_section;
+}
+#endif
+
+/* Return the section for function DECL.
- If DECL is NULL_TREE, switch to the text section. We can be passed
+ If DECL is NULL_TREE, return the text section. We can be passed
NULL_TREE under some circumstances by dbxout.c at least. */
-void
+section *
function_section (tree decl)
{
int reloc = 0;
-
+
if (first_function_block_is_cold)
reloc = 1;
-
+
#ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
- targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
+ return targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
#else
- if (decl != NULL_TREE
- && DECL_SECTION_NAME (decl) != NULL_TREE
- && targetm.have_named_sections)
- named_section (decl, (char *) 0, 0);
- else
- text_section ();
+ return hot_function_section (decl);
#endif
}
-void
-current_function_section (tree decl)
+section *
+current_function_section (void)
{
#ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
- int reloc = 0;
-
- if (in_unlikely_text_section ()
- || last_text_section == in_unlikely_executed_text)
- reloc = 1;
-
- targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
+ return targetm.asm_out.select_section (current_function_decl,
+ in_cold_section_p,
+ DECL_ALIGN (current_function_decl));
#else
- if (last_text_section == in_unlikely_executed_text)
- unlikely_text_section ();
- else if (last_text_section == in_text)
- text_section ();
- else if (last_text_section == in_named
- && targetm.have_named_sections)
- named_section (NULL_TREE, last_text_section_name, 0);
- else
- function_section (decl);
+ return (in_cold_section_p
+ ? unlikely_text_section ()
+ : hot_function_section (current_function_decl));
#endif
}
-/* Switch to read-only data section associated with function DECL. */
+/* Return the read-only data section associated with function DECL. */
-void
+section *
default_function_rodata_section (tree decl)
{
if (decl != NULL_TREE && DECL_SECTION_NAME (decl))
{
size_t len = strlen (name) + 3;
char* rname = alloca (len);
-
+
strcpy (rname, ".rodata");
- strcat (rname, name + 5);
- named_section_real (rname, SECTION_LINKONCE, decl);
- return;
+ strcat (rname, name + 5);
+ return get_section (rname, SECTION_LINKONCE, decl);
}
/* For .gnu.linkonce.t.foo we want to use .gnu.linkonce.r.foo. */
else if (DECL_ONE_ONLY (decl)
memcpy (rname, name, len);
rname[14] = 'r';
- named_section_real (rname, SECTION_LINKONCE, decl);
- return;
+ return get_section (rname, SECTION_LINKONCE, decl);
}
/* For .text.foo we want to use .rodata.foo. */
else if (flag_function_sections && flag_data_sections
memcpy (rname, ".rodata", 7);
memcpy (rname + 7, name + 5, len - 5);
- named_section_flags (rname, 0);
- return;
+ return get_section (rname, 0, decl);
}
}
- readonly_data_section ();
+ return readonly_data_section;
}
-/* Switch to read-only data section associated with function DECL
+/* Return the read-only data section associated with function DECL
for targets where that section should be always the single
readonly data section. */
-void
+section *
default_no_function_rodata_section (tree decl ATTRIBUTE_UNUSED)
{
- readonly_data_section ();
+ return readonly_data_section;
}
/* Switch to section for variable DECL. RELOC is the same as the
variable_section (tree decl, int reloc)
{
if (IN_NAMED_SECTION (decl))
- named_section (decl, NULL, reloc);
+ switch_to_section (get_named_section (decl, NULL, reloc));
else
- targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
+ switch_to_section (targetm.asm_out.select_section (decl, reloc,
+ DECL_ALIGN (decl)));
}
-/* Tell assembler to switch to the section for string merging. */
+/* Return the section to use for string merging. */
-void
+static section *
mergeable_string_section (tree decl ATTRIBUTE_UNUSED,
unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED,
unsigned int flags ATTRIBUTE_UNUSED)
sprintf (name, ".rodata.str%d.%d", modesize / 8,
(int) (align / 8));
flags |= (modesize / 8) | SECTION_MERGE | SECTION_STRINGS;
- if (!i && modesize < align)
- {
- /* A "" string with requested alignment greater than
- character size might cause a problem:
- if some other string required even bigger
- alignment than "", then linker might think the
- "" is just part of padding after some other string
- and not put it into the hash table initially.
- But this means "" could have smaller alignment
- than requested. */
-#ifdef ASM_OUTPUT_SECTION_START
- named_section_flags (name, flags);
- ASM_OUTPUT_SECTION_START (asm_out_file);
-#else
- readonly_data_section ();
-#endif
- return;
- }
-
- named_section_flags (name, flags);
- return;
+ return get_section (name, flags, NULL);
}
}
}
- readonly_data_section ();
+ return readonly_data_section;
}
-/* Tell assembler to switch to the section for constant merging. */
+/* Return the section to use for constant merging. */
-void
+section *
mergeable_constant_section (enum machine_mode mode ATTRIBUTE_UNUSED,
unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED,
unsigned int flags ATTRIBUTE_UNUSED)
sprintf (name, ".rodata.cst%d", (int) (align / 8));
flags |= (align / 8) | SECTION_MERGE;
- named_section_flags (name, flags);
- return;
+ return get_section (name, flags, NULL);
}
-
- readonly_data_section ();
+ return readonly_data_section;
}
\f
/* Given NAME, a putative register name, discard any customary prefixes. */
= ADDITIONAL_REGISTER_NAMES;
for (i = 0; i < (int) ARRAY_SIZE (table); i++)
- if (! strcmp (asmspec, table[i].name))
+ if (table[i].name[0]
+ && ! strcmp (asmspec, table[i].name))
return table[i].number;
}
#endif /* ADDITIONAL_REGISTER_NAMES */
|| 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);
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
- if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
+ if (name[0] != '*' && TREE_CODE (decl) != FUNCTION_DECL
+ && DECL_REGISTER (decl))
{
- reg_number = decode_reg_name (name);
+ error ("register name not specified for %q+D", decl);
+ }
+ else if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
+ {
+ const char *asmspec = name+1;
+ reg_number = decode_reg_name (asmspec);
/* First detect errors in declaring global registers. */
if (reg_number == -1)
error ("register name not specified for %q+D", decl);
error ("global register variable has initial value");
}
if (TREE_THIS_VOLATILE (decl))
- warning (0, "volatile register variables don%'t "
- "work as you might wish");
+ warning (OPT_Wvolatile_register_var,
+ "optimization may eliminate reads and/or "
+ "writes to register variables");
/* If the user specified one of the eliminables registers here,
e.g., FRAME_POINTER_REGNUM, we don't want to get this variable
section = buf;
}
- named_section_flags (section, SECTION_WRITE);
+ switch_to_section (get_section (section, SECTION_WRITE, NULL));
assemble_align (POINTER_SIZE);
assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
}
#ifdef DTORS_SECTION_ASM_OP
void
-dtors_section (void)
-{
- if (in_section != in_dtors)
- {
- in_section = in_dtors;
- fputs (DTORS_SECTION_ASM_OP, asm_out_file);
- fputc ('\n', asm_out_file);
- }
-}
-
-void
default_dtor_section_asm_out_destructor (rtx symbol,
int priority ATTRIBUTE_UNUSED)
{
- dtors_section ();
+ switch_to_section (dtors_section);
assemble_align (POINTER_SIZE);
assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
}
section = buf;
}
- named_section_flags (section, SECTION_WRITE);
+ switch_to_section (get_section (section, SECTION_WRITE, NULL));
assemble_align (POINTER_SIZE);
assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
}
#ifdef CTORS_SECTION_ASM_OP
void
-ctors_section (void)
-{
- if (in_section != in_ctors)
- {
- in_section = in_ctors;
- fputs (CTORS_SECTION_ASM_OP, asm_out_file);
- fputc ('\n', asm_out_file);
- }
-}
-
-void
default_ctor_section_asm_out_constructor (rtx symbol,
int priority ATTRIBUTE_UNUSED)
{
- ctors_section ();
+ switch_to_section (ctors_section);
assemble_align (POINTER_SIZE);
assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
}
if (!*type)
{
const char *p;
- char *name;
+ const char *name;
rtx decl_rtl = DECL_RTL (decl);
p = targetm.strip_name_encoding (XSTR (XEXP (decl_rtl, 0), 0));
- name = xstrdup (p);
+ name = ggc_strdup (p);
*type = name;
}
bool hot_label_written = false;
cfun->unlikely_text_section_name = NULL;
-
+
first_function_block_is_cold = false;
if (flag_reorder_blocks_and_partition)
{
if (flag_reorder_blocks_and_partition)
{
- unlikely_text_section ();
+ switch_to_section (unlikely_text_section ());
assemble_align (FUNCTION_BOUNDARY);
ASM_OUTPUT_LABEL (asm_out_file, cfun->cold_section_label);
- if (BB_PARTITION (ENTRY_BLOCK_PTR->next_bb) == BB_COLD_PARTITION)
+
+ /* When the function starts with a cold section, we need to explicitly
+ align the hot section and write out the hot section label.
+ But if the current function is a thunk, we do not have a CFG. */
+ if (!current_function_is_thunk
+ && BB_PARTITION (ENTRY_BLOCK_PTR->next_bb) == BB_COLD_PARTITION)
{
- /* Since the function starts with a cold section, we need to
- explicitly align the hot section and write out the hot
- section label. */
- text_section ();
+ switch_to_section (text_section);
assemble_align (FUNCTION_BOUNDARY);
ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_label);
hot_label_written = true;
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;
}
- last_text_section = no_section;
+ in_cold_section_p = first_function_block_is_cold;
/* Switch to the correct text section for the start of the function. */
- function_section (decl);
- if (flag_reorder_blocks_and_partition
+ 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);
/* Standard thing is just output label for the function. */
ASM_OUTPUT_LABEL (asm_out_file, fnname);
#endif /* ASM_DECLARE_FUNCTION_NAME */
-
- insert_section_boundary_note ();
}
/* Output assembler code associated with defining the size of the
assemble_end_function (tree decl, const char *fnname)
{
#ifdef ASM_DECLARE_FUNCTION_SIZE
+ /* We could have switched section in the middle of the function. */
+ if (flag_reorder_blocks_and_partition)
+ switch_to_section (function_section (decl));
ASM_DECLARE_FUNCTION_SIZE (asm_out_file, fnname, decl);
#endif
if (! CONSTANT_POOL_BEFORE_FUNCTION)
{
output_constant_pool (fnname, decl);
- function_section (decl); /* need to switch back */
+ switch_to_section (function_section (decl)); /* need to switch back */
}
/* Output labels for end of hot/cold text sections (to be used by
debug info.) */
if (flag_reorder_blocks_and_partition)
{
- enum in_section save_text_section;
+ section *save_text_section;
save_text_section = in_section;
- unlikely_text_section ();
+ switch_to_section (unlikely_text_section ());
ASM_OUTPUT_LABEL (asm_out_file, cfun->cold_section_end_label);
if (first_function_block_is_cold)
- text_section ();
+ switch_to_section (text_section);
else
- function_section (decl);
+ switch_to_section (function_section (decl));
ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_end_label);
- if (save_text_section == in_unlikely_executed_text)
- unlikely_text_section ();
+ switch_to_section (save_text_section);
}
}
\f
#ifdef ASM_NO_SKIP_IN_TEXT
/* The `space' pseudo in the text section outputs nop insns rather than 0s,
so we must output 0s explicitly in the text section. */
- if ((ASM_NO_SKIP_IN_TEXT && in_text_section ())
- || (ASM_NO_SKIP_IN_TEXT && in_unlikely_text_section ()))
+ if (ASM_NO_SKIP_IN_TEXT && (in_section->common.flags & SECTION_CODE) != 0)
{
unsigned HOST_WIDE_INT i;
for (i = 0; i < size; i++)
isn't common, and shouldn't be handled as such. */
if (DECL_SECTION_NAME (decl) || dont_output_data)
;
- /* We don't implement common thread-local data at present. */
else if (DECL_THREAD_LOCAL_P (decl))
{
if (DECL_COMMON (decl))
- sorry ("thread-local COMMON data not implemented");
+ {
+#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
#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 %d", decl, rounded);
+ "implemented alignment of %wu", decl, rounded);
#endif
/* If the target cannot output uninitialized but not common global data
variable_section (decl, reloc);
/* dbxout.c needs to know this. */
- if (in_text_section () || in_unlikely_text_section ())
+ if (in_section && (in_section->common.flags & SECTION_CODE) != 0)
DECL_IN_TEXT_SECTION (decl) = 1;
/* Output the alignment of this data. */
which do not need to be marked. */
}
+
+/* Follow the IDENTIFIER_TRANSPARENT_ALIAS chain starting at *ALIAS
+ until we find an identifier that is not itself a transparent alias.
+ Modify the alias passed to it by reference (and all aliases on the
+ way to the ultimate target), such that they do not have to be
+ followed again, and return the ultimate target of the alias
+ chain. */
+
+static inline tree
+ultimate_transparent_alias_target (tree *alias)
+{
+ tree target = *alias;
+
+ if (IDENTIFIER_TRANSPARENT_ALIAS (target))
+ {
+ gcc_assert (TREE_CHAIN (target));
+ target = ultimate_transparent_alias_target (&TREE_CHAIN (target));
+ gcc_assert (! IDENTIFIER_TRANSPARENT_ALIAS (target)
+ && ! TREE_CHAIN (target));
+ *alias = target;
+ }
+
+ return target;
+}
+
/* Output to FILE (an assembly file) a reference to NAME. If NAME
starts with a *, the rest of NAME is output verbatim. Otherwise
NAME is transformed in a target-specific way (usually by the
id = maybe_get_identifier (real_name);
if (id)
- mark_referenced (id);
+ {
+ tree id_orig = id;
+
+ mark_referenced (id);
+ ultimate_transparent_alias_target (&id);
+ if (id != id_orig)
+ name = IDENTIFIER_POINTER (id);
+ gcc_assert (! TREE_CHAIN (id));
+ }
assemble_name_raw (file, name);
}
#if 0
if (flag_shared_data)
- data_section ();
+ switch_to_section (data_section);
#endif
ASM_GENERATE_INTERNAL_LABEL (name, "LF", const_labelno);
/* By default, put trampoline templates in read-only data section. */
#ifdef TRAMPOLINE_SECTION
- TRAMPOLINE_SECTION ();
+ switch_to_section (TRAMPOLINE_SECTION);
#else
- readonly_data_section ();
+ switch_to_section (readonly_data_section);
#endif
/* Write the assembler code to define one. */
}
gcc_assert (!force);
-
+
return false;
}
\f
case CONSTRUCTOR:
{
- tree link;
-
+ unsigned HOST_WIDE_INT idx;
+ tree value;
+
hi = 5 + int_size_in_bytes (TREE_TYPE (exp));
-
- for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
- if (TREE_VALUE (link))
- hi = hi * 603 + const_hash_1 (TREE_VALUE (link));
-
+
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
+ if (value)
+ hi = hi * 603 + const_hash_1 (value);
+
return hi;
}
case CONSTRUCTOR:
{
- tree l1, l2;
-
+ 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;
}
- for (l1 = CONSTRUCTOR_ELTS (t1), l2 = CONSTRUCTOR_ELTS (t2);
- l1 && l2;
- l1 = TREE_CHAIN (l1), l2 = TREE_CHAIN (l2))
+ v1 = CONSTRUCTOR_ELTS (t1);
+ v2 = CONSTRUCTOR_ELTS (t2);
+ if (VEC_length (constructor_elt, v1)
+ != VEC_length (constructor_elt, v2))
+ return 0;
+
+ for (idx = 0; idx < VEC_length (constructor_elt, v1); ++idx)
{
+ constructor_elt *c1 = VEC_index (constructor_elt, v1, idx);
+ constructor_elt *c2 = VEC_index (constructor_elt, v2, idx);
+
/* Check that each value is the same... */
- if (! compare_constant (TREE_VALUE (l1), TREE_VALUE (l2)))
+ if (!compare_constant (c1->value, c2->value))
return 0;
/* ... and that they apply to the same fields! */
if (typecode == ARRAY_TYPE)
{
- if (! compare_constant (TREE_PURPOSE (l1),
- TREE_PURPOSE (l2)))
+ if (!compare_constant (c1->index, c2->index))
return 0;
}
else
{
- if (TREE_PURPOSE (l1) != TREE_PURPOSE (l2))
+ if (c1->index != c2->index)
return 0;
}
}
-
- return l1 == NULL_TREE && l2 == NULL_TREE;
+
+ return 1;
}
case ADDR_EXPR:
case CONSTRUCTOR:
{
tree copy = copy_node (exp);
- tree list = copy_list (CONSTRUCTOR_ELTS (exp));
- tree tail;
-
- CONSTRUCTOR_ELTS (copy) = list;
- for (tail = list; tail; tail = TREE_CHAIN (tail))
- TREE_VALUE (tail) = copy_constant (TREE_VALUE (tail));
+ 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)
+ {
+ constructor_elt *ce = VEC_quick_push (constructor_elt, v, NULL);
+ ce->index = purpose;
+ ce->value = copy_constant (value);
+ }
+ CONSTRUCTOR_ELTS (copy) = v;
return copy;
}
default:
{
tree t = lang_hooks.expand_constant (exp);
-
+
gcc_assert (t == exp);
return copy_constant (t);
}
TREE_ASM_WRITTEN (exp) = 1;
if (IN_NAMED_SECTION (exp))
- named_section (exp, NULL, reloc);
+ switch_to_section (get_named_section (exp, NULL, reloc));
else
- targetm.asm_out.select_section (exp, reloc, align);
+ switch_to_section (targetm.asm_out.select_section (exp, reloc, align));
if (align > BITS_PER_UNIT)
{
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);
switch (GET_MODE_CLASS (mode))
{
case MODE_FLOAT:
+ 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);
}
/* First switch to correct section. */
- targetm.asm_out.select_rtx_section (desc->mode, x, desc->align);
+ 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,
/* Make sure all constants in SECTION_MERGE and not SECTION_STRINGS
sections have proper size. */
if (desc->align > GET_MODE_BITSIZE (desc->mode)
- && in_section == in_named
- && get_named_section_flags (in_named_name) & SECTION_MERGE)
+ && in_section
+ && (in_section->common.flags & SECTION_MERGE))
assemble_align (desc->align);
#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
}
return -1;
-}
+}
/* Look through appropriate parts of INSN, marking all entries in the
constant pool which are actually being used. Entries that are only
break;
case CONSTRUCTOR:
- for (tem = CONSTRUCTOR_ELTS (exp); tem; tem = TREE_CHAIN (tem))
- if (TREE_VALUE (tem) != 0)
- reloc |= compute_reloc_for_constant (TREE_VALUE (tem));
-
+ {
+ unsigned HOST_WIDE_INT idx;
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, tem)
+ if (tem != 0)
+ reloc |= compute_reloc_for_constant (tem);
+ }
break;
default:
break;
case CONSTRUCTOR:
- for (tem = CONSTRUCTOR_ELTS (exp); tem; tem = TREE_CHAIN (tem))
- if (TREE_VALUE (tem) != 0)
- output_addressed_constants (TREE_VALUE (tem));
-
+ {
+ unsigned HOST_WIDE_INT idx;
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, tem)
+ if (tem != 0)
+ output_addressed_constants (tem);
+ }
break;
default:
if ((TREE_CODE (TREE_TYPE (value)) == UNION_TYPE
|| TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE)
&& TREE_CONSTANT (value)
- && CONSTRUCTOR_ELTS (value))
+ && !VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (value)))
{
+ unsigned HOST_WIDE_INT idx;
tree elt;
bool absolute = true;
- for (elt = CONSTRUCTOR_ELTS (value); elt; elt = TREE_CHAIN (elt))
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (value), idx, elt)
{
tree reloc;
- value = TREE_VALUE (elt);
- reloc = initializer_constant_valid_p (value, TREE_TYPE (value));
+ reloc = initializer_constant_valid_p (elt, TREE_TYPE (elt));
if (!reloc)
return NULL_TREE;
if (reloc != null_pointer_node)
case ADDR_EXPR:
case FDESC_EXPR:
value = staticp (TREE_OPERAND (value, 0));
- /* "&(*a).f" is like unto pointer arithmetic. If "a" turns out to
- be a constant, this is old-skool offsetof-like nonsense. */
- if (value
- && TREE_CODE (value) == INDIRECT_REF
- && TREE_CONSTANT (TREE_OPERAND (value, 0)))
- return null_pointer_node;
- /* Taking the address of a nested function involves a trampoline. */
- if (value
- && TREE_CODE (value) == FUNCTION_DECL
- && ((decl_function_context (value) && !DECL_NO_STATIC_CHAIN (value))
- || DECL_NON_ADDR_CONST_P (value)))
- return NULL_TREE;
+ if (value)
+ {
+ /* "&(*a).f" is like unto pointer arithmetic. If "a" turns out to
+ be a constant, this is old-skool offsetof-like nonsense. */
+ if (TREE_CODE (value) == INDIRECT_REF
+ && TREE_CONSTANT (TREE_OPERAND (value, 0)))
+ 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)))
+ return NULL_TREE;
+ /* "&{...}" requires a temporary to hold the constructed
+ object. */
+ if (TREE_CODE (value) == CONSTRUCTOR)
+ return NULL_TREE;
+ }
return value;
case VIEW_CONVERT_EXPR:
if (size == 0 || flag_syntax_only)
return;
+ /* See if we're trying to initialize a pointer in a non-default mode
+ to the address of some declaration somewhere. If the target says
+ the mode is valid for pointers, assume the target has a way of
+ resolving it. */
+ if (TREE_CODE (exp) == NOP_EXPR
+ && POINTER_TYPE_P (TREE_TYPE (exp))
+ && targetm.valid_pointer_mode (TYPE_MODE (TREE_TYPE (exp))))
+ {
+ tree saved_type = TREE_TYPE (exp);
+
+ /* Peel off any intermediate conversions-to-pointer for valid
+ pointer modes. */
+ while (TREE_CODE (exp) == NOP_EXPR
+ && POINTER_TYPE_P (TREE_TYPE (exp))
+ && targetm.valid_pointer_mode (TYPE_MODE (TREE_TYPE (exp))))
+ exp = TREE_OPERAND (exp, 0);
+
+ /* If what we're left with is the address of something, we can
+ convert the address to the final type and output it that
+ way. */
+ if (TREE_CODE (exp) == ADDR_EXPR)
+ exp = build1 (ADDR_EXPR, saved_type, TREE_OPERAND (exp, 0));
+ }
+
/* Eliminate any conversions since we'll be outputting the underlying
constant. */
while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR
|| TREE_CODE (exp) == NON_LVALUE_EXPR
|| TREE_CODE (exp) == VIEW_CONVERT_EXPR)
- exp = TREE_OPERAND (exp, 0);
+ {
+ HOST_WIDE_INT type_size = int_size_in_bytes (TREE_TYPE (exp));
+ HOST_WIDE_INT op_size = int_size_in_bytes (TREE_TYPE (TREE_OPERAND (exp, 0)));
+
+ /* Make sure eliminating the conversion is really a no-op, except with
+ VIEW_CONVERT_EXPRs to allow for wild Ada unchecked conversions and
+ union types to allow for Ada unchecked unions. */
+ 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);
+ }
code = TREE_CODE (TREE_TYPE (exp));
thissize = int_size_in_bytes (TREE_TYPE (exp));
/* Allow a constructor with no elements for any data type.
This means to fill the space with zeros. */
- if (TREE_CODE (exp) == CONSTRUCTOR && CONSTRUCTOR_ELTS (exp) == 0)
+ if (TREE_CODE (exp) == CONSTRUCTOR
+ && VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (exp)))
{
assemble_zeros (size);
return;
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);
while ((link = TREE_CHAIN (link)) != NULL)
array_size_for_constructor (tree val)
{
tree max_index, i;
+ unsigned HOST_WIDE_INT cnt;
+ tree index, value;
/* 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 TREE_STRING_LENGTH (val);
max_index = NULL_TREE;
- for (i = CONSTRUCTOR_ELTS (val); i; i = TREE_CHAIN (i))
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (val), cnt, index, value)
{
- tree index = TREE_PURPOSE (i);
-
if (TREE_CODE (index) == RANGE_EXPR)
index = TREE_OPERAND (index, 1);
if (max_index == NULL_TREE || tree_int_cst_lt (max_index, index))
i = size_binop (MINUS_EXPR, convert (sizetype, max_index),
convert (sizetype,
TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (val)))));
- i = size_binop (PLUS_EXPR, i, convert (sizetype, integer_one_node));
+ i = size_binop (PLUS_EXPR, i, build_int_cst (sizetype, 1));
/* Multiply by the array element unit size to find number of bytes. */
i = size_binop (MULT_EXPR, i, TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (val))));
unsigned int align)
{
tree type = TREE_TYPE (exp);
- tree link, field = 0;
+ tree field = 0;
tree min_index = 0;
/* Number of bytes output or skipped so far.
In other words, current position within the constructor. */
/* Nonzero means BYTE contains part of a byte, to be output. */
int byte_buffer_in_use = 0;
int byte = 0;
+ unsigned HOST_WIDE_INT cnt;
+ constructor_elt *ce;
gcc_assert (HOST_BITS_PER_WIDE_INT >= BITS_PER_UNIT);
There is always a maximum of one element in the chain LINK for unions
(even if the initializer in a source program incorrectly contains
more one). */
- for (link = CONSTRUCTOR_ELTS (exp);
- link;
- link = TREE_CHAIN (link),
- field = field ? TREE_CHAIN (field) : 0)
+ for (cnt = 0;
+ VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (exp), cnt, ce);
+ cnt++, field = field ? TREE_CHAIN (field) : 0)
{
- tree val = TREE_VALUE (link);
+ tree val = ce->value;
tree index = 0;
/* The element in a union constructor specifies the proper field
or index. */
if ((TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE
|| TREE_CODE (type) == QUAL_UNION_TYPE)
- && TREE_PURPOSE (link) != 0)
- field = TREE_PURPOSE (link);
+ && ce->index != 0)
+ field = ce->index;
else if (TREE_CODE (type) == ARRAY_TYPE)
- index = TREE_PURPOSE (link);
+ index = ce->index;
#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
if each element has the proper size. */
if ((field != 0 || index != 0) && pos != total_bytes)
{
+ gcc_assert (pos >= total_bytes);
assemble_zeros (pos - total_bytes);
total_bytes = pos;
}
/* If still not at proper byte, advance to there. */
if (next_offset / BITS_PER_UNIT != total_bytes)
{
+ gcc_assert (next_offset / BITS_PER_UNIT >= total_bytes);
assemble_zeros (next_offset / BITS_PER_UNIT - total_bytes);
total_bytes = next_offset / BITS_PER_UNIT;
}
mark_weak (decl);
}
-/* Emit any pending weak declarations. */
-
-void
-weak_finish (void)
+static void
+weak_finish_1 (tree decl)
{
- tree t;
-
- for (t = weak_decls; t; t = TREE_CHAIN (t))
- {
- tree decl = TREE_VALUE (t);
#if defined (ASM_WEAKEN_DECL) || defined (ASM_WEAKEN_LABEL)
- const char *const name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+ const char *const name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
#endif
- if (! TREE_USED (decl))
- continue;
+ if (! TREE_USED (decl))
+ return;
#ifdef ASM_WEAKEN_DECL
- ASM_WEAKEN_DECL (asm_out_file, decl, name, NULL);
+ ASM_WEAKEN_DECL (asm_out_file, decl, name, NULL);
#else
#ifdef ASM_WEAKEN_LABEL
- ASM_WEAKEN_LABEL (asm_out_file, name);
+ ASM_WEAKEN_LABEL (asm_out_file, name);
#else
#ifdef ASM_OUTPUT_WEAK_ALIAS
- warning (0, "only weak aliases are supported in this configuration");
- return;
+ {
+ static bool warn_once = 0;
+ if (! warn_once)
+ {
+ warning (0, "only weak aliases are supported in this configuration");
+ warn_once = 1;
+ }
+ return;
+ }
#endif
#endif
#endif
+}
+
+/* This TREE_LIST contains weakref targets. */
+
+static GTY(()) tree weakref_targets;
+
+/* Forward declaration. */
+static tree find_decl_and_mark_needed (tree decl, tree target);
+
+/* Emit any pending weak declarations. */
+
+void
+weak_finish (void)
+{
+ tree t;
+
+ for (t = weakref_targets; t; t = TREE_CHAIN (t))
+ {
+ tree alias_decl = TREE_PURPOSE (t);
+ tree target = ultimate_transparent_alias_target (&TREE_VALUE (t));
+
+ if (! TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias_decl)))
+ /* Remove alias_decl from the weak list, but leave entries for
+ the target alone. */
+ target = NULL_TREE;
+#ifndef ASM_OUTPUT_WEAKREF
+ 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
+ different macros. */
+# if defined ASM_WEAKEN_LABEL && ! defined ASM_WEAKEN_DECL
+ ASM_WEAKEN_LABEL (asm_out_file, IDENTIFIER_POINTER (target));
+# else
+ tree decl = find_decl_and_mark_needed (alias_decl, target);
+
+ if (! decl)
+ {
+ decl = build_decl (TREE_CODE (alias_decl), target,
+ TREE_TYPE (alias_decl));
+
+ DECL_EXTERNAL (decl) = 1;
+ TREE_PUBLIC (decl) = 1;
+ DECL_ARTIFICIAL (decl) = 1;
+ TREE_NOTHROW (decl) = TREE_NOTHROW (alias_decl);
+ TREE_USED (decl) = 1;
+ }
+
+ weak_finish_1 (decl);
+# endif
+ }
+#endif
+
+ {
+ tree *p;
+ tree t2;
+
+ /* Remove the alias and the target from the pending weak list
+ so that we do not emit any .weak directives for the former,
+ nor multiple .weak directives for the latter. */
+ for (p = &weak_decls; (t2 = *p) ; )
+ {
+ if (TREE_VALUE (t2) == alias_decl
+ || target == DECL_ASSEMBLER_NAME (TREE_VALUE (t2)))
+ *p = TREE_CHAIN (t2);
+ else
+ p = &TREE_CHAIN (t2);
+ }
+
+ /* Remove other weakrefs to the same target, to speed things up. */
+ for (p = &TREE_CHAIN (t); (t2 = *p) ; )
+ {
+ if (target == ultimate_transparent_alias_target (&TREE_VALUE (t2)))
+ *p = TREE_CHAIN (t2);
+ else
+ p = &TREE_CHAIN (t2);
+ }
+ }
+ }
+
+ for (t = weak_decls; t; t = TREE_CHAIN (t))
+ {
+ tree decl = TREE_VALUE (t);
+
+ weak_finish_1 (decl);
}
}
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)
struct cgraph_node *fnode = NULL;
struct cgraph_varpool_node *vnode = NULL;
- /* C++ thunk emitting code produces aliases late in the game.
- Avoid confusing cgraph code in that case. */
- if (!cgraph_global_info_ready)
+ if (TREE_CODE (decl) == FUNCTION_DECL)
{
- if (TREE_CODE (decl) == FUNCTION_DECL)
- {
- fnode = cgraph_node_for_asm (target);
- if (fnode == NULL)
- vnode = cgraph_varpool_node_for_asm (target);
- }
- else
- {
- vnode = cgraph_varpool_node_for_asm (target);
- if (vnode == NULL)
- fnode = cgraph_node_for_asm (target);
- }
+ fnode = cgraph_node_for_asm (target);
+ if (fnode == NULL)
+ vnode = cgraph_varpool_node_for_asm (target);
+ }
+ else
+ {
+ vnode = cgraph_varpool_node_for_asm (target);
+ if (vnode == NULL)
+ fnode = cgraph_node_for_asm (target);
}
if (fnode)
{
- cgraph_mark_needed_node (fnode);
+ /* We can't mark function nodes as used after cgraph global info
+ is finished. This wouldn't generally be necessary, but C++
+ virtual table thunks are introduced late in the game and
+ might seem like they need marking, although in fact they
+ don't. */
+ if (! cgraph_global_info_ready)
+ cgraph_mark_needed_node (fnode);
return fnode->decl;
}
else if (vnode)
cgraph_varpool_mark_needed_node (vnode);
return vnode->decl;
}
- else
+ else
return NULL_TREE;
}
tree node is DECL to have the value of the tree node TARGET. */
static void
-do_assemble_alias (tree decl, tree target ATTRIBUTE_UNUSED)
+do_assemble_alias (tree decl, tree target)
{
if (TREE_ASM_WRITTEN (decl))
return;
TREE_ASM_WRITTEN (decl) = 1;
TREE_ASM_WRITTEN (DECL_ASSEMBLER_NAME (decl)) = 1;
+ if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
+ {
+ ultimate_transparent_alias_target (&target);
+
+ if (!TREE_SYMBOL_REFERENCED (target))
+ weakref_targets = tree_cons (decl, target, weakref_targets);
+
+#ifdef ASM_OUTPUT_WEAKREF
+ ASM_OUTPUT_WEAKREF (asm_out_file, decl,
+ IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
+ IDENTIFIER_POINTER (target));
+#else
+ if (!SUPPORTS_WEAK)
+ {
+ error ("%Jweakref is not supported in this configuration", decl);
+ return;
+ }
+#endif
+ return;
+ }
+
#ifdef ASM_OUTPUT_DEF
/* Make name accessible from other files, if appropriate. */
*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);
+ }
}
#endif
}
target_decl = find_decl_and_mark_needed (p->decl, p->target);
if (target_decl == NULL)
- error ("%q+D aliased to undefined symbol %qE",
- p->decl, p->target);
- else if (DECL_EXTERNAL (target_decl))
- error ("%q+D aliased to external symbol %qE",
- p->decl, p->target);
+ {
+ if (! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)))
+ error ("%q+D aliased to undefined symbol %qs",
+ p->decl, IDENTIFIER_POINTER (p->target));
+ }
+ else if (DECL_EXTERNAL (target_decl)
+ && ! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)))
+ error ("%q+D aliased to external symbol %qs",
+ p->decl, IDENTIFIER_POINTER (p->target));
}
}
assemble_alias (tree decl, tree target)
{
tree target_decl;
+ bool is_weakref = false;
+
+ if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
+ {
+ tree alias = DECL_ASSEMBLER_NAME (decl);
+ is_weakref = true;
+
+ ultimate_transparent_alias_target (&target);
+
+ if (alias == target)
+ error ("weakref %q+D ultimately targets itself", decl);
+ else
+ {
+#ifndef ASM_OUTPUT_WEAKREF
+ IDENTIFIER_TRANSPARENT_ALIAS (alias) = 1;
+ TREE_CHAIN (alias) = target;
+#endif
+ }
+ if (TREE_PUBLIC (decl))
+ error ("weakref %q+D must have static linkage", decl);
+ }
+ else
+ {
#if !defined (ASM_OUTPUT_DEF)
# if !defined(ASM_OUTPUT_WEAK_ALIAS) && !defined (ASM_WEAKEN_DECL)
- error ("%Jalias definitions not supported in this configuration", decl);
- return;
-# else
- if (!DECL_WEAK (decl))
- {
- error ("%Jonly weak aliases are supported in this configuration", decl);
+ error ("%Jalias definitions not supported in this configuration", decl);
return;
- }
+# else
+ if (!DECL_WEAK (decl))
+ {
+ error ("%Jonly weak aliases are supported in this configuration", decl);
+ return;
+ }
# endif
#endif
+ }
/* We must force creation of DECL_RTL for debug info generation, even though
we don't use it here. */
/* A quirk of the initial implementation of aliases required that the user
add "extern" to all of them. Which is silly, but now historical. Do
note that the symbol is in fact locally defined. */
- DECL_EXTERNAL (decl) = 0;
+ if (! is_weakref)
+ DECL_EXTERNAL (decl) = 0;
/* Allow aliases to aliases. */
if (TREE_CODE (decl) == FUNCTION_DECL)
void
init_varasm_once (void)
{
- in_named_htab = htab_create_ggc (31, in_named_entry_hash,
- in_named_entry_eq, NULL);
+ section_htab = htab_create_ggc (31, section_entry_hash,
+ section_entry_eq, NULL);
const_desc_htab = htab_create_ggc (1009, const_desc_hash,
const_desc_eq, NULL);
const_alias_set = new_alias_set ();
+
+#ifdef TEXT_SECTION_ASM_OP
+ text_section = get_unnamed_section (SECTION_CODE, output_section_asm_op,
+ TEXT_SECTION_ASM_OP);
+#endif
+
+#ifdef DATA_SECTION_ASM_OP
+ data_section = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
+ DATA_SECTION_ASM_OP);
+#endif
+
+#ifdef SDATA_SECTION_ASM_OP
+ sdata_section = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
+ SDATA_SECTION_ASM_OP);
+#endif
+
+#ifdef READONLY_DATA_SECTION_ASM_OP
+ readonly_data_section = get_unnamed_section (0, output_section_asm_op,
+ READONLY_DATA_SECTION_ASM_OP);
+#endif
+
+#ifdef CTORS_SECTION_ASM_OP
+ ctors_section = get_unnamed_section (0, output_section_asm_op,
+ CTORS_SECTION_ASM_OP);
+#endif
+
+#ifdef DTORS_SECTION_ASM_OP
+ dtors_section = get_unnamed_section (0, output_section_asm_op,
+ DTORS_SECTION_ASM_OP);
+#endif
+
+#ifdef BSS_SECTION_ASM_OP
+ bss_section = get_unnamed_section (SECTION_WRITE | SECTION_BSS,
+ output_section_asm_op,
+ BSS_SECTION_ASM_OP);
+#endif
+
+#ifdef SBSS_SECTION_ASM_OP
+ sbss_section = get_unnamed_section (SECTION_WRITE | SECTION_BSS,
+ output_section_asm_op,
+ SBSS_SECTION_ASM_OP);
+#endif
+
+ targetm.asm_out.init_sections ();
+
+ if (readonly_data_section == NULL)
+ readonly_data_section = text_section;
}
enum tls_model
&& 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;
part of a COMDAT groups, in which case GAS requires the full
declaration every time. */
if (!(HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
- && ! named_section_first_declaration (name))
+ && (flags & SECTION_DECLARED))
{
fprintf (asm_out_file, "\t.section\t%s\n", name);
return;
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;
\f
/* The lame default section selector. */
-void
+section *
default_select_section (tree decl, int reloc,
unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
{
- bool readonly = false;
-
if (DECL_P (decl))
{
if (decl_readonly_section (decl, reloc))
- readonly = true;
+ return readonly_data_section;
}
else if (TREE_CODE (decl) == CONSTRUCTOR)
{
|| !TREE_READONLY (decl)
|| TREE_SIDE_EFFECTS (decl)
|| !TREE_CONSTANT (decl)))
- readonly = true;
+ return readonly_data_section;
}
else if (TREE_CODE (decl) == STRING_CST)
- readonly = true;
+ return readonly_data_section;
else if (! (flag_pic && reloc))
- readonly = true;
+ return readonly_data_section;
- if (readonly)
- readonly_data_section ();
- else
- data_section ();
+ return data_section;
}
-/* A helper function for default_elf_select_section and
- default_elf_unique_section. Categorizes the DECL. */
-
enum section_category
-{
- SECCAT_TEXT,
-
- SECCAT_RODATA,
- SECCAT_RODATA_MERGE_STR,
- SECCAT_RODATA_MERGE_STR_INIT,
- SECCAT_RODATA_MERGE_CONST,
- SECCAT_SRODATA,
-
- SECCAT_DATA,
-
- /* To optimize loading of shared programs, define following subsections
- of data section:
- _REL Contains data that has relocations, so they get grouped
- together and dynamic linker will visit fewer pages in memory.
- _RO Contains data that is otherwise read-only. This is useful
- with prelinking as most relocations won't be dynamically
- linked and thus stay read only.
- _LOCAL Marks data containing relocations only to local objects.
- These relocations will get fully resolved by prelinking. */
- SECCAT_DATA_REL,
- SECCAT_DATA_REL_LOCAL,
- SECCAT_DATA_REL_RO,
- SECCAT_DATA_REL_RO_LOCAL,
-
- SECCAT_SDATA,
- SECCAT_TDATA,
-
- SECCAT_BSS,
- SECCAT_SBSS,
- SECCAT_TBSS
-};
-
-static enum section_category
-categorize_decl_for_section (tree, int, int);
-
-static enum section_category
categorize_decl_for_section (tree decl, int reloc, int shlib)
{
enum section_category ret;
/* Select a section based on the above categorization. */
-void
+section *
default_elf_select_section (tree decl, int reloc,
unsigned HOST_WIDE_INT align)
{
- default_elf_select_section_1 (decl, reloc, align, flag_pic);
+ return default_elf_select_section_1 (decl, reloc, align, flag_pic);
}
-void
+section *
default_elf_select_section_1 (tree decl, int reloc,
unsigned HOST_WIDE_INT align, int shlib)
{
/* We're not supposed to be called on FUNCTION_DECLs. */
gcc_unreachable ();
case SECCAT_RODATA:
- readonly_data_section ();
- return;
+ return readonly_data_section;
case SECCAT_RODATA_MERGE_STR:
- mergeable_string_section (decl, align, 0);
- return;
+ return mergeable_string_section (decl, align, 0);
case SECCAT_RODATA_MERGE_STR_INIT:
- mergeable_string_section (DECL_INITIAL (decl), align, 0);
- return;
+ return mergeable_string_section (DECL_INITIAL (decl), align, 0);
case SECCAT_RODATA_MERGE_CONST:
- mergeable_constant_section (DECL_MODE (decl), align, 0);
- return;
+ return mergeable_constant_section (DECL_MODE (decl), align, 0);
case SECCAT_SRODATA:
sname = ".sdata2";
break;
case SECCAT_DATA:
- data_section ();
- return;
+ return data_section;
case SECCAT_DATA_REL:
sname = ".data.rel";
break;
sname = ".tdata";
break;
case SECCAT_BSS:
-#ifdef BSS_SECTION_ASM_OP
- bss_section ();
- return;
-#else
+ if (bss_section)
+ return bss_section;
sname = ".bss";
break;
-#endif
case SECCAT_SBSS:
sname = ".sbss";
break;
if (!DECL_P (decl))
decl = NULL_TREE;
- named_section (decl, sname, reloc);
+ return get_named_section (decl, sname, reloc);
}
/* Construct a unique section name based on the decl name and the
prefix = one_only ? ".gnu.linkonce.s2." : ".sdata2.";
break;
case SECCAT_DATA:
+ prefix = one_only ? ".gnu.linkonce.d." : ".data.";
+ break;
case SECCAT_DATA_REL:
+ prefix = one_only ? ".gnu.linkonce.d.rel." : ".data.rel.";
+ break;
case SECCAT_DATA_REL_LOCAL:
+ prefix = one_only ? ".gnu.linkonce.d.rel.local." : ".data.rel.local.";
+ break;
case SECCAT_DATA_REL_RO:
+ prefix = one_only ? ".gnu.linkonce.d.rel.ro." : ".data.rel.ro.";
+ break;
case SECCAT_DATA_REL_RO_LOCAL:
- prefix = one_only ? ".gnu.linkonce.d." : ".data.";
+ prefix = one_only ? ".gnu.linkonce.d.rel.ro.local."
+ : ".data.rel.ro.local.";
break;
case SECCAT_SDATA:
prefix = one_only ? ".gnu.linkonce.s." : ".sdata.";
DECL_SECTION_NAME (decl) = build_string (nlen + plen, string);
}
-void
+section *
default_select_rtx_section (enum machine_mode mode ATTRIBUTE_UNUSED,
rtx x,
unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
case CONST:
case SYMBOL_REF:
case LABEL_REF:
- data_section ();
- return;
+ return data_section;
default:
break;
}
- readonly_data_section ();
+ return readonly_data_section;
}
-void
+section *
default_elf_select_rtx_section (enum machine_mode mode, rtx x,
unsigned HOST_WIDE_INT align)
{
{
case CONST:
case SYMBOL_REF:
- named_section (NULL_TREE, ".data.rel.ro", 3);
- return;
+ return get_named_section (NULL, ".data.rel.ro", 3);
case LABEL_REF:
- named_section (NULL_TREE, ".data.rel.ro.local", 1);
- return;
+ return get_named_section (NULL, ".data.rel.ro.local", 1);
default:
break;
}
- mergeable_constant_section (mode, align, 0);
+ return mergeable_constant_section (mode, align, 0);
}
/* Set the generally applicable flags on the SYMBOL_REF for EXP. */
/* A non-decl is an entry in the constant pool. */
if (!DECL_P (exp))
local_p = true;
+ /* Weakrefs may not bind locally, even though the weakref itself is
+ always static and therefore local. */
+ else if (lookup_attribute ("weakref", DECL_ATTRIBUTES (exp)))
+ local_p = false;
/* Static variables are always local. */
else if (! TREE_PUBLIC (exp))
local_p = true;
- /* A variable is local if the user explicitly tells us so. */
- else if (DECL_VISIBILITY_SPECIFIED (exp) && DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
+ /* A variable is local if the user has said explicitly that it will
+ be. */
+ else if (DECL_VISIBILITY_SPECIFIED (exp)
+ && DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
local_p = true;
- /* Otherwise, variables defined outside this object may not be local. */
+ /* Variables defined outside this object might not be local. */
else if (DECL_EXTERNAL (exp))
local_p = false;
- /* Linkonce and weak data are never local. */
- else if (DECL_ONE_ONLY (exp) || DECL_WEAK (exp))
- local_p = false;
- /* If none of the above and visibility is not default, make local. */
+ /* If defined in this object and visibility is not default, must be
+ local. */
else if (DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
local_p = true;
+ /* Default visibility weak data can be overridden by a strong symbol
+ in another module and so are not local. */
+ 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. */
else if (shlib)
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
if (trampolines_created)
flags |= SECTION_CODE;
- named_section_flags (".note.GNU-stack", flags);
+ switch_to_section (get_section (".note.GNU-stack", flags, NULL));
+}
+
+/* Output DIRECTIVE (a C string) followed by a newline. This is used as
+ a get_unnamed_section callback. */
+
+void
+output_section_asm_op (const void *directive)
+{
+ fprintf (asm_out_file, "%s\n", (const char *) directive);
+}
+
+/* Emit assembly code to switch to section NEW_SECTION. Do nothing if
+ the current section is NEW_SECTION. */
+
+void
+switch_to_section (section *new_section)
+{
+ if (in_section == new_section)
+ return;
+
+ if (new_section->common.flags & SECTION_FORGET)
+ in_section = NULL;
+ else
+ in_section = new_section;
+
+ if (new_section->common.flags & SECTION_NAMED)
+ {
+ if (cfun
+ && !cfun->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;
+
+ targetm.asm_out.named_section (new_section->named.name,
+ new_section->named.common.flags,
+ new_section->named.decl);
+ }
+ else
+ new_section->unnamed.callback (new_section->unnamed.data);
+
+ new_section->common.flags |= SECTION_DECLARED;
}
#include "gt-varasm.h"