/* 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 Free Software Foundation, Inc.
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ Free Software Foundation, Inc.
This file is part of GCC.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
/* This file handles generation of all the assembler code
#include "tree-mudflap.h"
#include "cgraph.h"
#include "cfglayout.h"
+#include "basic-block.h"
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h" /* Needed for external data
#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;
tree last_assemble_variable_decl;
-/* The following global variable indicates if the section label for the
- "cold" section of code has been output yet to the assembler. The
- label is useful when running gdb. This is part of the optimization that
- partitions hot and cold basic blocks into separate sections of the .o
- file. */
-
-static bool unlikely_section_label_printed = false;
-
-/* The following global variable indicates the label name to be put at
- the start of the first cold section within each function, when
- partitioning basic blocks into hot and cold sections. */
-
-static char *unlikely_section_label = NULL;
-
-/* The following global variable indicates the section name to be used
- for the current cold section, when partitioning hot and cold basic
- blocks into separate sections. */
+/* The following global variable indicates if the first basic block
+ in a function belongs to the cold partition or not. */
-static char *unlikely_text_section_name = NULL;
+bool first_function_block_is_cold;
/* We give all constants their own alias set. Perhaps redundant with
MEM_READONLY_P, but pre-dates it. */
static 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 *);
#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
-enum in_section { no_section, in_text, in_unlikely_executed_text, in_data,
- in_named
-#ifdef BSS_SECTION_ASM_OP
- , in_bss
-#endif
-#ifdef CTORS_SECTION_ASM_OP
- , in_ctors
-#endif
-#ifdef DTORS_SECTION_ASM_OP
- , in_dtors
-#endif
-#ifdef READONLY_DATA_SECTION_ASM_OP
- , in_readonly_data
-#endif
-#ifdef EXTRA_SECTIONS
- , EXTRA_SECTIONS
-#endif
-};
-static GTY(()) enum in_section in_section = no_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;
+/* 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;
-};
-
-static GTY((param_is (struct in_named_entry))) htab_t in_named_htab;
-
-/* Define functions like text_section for any extra sections. */
-#ifdef EXTRA_SECTION_FUNCTIONS
-EXTRA_SECTION_FUNCTIONS
-#endif
+ const section *old = p1;
+ const char *new = p2;
-/* Tell assembler to switch to text section. */
+ return strcmp (old->named.name, new) == 0;
+}
-void
-text_section (void)
+static hashval_t
+section_entry_hash (const void *p)
{
- if (in_section != in_text)
- {
- in_section = in_text;
- fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
- }
+ const section *old = p;
+ return htab_hash_string (old->named.name);
}
-/* Tell assembler to switch to unlikely-to-be-executed text section. */
+/* Return a new unnamed section with the given fields. */
-void
-unlikely_text_section (void)
+section *
+get_unnamed_section (unsigned int flags, void (*callback) (const void *),
+ const void *data)
{
- const char *name;
- int len;
-
- if (! unlikely_text_section_name)
- {
- if (DECL_SECTION_NAME (current_function_decl)
- && (strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME
- (current_function_decl)),
- HOT_TEXT_SECTION_NAME) != 0)
- && (strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME
- (current_function_decl)),
- UNLIKELY_EXECUTED_TEXT_SECTION_NAME) != 0))
- {
- name = TREE_STRING_POINTER (DECL_SECTION_NAME
- (current_function_decl));
- len = strlen (name);
- unlikely_text_section_name = xmalloc ((len + 10) * sizeof (char));
- strcpy (unlikely_text_section_name, name);
- strcat (unlikely_text_section_name, "_unlikely");
- }
- else
- {
- len = strlen (UNLIKELY_EXECUTED_TEXT_SECTION_NAME);
- unlikely_text_section_name = xmalloc (len+1 * sizeof (char));
- strcpy (unlikely_text_section_name,
- UNLIKELY_EXECUTED_TEXT_SECTION_NAME);
- }
- }
+ section *sect;
- if ((in_section != in_unlikely_executed_text)
- && (in_section != in_named
- || strcmp (in_named_name, unlikely_text_section_name) != 0))
- {
- named_section (NULL_TREE, unlikely_text_section_name, 0);
- in_section = in_unlikely_executed_text;
+ 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;
- if (!unlikely_section_label_printed)
- {
- ASM_OUTPUT_LABEL (asm_out_file, unlikely_section_label);
- unlikely_section_label_printed = true;
- }
- }
+ unnamed_sections = sect;
+ return sect;
}
-/* Tell assembler to switch to data section. */
+/* Return the named section structure associated with NAME. Create
+ a new section with the given fields if no such structure exists. */
-void
-data_section (void)
+section *
+get_section (const char *name, unsigned int flags, tree decl)
{
- if (in_section != in_data)
+ section *sect, **slot;
+
+ slot = (section **)
+ htab_find_slot_with_hash (section_htab, name,
+ htab_hash_string (name), INSERT);
+ flags |= SECTION_NAMED;
+ if (*slot == NULL)
{
- in_section = in_data;
- fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
+ sect = ggc_alloc (sizeof (struct named_section));
+ sect->named.common.flags = flags;
+ sect->named.name = ggc_strdup (name);
+ sect->named.decl = decl;
+ *slot = sect;
}
-}
-
-/* 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)
+ else
{
- in_section = in_readonly_data;
- fputs (READONLY_DATA_SECTION_ASM_OP, asm_out_file);
- fputc ('\n', asm_out_file);
+ 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);
+ }
}
-#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;
-
- ret_val = ((in_section == in_unlikely_executed_text)
- || (in_section == in_named
- && unlikely_text_section_name
- && strcmp (in_named_name, unlikely_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);
+ return sect;
}
-/* 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)
+static void
+initialize_cold_section_name (void)
{
- struct in_named_entry **slot;
+ const char *stripped_name;
+ char *name, *buffer;
+ tree dsn;
- 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;
-}
+ gcc_assert (cfun && current_function_decl);
+ if (cfun->unlikely_text_section_name)
+ return;
-/* 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. */
+ dsn = DECL_SECTION_NAME (current_function_decl);
+ if (flag_function_sections && dsn)
+ {
+ name = alloca (TREE_STRING_LENGTH (dsn) + 1);
+ memcpy (name, TREE_STRING_POINTER (dsn), TREE_STRING_LENGTH (dsn) + 1);
-bool
-named_section_first_declaration (const char *name)
-{
- struct in_named_entry **slot;
+ stripped_name = targetm.strip_name_encoding (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;
+ buffer = ACONCAT ((stripped_name, "_unlikely", NULL));
+ cfun->unlikely_text_section_name = ggc_strdup (buffer);
}
else
- {
- return false;
- }
+ cfun->unlikely_text_section_name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
}
+/* Tell assembler to switch to unlikely-to-be-executed text section. */
-/* Record FLAGS for SECTION. If SECTION was previously recorded with a
- different set of flags, return false. */
-
-bool
-set_named_section_flags (const char *section, unsigned int flags)
+section *
+unlikely_text_section (void)
{
- 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)
+ if (cfun)
{
- 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;
+ if (!cfun->unlikely_text_section_name)
+ initialize_cold_section_name ();
- return true;
+ return get_named_section (NULL, cfun->unlikely_text_section_name, 0);
+ }
+ else
+ return get_named_section (NULL, UNLIKELY_EXECUTED_TEXT_SECTION_NAME, 0);
}
-/* 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. */
+/* 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. */
-void
-named_section_real (const char *name, unsigned int flags, tree decl)
+bool
+unlikely_text_section_p (section *sect)
{
- if (in_section != in_named || strcmp (name, in_named_name) != 0)
- {
- if (! set_named_section_flags (name, flags))
- abort ();
+ const char *name;
- targetm.asm_out.named_section (name, flags, decl);
+ if (cfun)
+ name = cfun->unlikely_text_section_name;
+ else
+ name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
- if (flags & SECTION_FORGET)
- in_section = no_section;
- else
- {
- in_named_name = ggc_strdup (name);
- in_section = in_named;
- }
- }
+ 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 (decl != NULL_TREE && !DECL_P (decl))
- abort ();
+ gcc_assert (!decl || DECL_P (decl));
if (name == NULL)
name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
- if (strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0
- && !unlikely_text_section_name)
- {
- unlikely_text_section_name = xmalloc
- (strlen (UNLIKELY_EXECUTED_TEXT_SECTION_NAME) + 1
- * sizeof (char));
- strcpy (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 abort 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 ("%J%D causes a section type conflict", decl, 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)
{
- if (decl == NULL_TREE)
- text_section ();
- else
- {
- /* ??? Typical use of this function maybe shouldn't be looking
- for unlikely blocks at all - in the event that an entire
- function is going into the unlikely-execute section, that
- should be reflected in its DECL_SECTION_NAME. */
- rtx insns = cfun && cfun->emit ? get_insns () : 0;
- bool unlikely = insns && scan_ahead_for_unlikely_executed_note (insns);
+ int reloc = 0;
+
+ if (first_function_block_is_cold)
+ reloc = 1;
#ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
- targetm.asm_out.select_section (decl, unlikely, DECL_ALIGN (decl));
+ return targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
#else
- if (unlikely)
- unlikely_text_section ();
- else if (DECL_SECTION_NAME (decl))
- named_section (decl, 0, 0);
- else
- text_section ();
+ return hot_function_section (decl);
+#endif
+}
+
+section *
+current_function_section (void)
+{
+#ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
+ return targetm.asm_out.select_section (current_function_decl,
+ in_cold_section_p,
+ DECL_ALIGN (current_function_decl));
+#else
+ 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))
{
const char *name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
+ if (DECL_ONE_ONLY (decl) && HAVE_COMDAT_GROUP)
+ {
+ size_t len = strlen (name) + 3;
+ char* rname = alloca (len);
+
+ strcpy (rname, ".rodata");
+ strcat (rname, name + 5);
+ return get_section (rname, SECTION_LINKONCE, decl);
+ }
/* For .gnu.linkonce.t.foo we want to use .gnu.linkonce.r.foo. */
- if (DECL_ONE_ONLY (decl) && strncmp (name, ".gnu.linkonce.t.", 16) == 0)
+ else if (DECL_ONE_ONLY (decl)
+ && strncmp (name, ".gnu.linkonce.t.", 16) == 0)
{
size_t len = strlen (name) + 1;
char *rname = alloca (len);
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 */
rtx x;
/* Check that we are not being given an automatic variable. */
+ gcc_assert (TREE_CODE (decl) != PARM_DECL
+ && TREE_CODE (decl) != RESULT_DECL);
+
/* A weak alias has TREE_PUBLIC set but not the other bits. */
- if (TREE_CODE (decl) == PARM_DECL
- || TREE_CODE (decl) == RESULT_DECL
- || (TREE_CODE (decl) == VAR_DECL
- && !TREE_STATIC (decl)
- && !TREE_PUBLIC (decl)
- && !DECL_EXTERNAL (decl)
- && !DECL_REGISTER (decl)))
- abort ();
+ gcc_assert (TREE_CODE (decl) != VAR_DECL
+ || TREE_STATIC (decl)
+ || TREE_PUBLIC (decl)
+ || DECL_EXTERNAL (decl)
+ || DECL_REGISTER (decl));
+
/* And that we were not given a type or a label. */
- else if (TREE_CODE (decl) == TYPE_DECL
- || TREE_CODE (decl) == LABEL_DECL)
- abort ();
+ gcc_assert (TREE_CODE (decl) != TYPE_DECL
+ && TREE_CODE (decl) != LABEL_DECL);
/* For a duplicate declaration, we can be called twice on the
same DECL node. Don't discard the RTL already made. */
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))
+ {
+ error ("register name not specified for %q+D", decl);
+ }
+ else if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
{
- reg_number = decode_reg_name (name);
+ const char *asmspec = name+1;
+ reg_number = decode_reg_name (asmspec);
/* First detect errors in declaring global registers. */
if (reg_number == -1)
- error ("%Jregister name not specified for %qD", decl, decl);
+ error ("register name not specified for %q+D", decl);
else if (reg_number < 0)
- error ("%Jinvalid register name for %qD", decl, decl);
+ error ("invalid register name for %q+D", decl);
else if (TYPE_MODE (TREE_TYPE (decl)) == BLKmode)
- error ("%Jdata type of %qD isn%'t suitable for a register",
- decl, decl);
+ error ("data type of %q+D isn%'t suitable for a register",
+ decl);
else if (! HARD_REGNO_MODE_OK (reg_number, TYPE_MODE (TREE_TYPE (decl))))
- error ("%Jregister specified for %qD isn%'t suitable for data type",
- decl, decl);
+ error ("register specified for %q+D isn%'t suitable for data type",
+ decl);
/* Now handle properly declared static register variables. */
else
{
error ("global register variable has initial value");
}
if (TREE_THIS_VOLATILE (decl))
- warning ("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
/* Make this register global, so not usable for anything
else. */
#ifdef ASM_DECLARE_REGISTER_GLOBAL
+ name = IDENTIFIER_POINTER (DECL_NAME (decl));
ASM_DECLARE_REGISTER_GLOBAL (asm_out_file, decl, reg_number, name);
#endif
nregs = hard_regno_nregs[reg_number][DECL_MODE (decl)];
{
reg_number = decode_reg_name (name);
if (reg_number >= 0 || reg_number == -3)
- error ("%Jregister name given for non-register variable %qD", decl, decl);
+ error ("register name given for non-register variable %q+D", decl);
}
#endif
}
void
make_var_volatile (tree var)
{
- if (!MEM_P (DECL_RTL (var)))
- abort ();
+ gcc_assert (MEM_P (DECL_RTL (var)));
MEM_VOLATILE_P (DECL_RTL (var)) = 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 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;
}
assemble_start_function (tree decl, const char *fnname)
{
int align;
+ char tmp_label[100];
+ bool hot_label_written = false;
- if (unlikely_text_section_name)
- free (unlikely_text_section_name);
+ cfun->unlikely_text_section_name = NULL;
+
+ first_function_block_is_cold = false;
+ if (flag_reorder_blocks_and_partition)
+ {
+ ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LHOTB", const_labelno);
+ cfun->hot_section_label = ggc_strdup (tmp_label);
+ ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LCOLDB", const_labelno);
+ cfun->cold_section_label = ggc_strdup (tmp_label);
+ ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LHOTE", const_labelno);
+ cfun->hot_section_end_label = ggc_strdup (tmp_label);
+ ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LCOLDE", const_labelno);
+ cfun->cold_section_end_label = ggc_strdup (tmp_label);
+ const_labelno++;
+ }
+ else
+ {
+ cfun->hot_section_label = NULL;
+ cfun->cold_section_label = NULL;
+ cfun->hot_section_end_label = NULL;
+ cfun->cold_section_end_label = NULL;
+ }
- unlikely_section_label_printed = false;
- unlikely_text_section_name = NULL;
-
- unlikely_section_label = reconcat (unlikely_section_label,
- fnname, ".unlikely_section", NULL);
-
/* The following code does not need preprocessing in the assembler. */
app_disable ();
if (CONSTANT_POOL_BEFORE_FUNCTION)
output_constant_pool (fnname, decl);
- /* Make sure the cold text (code) section is properly aligned. This
- is necessary here in the case where the function has both hot and
- cold sections, because we don't want to re-set the alignment when the
- section switch happens mid-function. We don't need to set the hot
- section alignment here, because code further down in this function
- sets the alignment for whichever section comes first, and if there
- is a hot section it is guaranteed to be first. */
+ resolve_unique_section (decl, 0, flag_function_sections);
+
+ /* Make sure the not and cold text (code) sections are properly
+ aligned. This is necessary here in the case where the function
+ has both hot and cold sections, because we don't want to re-set
+ the alignment when the section switch happens mid-function. */
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);
+
+ /* 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)
+ {
+ switch_to_section (text_section);
+ assemble_align (FUNCTION_BOUNDARY);
+ ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_label);
+ hot_label_written = true;
+ first_function_block_is_cold = true;
+ }
}
+ else if (DECL_SECTION_NAME (decl))
+ {
+ /* Calls to function_section rely on first_function_block_is_cold
+ being accurate. The first block may be cold even if we aren't
+ doing partitioning, if the entire function was decided by
+ choose_function_section (predict.c) to be cold. */
- resolve_unique_section (decl, 0, flag_function_sections);
- function_section (decl);
+ initialize_cold_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;
+ }
+
+ in_cold_section_p = first_function_block_is_cold;
+
+ /* Switch to the correct text section for the start of the function. */
+
+ 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);
/* Tell assembler to move to target machine's alignment for functions. */
align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
/* Standard thing is just output label for the function. */
ASM_OUTPUT_LABEL (asm_out_file, fnname);
#endif /* ASM_DECLARE_FUNCTION_NAME */
-
- if (in_unlikely_text_section ()
- && !unlikely_section_label_printed)
- {
- ASM_OUTPUT_LABEL (asm_out_file, unlikely_section_label);
- unlikely_section_label_printed = true;
- }
}
/* 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)
+ {
+ section *save_text_section;
+
+ save_text_section = in_section;
+ switch_to_section (unlikely_text_section ());
+ ASM_OUTPUT_LABEL (asm_out_file, cfun->cold_section_end_label);
+ if (first_function_block_is_cold)
+ switch_to_section (text_section);
+ else
+ switch_to_section (function_section (decl));
+ ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_end_label);
+ 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++)
ASM_EMIT_LOCAL (decl, name, size, rounded);
break;
default:
- abort ();
+ gcc_unreachable ();
}
return true;
if (!dont_output_data && DECL_SIZE (decl) == 0)
{
- error ("%Jstorage size of %qD isn%'t known", decl, decl);
+ error ("storage size of %q+D isn%'t known", decl);
TREE_ASM_WRITTEN (decl) = 1;
return;
}
if (! dont_output_data
&& ! host_integerp (DECL_SIZE_UNIT (decl), 1))
{
- error ("%Jsize of variable %qD is too large", decl, decl);
+ error ("size of variable %q+D is too large", decl);
return;
}
In particular, a.out format supports a maximum alignment of 4. */
if (align > MAX_OFILE_ALIGNMENT)
{
- warning ("%Jalignment of %qD is greater than maximum object "
- "file alignment. Using %d", decl, decl,
+ 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;
}
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 (decl))
+ 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 ("%Jrequested alignment for %qD is greater than "
- "implemented alignment of %d", decl, 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
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. */
mark_decl_referenced (tree decl)
{
if (TREE_CODE (decl) == FUNCTION_DECL)
- cgraph_mark_needed_node (cgraph_node (decl));
+ {
+ /* Extern inline functions don't become needed when referenced.
+ If we know a method will be emitted in other TU and no new
+ functions can be marked reachable, just use the external
+ definition. */
+ struct cgraph_node *node = cgraph_node (decl);
+ if (!DECL_EXTERNAL (decl)
+ && (!node->local.vtable_method || !cgraph_global_info_ready
+ || !node->local.finalized))
+ cgraph_mark_needed_node (node);
+ }
else if (TREE_CODE (decl) == VAR_DECL)
- cgraph_varpool_mark_needed_node (cgraph_varpool_node (decl));
+ {
+ struct cgraph_varpool_node *node = cgraph_varpool_node (decl);
+ cgraph_varpool_mark_needed_node (node);
+ /* C++ frontend use mark_decl_references to force COMDAT variables
+ to be output that might appear dead otherwise. */
+ node->force_output = true;
+ }
/* else do nothing - we can get various sorts of CST nodes here,
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. */
/* Assemble the integer constant X into an object of SIZE bytes. ALIGN is
the alignment of the integer in bits. Return 1 if we were able to output
- the constant, otherwise 0. If FORCE is nonzero, abort if we can't output
- the constant. */
+ the constant, otherwise 0. We must be able to output the constant,
+ if FORCE is nonzero. */
bool
assemble_integer (rtx x, unsigned int size, unsigned int align, int force)
/* If we've printed some of it, but not all of it, there's no going
back now. */
- if (i > 0)
- abort ();
+ gcc_assert (!i);
}
- if (force)
- abort ();
+ gcc_assert (!force);
return false;
}
/* Given an expression EXP with a constant value,
reduce it to the sum of an assembler symbol and an integer.
Store them both in the structure *VALUE.
- Abort if EXP does not reduce. */
+ EXP must be reducible. */
struct addr_const GTY(())
{
case LABEL_DECL:
x = gen_rtx_MEM (FUNCTION_MODE,
- gen_rtx_LABEL_REF (VOIDmode, force_label_rtx (target)));
+ gen_rtx_LABEL_REF (Pmode, force_label_rtx (target)));
break;
case REAL_CST:
break;
default:
- abort ();
+ gcc_unreachable ();
}
- if (!MEM_P (x))
- abort ();
+ gcc_assert (MEM_P (x));
x = XEXP (x, 0);
value->base = x;
/* The value of the constant. */
tree value;
+
+ /* Hash of value. Computing the hash from value each time
+ hashfn is called can't work properly, as that means recursive
+ use of the hash table during hash table expansion. */
+ hashval_t hash;
};
static GTY((param_is (struct constant_descriptor_tree)))
static hashval_t
const_desc_hash (const void *ptr)
{
- return const_hash_1 (((struct constant_descriptor_tree *)ptr)->value);
+ return ((struct constant_descriptor_tree *)ptr)->hash;
}
static hashval_t
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;
}
struct addr_const value;
decode_addr_const (exp, &value);
- if (GET_CODE (value.base) == SYMBOL_REF)
+ switch (GET_CODE (value.base))
{
+ case SYMBOL_REF:
/* Don't hash the address of the SYMBOL_REF;
only use the offset and the symbol name. */
hi = value.offset;
p = XSTR (value.base, 0);
for (i = 0; p[i] != 0; i++)
hi = ((hi * 613) + (unsigned) (p[i]));
+ break;
+
+ case LABEL_REF:
+ hi = value.offset + CODE_LABEL_NUMBER (XEXP (value.base, 0)) * 13;
+ break;
+
+ default:
+ gcc_unreachable ();
}
- else if (GET_CODE (value.base) == LABEL_REF)
- hi = value.offset + CODE_LABEL_NUMBER (XEXP (value.base, 0)) * 13;
- else
- abort ();
}
return hi;
static int
const_desc_eq (const void *p1, const void *p2)
{
- return compare_constant (((struct constant_descriptor_tree *)p1)->value,
- ((struct constant_descriptor_tree *)p2)->value);
+ const struct constant_descriptor_tree *c1 = p1;
+ const struct constant_descriptor_tree *c2 = p2;
+ if (c1->hash != c2->hash)
+ return 0;
+ return compare_constant (c1->value, c2->value);
}
/* Compare t1 and t2, and return 1 only if they are known to result in
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:
}
}
- /* Should not get here. */
- abort ();
+ gcc_unreachable ();
}
\f
/* Make a copy of the whole tree structure for a constant. This
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;
- t = lang_hooks.expand_constant (exp);
- if (t != exp)
- return copy_constant (t);
- else
- abort ();
+ tree t = lang_hooks.expand_constant (exp);
+
+ gcc_assert (t == exp);
+ return copy_constant (t);
}
}
}
/* Look up EXP in the table of constant descriptors. If we didn't find
it, create a new one. */
key.value = exp;
- loc = htab_find_slot (const_desc_htab, &key, INSERT);
+ key.hash = const_hash_1 (exp);
+ loc = htab_find_slot_with_hash (const_desc_htab, &key, key.hash, INSERT);
desc = *loc;
if (desc == 0)
{
desc = build_constant_desc (exp);
+ desc->hash = key.hash;
*loc = desc;
}
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)
{
struct constant_descriptor_tree key;
key.value = exp;
- desc = htab_find (const_desc_htab, &key);
+ key.hash = const_hash_1 (exp);
+ desc = htab_find_with_hash (const_desc_htab, &key, key.hash);
return (desc ? desc->rtl : NULL_RTX);
}
h ^= real_hash (CONST_DOUBLE_REAL_VALUE (x));
break;
+ case CONST_VECTOR:
+ {
+ int i;
+ for (i = XVECLEN (x, 0); i-- > 0; )
+ h = h * 251 + const_rtx_hash_1 (&XVECEXP (x, 0, i), data);
+ }
+ break;
+
case SYMBOL_REF:
h ^= htab_hash_string (XSTR (x, 0));
break;
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);
/* Insert the descriptor into the symbol cross-reference table too. */
slot = htab_find_slot (pool->const_rtx_sym_htab, desc, INSERT);
- if (*slot)
- abort ();
+ gcc_assert (!*slot);
*slot = desc;
/* Construct the MEM. */
switch (GET_MODE_CLASS (mode))
{
case MODE_FLOAT:
- if (GET_CODE (x) != CONST_DOUBLE)
- abort ();
- else
- {
- REAL_VALUE_TYPE r;
- REAL_VALUE_FROM_CONST_DOUBLE (r, x);
- assemble_real (r, mode, align);
- }
- break;
+ 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:
enum machine_mode submode = GET_MODE_INNER (mode);
unsigned int subalign = MIN (align, GET_MODE_BITSIZE (submode));
- if (GET_CODE (x) != CONST_VECTOR)
- abort ();
+ gcc_assert (GET_CODE (x) == CONST_VECTOR);
units = CONST_VECTOR_NUNITS (x);
for (i = 0; i < units; i++)
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
case LABEL_REF:
tmp = XEXP (x, 0);
- if (INSN_DELETED_P (tmp)
- || (NOTE_P (tmp)
- && NOTE_LINE_NUMBER (tmp) == NOTE_INSN_DELETED))
- {
- abort ();
- x = const0_rtx;
- }
+ gcc_assert (!INSN_DELETED_P (tmp));
+ gcc_assert (!NOTE_P (tmp)
+ || NOTE_LINE_NUMBER (tmp) != NOTE_INSN_DELETED);
break;
default:
}
/* 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
case NOP_EXPR:
case CONVERT_EXPR:
case NON_LVALUE_EXPR:
+ case VIEW_CONVERT_EXPR:
reloc = compute_reloc_for_constant (TREE_OPERAND (exp, 0));
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:
case NOP_EXPR:
case CONVERT_EXPR:
case NON_LVALUE_EXPR:
+ case VIEW_CONVERT_EXPR:
output_addressed_constants (TREE_OPERAND (exp, 0));
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;
+ 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:
case CONVERT_EXPR:
case NOP_EXPR:
- /* Allow conversions between pointer types. */
- if (POINTER_TYPE_P (TREE_TYPE (value))
- && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
- return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
-
- /* Allow conversions between real types. */
- if (FLOAT_TYPE_P (TREE_TYPE (value))
- && FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
- return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
-
- /* Allow length-preserving conversions between integer types. */
- if (INTEGRAL_TYPE_P (TREE_TYPE (value))
- && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))
- && (TYPE_PRECISION (TREE_TYPE (value))
- == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
- return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
-
- /* Allow conversions between other integer types only if
- explicit value. */
- if (INTEGRAL_TYPE_P (TREE_TYPE (value))
- && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
- {
- tree inner = initializer_constant_valid_p (TREE_OPERAND (value, 0),
- endtype);
- if (inner == null_pointer_node)
- return null_pointer_node;
- break;
- }
+ {
+ tree src;
+ tree src_type;
+ tree dest_type;
+
+ src = TREE_OPERAND (value, 0);
+ src_type = TREE_TYPE (src);
+ dest_type = TREE_TYPE (value);
+
+ /* Allow conversions between pointer types, floating-point
+ types, and offset types. */
+ if ((POINTER_TYPE_P (dest_type) && POINTER_TYPE_P (src_type))
+ || (FLOAT_TYPE_P (dest_type) && FLOAT_TYPE_P (src_type))
+ || (TREE_CODE (dest_type) == OFFSET_TYPE
+ && TREE_CODE (src_type) == OFFSET_TYPE))
+ return initializer_constant_valid_p (src, endtype);
+
+ /* Allow length-preserving conversions between integer types. */
+ if (INTEGRAL_TYPE_P (dest_type) && INTEGRAL_TYPE_P (src_type)
+ && (TYPE_PRECISION (dest_type) == TYPE_PRECISION (src_type)))
+ return initializer_constant_valid_p (src, endtype);
+
+ /* Allow conversions between other integer types only if
+ explicit value. */
+ if (INTEGRAL_TYPE_P (dest_type) && INTEGRAL_TYPE_P (src_type))
+ {
+ tree inner = initializer_constant_valid_p (src, endtype);
+ if (inner == null_pointer_node)
+ return null_pointer_node;
+ break;
+ }
- /* Allow (int) &foo provided int is as wide as a pointer. */
- if (INTEGRAL_TYPE_P (TREE_TYPE (value))
- && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))
- && (TYPE_PRECISION (TREE_TYPE (value))
- >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
- return initializer_constant_valid_p (TREE_OPERAND (value, 0),
- endtype);
-
- /* Likewise conversions from int to pointers, but also allow
- conversions from 0. */
- if ((POINTER_TYPE_P (TREE_TYPE (value))
- || TREE_CODE (TREE_TYPE (value)) == OFFSET_TYPE)
- && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
- {
- if (integer_zerop (TREE_OPERAND (value, 0)))
- return null_pointer_node;
- else if (TYPE_PRECISION (TREE_TYPE (value))
- <= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0))))
- return initializer_constant_valid_p (TREE_OPERAND (value, 0),
- endtype);
- }
+ /* Allow (int) &foo provided int is as wide as a pointer. */
+ if (INTEGRAL_TYPE_P (dest_type) && POINTER_TYPE_P (src_type)
+ && (TYPE_PRECISION (dest_type) >= TYPE_PRECISION (src_type)))
+ return initializer_constant_valid_p (src, endtype);
- /* Allow conversions to struct or union types if the value
- inside is okay. */
- if (TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE
- || TREE_CODE (TREE_TYPE (value)) == UNION_TYPE)
- return initializer_constant_valid_p (TREE_OPERAND (value, 0),
- endtype);
+ /* Likewise conversions from int to pointers, but also allow
+ conversions from 0. */
+ if ((POINTER_TYPE_P (dest_type)
+ || TREE_CODE (dest_type) == OFFSET_TYPE)
+ && INTEGRAL_TYPE_P (src_type))
+ {
+ if (integer_zerop (src))
+ return null_pointer_node;
+ else if (TYPE_PRECISION (dest_type) <= TYPE_PRECISION (src_type))
+ return initializer_constant_valid_p (src, endtype);
+ }
+
+ /* Allow conversions to struct or union types if the value
+ inside is okay. */
+ if (TREE_CODE (dest_type) == RECORD_TYPE
+ || TREE_CODE (dest_type) == UNION_TYPE)
+ return initializer_constant_valid_p (src, endtype);
+ }
break;
case PLUS_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 decl = TREE_OPERAND (exp, 0);
ASM_OUTPUT_FDESC (asm_out_file, decl, part);
#else
- abort ();
+ gcc_unreachable ();
#endif
return;
}
case ARRAY_TYPE:
case VECTOR_TYPE:
- if (TREE_CODE (exp) == CONSTRUCTOR)
+ switch (TREE_CODE (exp))
{
+ case CONSTRUCTOR:
output_constructor (exp, size, align);
return;
- }
- else if (TREE_CODE (exp) == STRING_CST)
- {
+ case STRING_CST:
thissize = MIN ((unsigned HOST_WIDE_INT)TREE_STRING_LENGTH (exp),
size);
assemble_string (TREE_STRING_POINTER (exp), thissize);
- }
- else if (TREE_CODE (exp) == VECTOR_CST)
- {
- int elt_size;
- tree link;
- unsigned int nalign;
- enum machine_mode inner;
+ break;
+
+ case VECTOR_CST:
+ {
+ int elt_size;
+ tree link;
+ unsigned int nalign;
+ enum machine_mode inner;
- inner = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
- nalign = MIN (align, GET_MODE_ALIGNMENT (inner));
+ inner = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
+ nalign = MIN (align, GET_MODE_ALIGNMENT (inner));
- elt_size = GET_MODE_SIZE (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)
- output_constant (TREE_VALUE (link), elt_size, nalign);
+ link = TREE_VECTOR_CST_ELTS (exp);
+ output_constant (TREE_VALUE (link), elt_size, align);
+ while ((link = TREE_CHAIN (link)) != NULL)
+ output_constant (TREE_VALUE (link), elt_size, nalign);
+ break;
+ }
+ default:
+ gcc_unreachable ();
}
- else
- abort ();
break;
case RECORD_TYPE:
case UNION_TYPE:
- if (TREE_CODE (exp) == CONSTRUCTOR)
- output_constructor (exp, size, align);
- else
- abort ();
+ gcc_assert (TREE_CODE (exp) == CONSTRUCTOR);
+ output_constructor (exp, size, align);
return;
case ERROR_MARK:
return;
default:
- abort ();
+ gcc_unreachable ();
}
if (size > thissize)
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;
- if (HOST_BITS_PER_WIDE_INT < BITS_PER_UNIT)
- abort ();
+ gcc_assert (HOST_BITS_PER_WIDE_INT >= BITS_PER_UNIT);
if (TREE_CODE (type) == RECORD_TYPE)
field = TYPE_FIELDS (type);
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;
}
fieldsize = array_size_for_constructor (val);
/* Given a non-empty initialization, this field had
better be last. */
- if (fieldsize != 0 && TREE_CHAIN (field) != NULL_TREE)
- abort ();
+ gcc_assert (!fieldsize || !TREE_CHAIN (field));
}
else if (DECL_SIZE_UNIT (field))
{
/* 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;
}
/* Now get the bits from the appropriate constant word. */
if (shift < HOST_BITS_PER_WIDE_INT)
value = TREE_INT_CST_LOW (val);
- else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
+ else
{
+ gcc_assert (shift < 2 * HOST_BITS_PER_WIDE_INT);
value = TREE_INT_CST_HIGH (val);
shift -= HOST_BITS_PER_WIDE_INT;
}
- else
- abort ();
/* Get the result. This works only when:
1 <= this_time <= HOST_BITS_PER_WIDE_INT. */
/* Now get the bits from the appropriate constant word. */
if (shift < HOST_BITS_PER_WIDE_INT)
value = TREE_INT_CST_LOW (val);
- else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
+ else
{
+ gcc_assert (shift < 2 * HOST_BITS_PER_WIDE_INT);
value = TREE_INT_CST_HIGH (val);
shift -= HOST_BITS_PER_WIDE_INT;
}
- else
- abort ();
/* Get the result. This works only when:
1 <= this_time <= HOST_BITS_PER_WIDE_INT. */
merge_weak (tree newdecl, tree olddecl)
{
if (DECL_WEAK (newdecl) == DECL_WEAK (olddecl))
- return;
+ {
+ if (DECL_WEAK (newdecl) && SUPPORTS_WEAK)
+ {
+ tree *pwd;
+ /* We put the NEWDECL on the weak_decls list at some point
+ and OLDDECL as well. Keep just OLDDECL on the list. */
+ for (pwd = &weak_decls; *pwd; pwd = &TREE_CHAIN (*pwd))
+ if (TREE_VALUE (*pwd) == newdecl)
+ {
+ *pwd = TREE_CHAIN (*pwd);
+ break;
+ }
+ }
+ return;
+ }
if (DECL_WEAK (newdecl))
{
declare_weak because the NEWDECL and OLDDECL was not yet
been merged; therefore, TREE_ASM_WRITTEN was not set. */
if (TREE_ASM_WRITTEN (olddecl))
- error ("%Jweak declaration of %qD must precede definition",
- newdecl, newdecl);
+ error ("weak declaration of %q+D must precede definition",
+ newdecl);
/* If we've already generated rtl referencing OLDDECL, we may
have done so in a way that will not function properly with
a weak symbol. */
else if (TREE_USED (olddecl)
&& TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (olddecl)))
- warning ("%Jweak declaration of %qD after first use results "
- "in unspecified behavior", newdecl, newdecl);
+ warning (0, "weak declaration of %q+D after first use results "
+ "in unspecified behavior", newdecl);
if (SUPPORTS_WEAK)
{
declare_weak (tree decl)
{
if (! TREE_PUBLIC (decl))
- error ("%Jweak declaration of %qD must be public", decl, decl);
+ error ("weak declaration of %q+D must be public", decl);
else if (TREE_CODE (decl) == FUNCTION_DECL && TREE_ASM_WRITTEN (decl))
- error ("%Jweak declaration of %qD must precede definition", decl, decl);
+ error ("weak declaration of %q+D must precede definition", decl);
else if (SUPPORTS_WEAK)
{
if (! DECL_WEAK (decl))
weak_decls = tree_cons (NULL, decl, weak_decls);
}
else
- warning ("%Jweak declaration of %qD not supported", decl, decl);
+ warning (0, "weak declaration of %q+D not supported", decl);
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 ("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)
targetm.asm_out.globalize_label (asm_out_file, name);
}
-/* Emit an assembler directive to make the symbol for DECL an alias to
- the symbol for TARGET. */
+/* We have to be able to tell cgraph about the needed-ness of the target
+ of an alias. This requires that the decl have been defined. Aliases
+ that precede their definition have to be queued for later processing. */
-void
-assemble_alias (tree decl, tree target)
+typedef struct alias_pair GTY(())
{
- const char *name;
+ tree decl;
+ tree target;
+} alias_pair;
- /* We must force creation of DECL_RTL for debug info generation, even though
- we don't use it here. */
- make_decl_rtl (decl);
+/* Define gc'd vector type. */
+DEF_VEC_O(alias_pair);
+DEF_VEC_ALLOC_O(alias_pair,gc);
- name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+static GTY(()) VEC(alias_pair,gc) *alias_pairs;
+
+/* Given an assembly name, find the decl it is associated with. At the
+ same time, mark it needed for cgraph. */
+
+static tree
+find_decl_and_mark_needed (tree decl, tree target)
+{
+ struct cgraph_node *fnode = NULL;
+ struct cgraph_varpool_node *vnode = NULL;
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ fnode = cgraph_node_for_asm (target);
+ if (fnode == NULL)
+ vnode = cgraph_varpool_node_for_asm (target);
+ }
+ else
+ {
+ vnode = cgraph_varpool_node_for_asm (target);
+ if (vnode == NULL)
+ fnode = cgraph_node_for_asm (target);
+ }
+
+ if (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
+ return NULL_TREE;
+}
+
+/* Output the assembler code for a define (equate) using ASM_OUTPUT_DEF
+ or ASM_OUTPUT_DEF_FROM_DECLS. The function defines the symbol whose
+ tree node is DECL to have the value of the tree node TARGET. */
+
+static void
+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. */
maybe_assemble_visibility (decl);
}
-#ifdef ASM_OUTPUT_DEF_FROM_DECLS
+# ifdef ASM_OUTPUT_DEF_FROM_DECLS
ASM_OUTPUT_DEF_FROM_DECLS (asm_out_file, decl, target);
-#else
- ASM_OUTPUT_DEF (asm_out_file, name, IDENTIFIER_POINTER (target));
-#endif
-#else /* !ASM_OUTPUT_DEF */
-#if defined (ASM_OUTPUT_WEAK_ALIAS) || defined (ASM_WEAKEN_DECL)
- if (DECL_WEAK (decl))
- {
- tree *p, t;
-#ifdef ASM_WEAKEN_DECL
- ASM_WEAKEN_DECL (asm_out_file, decl, name, IDENTIFIER_POINTER (target));
-#else
- ASM_OUTPUT_WEAK_ALIAS (asm_out_file, name, IDENTIFIER_POINTER (target));
-#endif
- /* Remove this function from the pending weak list so that
- we do not emit multiple .weak directives for it. */
- for (p = &weak_decls; (t = *p) ; )
+# else
+ ASM_OUTPUT_DEF (asm_out_file,
+ IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
+ IDENTIFIER_POINTER (target));
+# endif
+#elif defined (ASM_OUTPUT_WEAK_ALIAS) || defined (ASM_WEAKEN_DECL)
+ {
+ const char *name;
+ tree *p, t;
+
+ name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+# ifdef ASM_WEAKEN_DECL
+ ASM_WEAKEN_DECL (asm_out_file, decl, name, IDENTIFIER_POINTER (target));
+# else
+ ASM_OUTPUT_WEAK_ALIAS (asm_out_file, name, IDENTIFIER_POINTER (target));
+# endif
+ /* Remove this function from the pending weak list so that
+ we do not emit multiple .weak directives for it. */
+ for (p = &weak_decls; (t = *p) ; )
+ if (DECL_ASSEMBLER_NAME (decl) == DECL_ASSEMBLER_NAME (TREE_VALUE (t)))
+ *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)
- == DECL_ASSEMBLER_NAME (TREE_VALUE (t)))
+ == ultimate_transparent_alias_target (&TREE_VALUE (t)))
*p = TREE_CHAIN (t);
else
p = &TREE_CHAIN (t);
- }
- else
- warning ("only weak aliases are supported in this configuration");
-
-#else
- warning ("alias definitions not supported in this configuration; ignored");
-#endif
+ }
+ }
#endif
+}
- /* Tell cgraph that the aliased symbol is needed. We *could* be more
- specific and tell cgraph about the relationship between the two
- symbols, but given that aliases virtually always exist for a reason,
- it doesn't seem worthwhile. */
- if (flag_unit_at_a_time)
+/* First pass of completing pending aliases. Make sure that cgraph knows
+ which symbols will be required. */
+
+void
+finish_aliases_1 (void)
+{
+ unsigned i;
+ alias_pair *p;
+
+ for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); i++)
{
- struct cgraph_node *fnode = NULL;
- struct cgraph_varpool_node *vnode = NULL;
+ tree target_decl;
- if (TREE_CODE (decl) == FUNCTION_DECL)
+ target_decl = find_decl_and_mark_needed (p->decl, p->target);
+ if (target_decl == NULL)
{
- fnode = cgraph_node_for_asm (target);
- if (fnode != NULL)
- cgraph_mark_needed_node (fnode);
- else
- {
- vnode = cgraph_varpool_node_for_asm (target);
- if (vnode != NULL)
- cgraph_varpool_mark_needed_node (vnode);
- }
+ 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));
+ }
+}
+
+/* Second pass of completing pending aliases. Emit the actual assembly.
+ This happens at the end of compilation and thus it is assured that the
+ target symbol has been emitted. */
+
+void
+finish_aliases_2 (void)
+{
+ unsigned i;
+ alias_pair *p;
+
+ for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); i++)
+ do_assemble_alias (p->decl, p->target);
+
+ VEC_truncate (alias_pair, alias_pairs, 0);
+}
+
+/* Emit an assembler directive to make the symbol for DECL an alias to
+ the symbol for TARGET. */
+
+void
+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
{
- vnode = cgraph_varpool_node_for_asm (target);
- if (vnode != NULL)
- cgraph_varpool_mark_needed_node (vnode);
- else
- {
- fnode = cgraph_node_for_asm (target);
- if (fnode != NULL)
- cgraph_mark_needed_node (fnode);
- }
+#ifndef ASM_OUTPUT_WEAKREF
+ IDENTIFIER_TRANSPARENT_ALIAS (alias) = 1;
+ TREE_CHAIN (alias) = target;
+#endif
}
-
- if (fnode == NULL && vnode == NULL)
- warning ("%qD aliased to undefined symbol %qE", decl, target);
+ 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);
+ return;
+ }
+# endif
+#endif
}
+ /* We must force creation of DECL_RTL for debug info generation, even though
+ we don't use it here. */
+ make_decl_rtl (decl);
TREE_USED (decl) = 1;
- TREE_ASM_WRITTEN (decl) = 1;
- TREE_ASM_WRITTEN (DECL_ASSEMBLER_NAME (decl)) = 1;
+
+ /* 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. */
+ if (! is_weakref)
+ DECL_EXTERNAL (decl) = 0;
+
+ /* Allow aliases to aliases. */
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ cgraph_node (decl)->alias = true;
+ else
+ cgraph_varpool_node (decl)->alias = true;
+
+ /* If the target has already been emitted, we don't have to queue the
+ alias. This saves a tad o memory. */
+ target_decl = find_decl_and_mark_needed (decl, target);
+ if (target_decl && TREE_ASM_WRITTEN (target_decl))
+ do_assemble_alias (decl, target);
+ else
+ {
+ alias_pair *p = VEC_safe_push (alias_pair, gc, alias_pairs, NULL);
+ p->decl = decl;
+ p->target = target;
+ }
}
/* Emit an assembler directive to set symbol for DECL visibility to
const char *name, *type;
- name = (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
+ name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
type = visibility_types[vis];
#ifdef HAVE_GAS_HIDDEN
assemble_name (asm_out_file, name);
fprintf (asm_out_file, "\n");
#else
- warning ("visibility attribute not supported in this configuration; ignored");
+ warning (OPT_Wattributes, "visibility attribute not supported "
+ "in this configuration; ignored");
#endif
}
void
make_decl_one_only (tree decl)
{
- if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL)
- abort ();
+ gcc_assert (TREE_CODE (decl) == VAR_DECL
+ || TREE_CODE (decl) == FUNCTION_DECL);
TREE_PUBLIC (decl) = 1;
else if (TREE_CODE (decl) == VAR_DECL
&& (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node))
DECL_COMMON (decl) = 1;
- else if (SUPPORTS_WEAK)
- DECL_WEAK (decl) = 1;
else
- abort ();
+ {
+ gcc_assert (SUPPORTS_WEAK);
+ DECL_WEAK (decl) = 1;
+ }
}
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;
}
-static enum tls_model
-decl_tls_model (tree decl)
+enum tls_model
+decl_default_tls_model (tree decl)
{
enum tls_model kind;
- tree attr = lookup_attribute ("tls_model", DECL_ATTRIBUTES (decl));
bool is_local;
- if (attr)
- {
- attr = TREE_VALUE (TREE_VALUE (attr));
- if (TREE_CODE (attr) != STRING_CST)
- abort ();
- if (!strcmp (TREE_STRING_POINTER (attr), "local-exec"))
- kind = TLS_MODEL_LOCAL_EXEC;
- else if (!strcmp (TREE_STRING_POINTER (attr), "initial-exec"))
- kind = TLS_MODEL_INITIAL_EXEC;
- else if (!strcmp (TREE_STRING_POINTER (attr), "local-dynamic"))
- kind = optimize ? TLS_MODEL_LOCAL_DYNAMIC : TLS_MODEL_GLOBAL_DYNAMIC;
- else if (!strcmp (TREE_STRING_POINTER (attr), "global-dynamic"))
- kind = TLS_MODEL_GLOBAL_DYNAMIC;
- else
- abort ();
- return kind;
- }
-
is_local = targetm.binds_local_p (decl);
- if (!flag_pic)
+ if (!flag_shlib)
{
if (is_local)
kind = TLS_MODEL_LOCAL_EXEC;
else
kind = TLS_MODEL_INITIAL_EXEC;
}
+
/* Local dynamic is inefficient when we're not combining the
parts of the address. */
else if (optimize && is_local)
flags = SECTION_CODE;
else if (decl && decl_readonly_section_1 (decl, reloc, shlib))
flags = 0;
- else if (unlikely_text_section_name
- && strcmp (name, unlikely_text_section_name) == 0)
+ else if (current_function_decl
+ && cfun
+ && cfun->unlikely_text_section_name
+ && strcmp (name, cfun->unlikely_text_section_name) == 0)
+ flags = SECTION_CODE;
+ else if (!decl
+ && (!current_function_decl || !cfun)
+ && strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0)
flags = SECTION_CODE;
else
flags = SECTION_WRITE;
if (decl && DECL_ONE_ONLY (decl))
flags |= SECTION_LINKONCE;
- if (decl && TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
+ if (decl && TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
flags |= SECTION_TLS | SECTION_WRITE;
if (strcmp (name, ".bss") == 0
|| strncmp (name, ".gnu.linkonce.b.", 16) == 0
|| strcmp (name, ".sbss") == 0
|| strncmp (name, ".sbss.", 6) == 0
- || strncmp (name, ".gnu.linkonce.sb.", 17) == 0
- || strcmp (name, ".tbss") == 0
- || strncmp (name, ".gnu.linkonce.tb.", 17) == 0)
+ || strncmp (name, ".gnu.linkonce.sb.", 17) == 0)
flags |= SECTION_BSS;
if (strcmp (name, ".tdata") == 0
- || strcmp (name, ".tbss") == 0
- || strncmp (name, ".gnu.linkonce.td.", 17) == 0
- || strncmp (name, ".gnu.linkonce.tb.", 17) == 0)
+ || strncmp (name, ".tdata.", 7) == 0
+ || strncmp (name, ".gnu.linkonce.td.", 17) == 0)
flags |= SECTION_TLS;
+ if (strcmp (name, ".tbss") == 0
+ || strncmp (name, ".tbss.", 6) == 0
+ || strncmp (name, ".gnu.linkonce.tb.", 17) == 0)
+ flags |= SECTION_TLS | SECTION_BSS;
+
/* These three sections have special ELF types. They are neither
SHT_PROGBITS nor SHT_NOBITS, so when changing sections we don't
want to print a section type (@progbits or @nobits). If someone
{
/* Some object formats don't support named sections at all. The
front-end should already have flagged this as an error. */
- abort ();
+ gcc_unreachable ();
}
void
abbreviated form to switch back to it -- unless this section is
part of a COMDAT groups, in which case GAS requires the full
declaration every time. */
- if (!(HAVE_GAS_COMDAT_GROUP && (flags & SECTION_LINKONCE))
- && ! named_section_first_declaration (name))
+ if (!(HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
+ && (flags & SECTION_DECLARED))
{
fprintf (asm_out_file, "\t.section\t%s\n", name);
return;
*f++ = 'S';
if (flags & SECTION_TLS)
*f++ = 'T';
- if (HAVE_GAS_COMDAT_GROUP && (flags & SECTION_LINKONCE))
+ if (HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
*f++ = 'G';
*f = '\0';
if (flags & SECTION_ENTSIZE)
fprintf (asm_out_file, ",%d", flags & SECTION_ENTSIZE);
- if (HAVE_GAS_COMDAT_GROUP && (flags & SECTION_LINKONCE))
- fprintf (asm_out_file, ",%s,comdat",
+ if (HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
+ 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;
ret = SECCAT_RODATA;
/* There are no read-only thread-local sections. */
- if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
+ if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
{
/* Note that this would be *just* SECCAT_BSS, except that there's
no concept of a read-only thread-local-data section. */
/* 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)
{
{
case SECCAT_TEXT:
/* We're not supposed to be called on FUNCTION_DECLs. */
- abort ();
+ 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;
sname = ".tbss";
break;
default:
- abort ();
+ gcc_unreachable ();
}
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
void
default_unique_section_1 (tree decl, int reloc, int shlib)
{
- bool one_only = DECL_ONE_ONLY (decl);
+ /* We only need to use .gnu.linkonce if we don't have COMDAT groups. */
+ bool one_only = DECL_ONE_ONLY (decl) && !HAVE_COMDAT_GROUP;
const char *prefix, *name;
size_t nlen, plen;
char *string;
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.";
prefix = one_only ? ".gnu.linkonce.tb." : ".tbss.";
break;
default:
- abort ();
+ gcc_unreachable ();
}
plen = strlen (prefix);
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. */
flags |= SYMBOL_FLAG_FUNCTION;
if (targetm.binds_local_p (decl))
flags |= SYMBOL_FLAG_LOCAL;
- if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
- flags |= decl_tls_model (decl) << SYMBOL_FLAG_TLS_SHIFT;
+ if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
+ flags |= DECL_TLS_MODEL (decl) << SYMBOL_FLAG_TLS_SHIFT;
else if (targetm.in_small_data_p (decl))
flags |= SYMBOL_FLAG_SMALL;
/* ??? Why is DECL_EXTERNAL ever set for non-PUBLIC names? Without
/* 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)
}
/* Default function to output code that will globalize a label. A
- target must define GLOBAL_ASM_OP or provide it's own function to
+ target must define GLOBAL_ASM_OP or provide its own function to
globalize a label. */
#ifdef GLOBAL_ASM_OP
void
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"