/* 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.
declarations for e.g. AIX 4.x. */
#endif
-#ifndef ASM_STABS_OP
-#define ASM_STABS_OP "\t.stabs\t"
-#endif
-
/* The (assembler) name of the first globally-visible object output. */
const char *first_global_object_name;
const char *weak_global_object_name;
partitions hot and cold basic blocks into separate sections of the .o
file. */
-bool unlikely_section_label_printed = false;
+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. */
-/* RTX_UNCHANGING_P in a MEM can mean it is stored into, for initialization.
- So giving constant the alias set for the type will allow such
- initializations to appear to conflict with the load of the constant. We
- avoid this by giving all constants an alias set for just constants.
- Since there will be no stores to that alias set, nothing will ever
- conflict with them. */
+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. */
+
+static char *unlikely_text_section_name = NULL;
+
+/* We give all constants their own alias set. Perhaps redundant with
+ MEM_READONLY_P, but pre-dates it. */
static HOST_WIDE_INT const_alias_set;
{
in_section = in_text;
fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
- ASM_OUTPUT_ALIGN (asm_out_file, 2);
}
}
void
unlikely_text_section (void)
{
- if ((in_section != in_unlikely_executed_text)
- && (in_section != in_named
- || strcmp (in_named_name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) != 0))
+ const char *name;
+ int len;
+
+ if (! unlikely_text_section_name)
{
- if (targetm.have_named_sections)
- named_section (NULL_TREE, UNLIKELY_EXECUTED_TEXT_SECTION_NAME, 0);
+ 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
{
- in_section = in_unlikely_executed_text;
- fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
+ 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);
}
-
+ }
+
+ 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;
+
if (!unlikely_section_label_printed)
{
- fprintf (asm_out_file, "__%s_unlikely_section:\n",
- current_function_name ());
+ ASM_OUTPUT_LABEL (asm_out_file, unlikely_section_label);
unlikely_section_label_printed = true;
-
- /* Make sure that we have appropriate alignment for instructions
- in this section. */
- assemble_align (FUNCTION_BOUNDARY);
}
}
}
int
in_unlikely_text_section (void)
{
- return in_section == in_unlikely_executed_text;
+ 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. */
set of flags for a section to have, so 0 does not mean that the section
has not been seen. */
-unsigned int
+static unsigned int
get_named_section_flags (const char *section)
{
struct in_named_entry **slot;
return true;
}
-/* Tell assembler to change to section NAME with attributes FLAGS. */
+/* Tell assembler to change to section NAME with attributes FLAGS. If
+ DECL is non-NULL, it is the VAR_DECL or FUNCTION_DECL with which
+ this section is associated. */
void
-named_section_flags (const char *name, unsigned int flags)
+named_section_real (const char *name, unsigned int flags, tree decl)
{
if (in_section != in_named || strcmp (name, in_named_name) != 0)
{
if (! set_named_section_flags (name, flags))
abort ();
- targetm.asm_out.named_section (name, flags);
+ targetm.asm_out.named_section (name, flags, decl);
if (flags & SECTION_FORGET)
in_section = no_section;
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 =
+ xstrdup (UNLIKELY_EXECUTED_TEXT_SECTION_NAME);
+
flags = targetm.section_type_flags (decl, name, reloc);
/* Sanity check user variables for flag changes. Non-user
error ("%J%D causes a section type conflict", decl, decl);
}
- named_section_flags (name, flags);
+ named_section_real (name, flags, decl);
}
/* If required, set DECL_SECTION_NAME to a unique name. */
/* Switch to the section for function DECL.
- If DECL is NULL_TREE, switch to the text section.
- ??? It's not clear that we will ever be passed NULL_TREE, but it's
- safer to handle it. */
+ If DECL is NULL_TREE, switch to the text section. We can be passed
+ NULL_TREE under some circumstances by dbxout.c at least. */
void
function_section (tree decl)
{
- if (scan_ahead_for_unlikely_executed_note (get_insns()))
- unlikely_text_section ();
+ if (decl == NULL_TREE)
+ text_section ();
else
{
- if (decl != NULL_TREE
- && DECL_SECTION_NAME (decl) != NULL_TREE)
- named_section (decl, (char *) 0, 0);
+ /* ??? 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);
+
+#ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
+ targetm.asm_out.select_section (decl, unlikely, DECL_ALIGN (decl));
+#else
+ if (unlikely)
+ unlikely_text_section ();
+ else if (DECL_SECTION_NAME (decl))
+ named_section (decl, 0, 0);
else
- text_section ();
+ text_section ();
+#endif
}
}
+/* Switch to read-only data section associated with function DECL. */
+
+void
+default_function_rodata_section (tree decl)
+{
+ if (decl != NULL_TREE && DECL_SECTION_NAME (decl))
+ {
+ const char *name = TREE_STRING_POINTER (DECL_SECTION_NAME (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)
+ {
+ 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;
+ }
+ /* For .text.foo we want to use .rodata.foo. */
+ else if (flag_function_sections && flag_data_sections
+ && strncmp (name, ".text.", 6) == 0)
+ {
+ size_t len = strlen (name) + 1;
+ char *rname = alloca (len + 2);
+
+ memcpy (rname, ".rodata", 7);
+ memcpy (rname + 7, name + 5, len - 5);
+ named_section_flags (rname, 0);
+ return;
+ }
+ }
+
+ readonly_data_section ();
+}
+
+/* Switch to read-only data section associated with function DECL
+ for targets where that section should be always the single
+ readonly data section. */
+
+void
+default_no_function_rodata_section (tree decl ATTRIBUTE_UNUSED)
+{
+ readonly_data_section ();
+}
+
/* Switch to section for variable DECL. RELOC is the same as the
argument to SELECT_SECTION. */
return name;
}
\f
+/* The user has asked for a DECL to have a particular name. Set (or
+ change) it in such a way that we don't prefix an underscore to
+ it. */
+void
+set_user_assembler_name (tree decl, const char *name)
+{
+ char *starred = alloca (strlen (name) + 2);
+ starred[0] = '*';
+ strcpy (starred + 1, name);
+ change_decl_assembler_name (decl, get_identifier (starred));
+ SET_DECL_RTL (decl, NULL_RTX);
+}
+\f
/* Decode an `asm' spec for a declaration as a register name.
Return the register number, or -1 if nothing specified,
or -2 if the ASMSPEC is not `cc' or `memory' and is not recognized,
There is, however, one exception: this function handles variables
explicitly placed in a particular register by the user.
- ASMSPEC, if not 0, is the string which the user specified as the
- assembler symbol name.
-
This is never called for PARM_DECL nodes. */
void
-make_decl_rtl (tree decl, const char *asmspec)
+make_decl_rtl (tree decl)
{
const char *name = 0;
int reg_number;
SET_DECL_RTL (decl, adjust_address_nv (DECL_RTL (decl),
DECL_MODE (decl), 0));
+ if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
+ return;
+
/* ??? Another way to do this would be to maintain a hashed
table of such critters. Instead of adding stuff to a DECL
to give certain attributes to it, we could use an external
return;
}
- reg_number = decode_reg_name (asmspec);
- if (reg_number == -2)
- {
- /* ASMSPEC is given, and not the name of a register. Mark the
- name with a star so assemble_name won't munge it. */
- char *starred = alloca (strlen (asmspec) + 2);
- starred[0] = '*';
- strcpy (starred + 1, asmspec);
- change_decl_assembler_name (decl, get_identifier (starred));
- }
-
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+
if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
{
+ reg_number = decode_reg_name (name);
/* First detect errors in declaring global registers. */
if (reg_number == -1)
- error ("%Jregister name not specified for '%D'", decl, decl);
+ error ("%Jregister name not specified for %qD", decl, decl);
else if (reg_number < 0)
- error ("%Jinvalid register name for '%D'", decl, decl);
+ error ("%Jinvalid register name for %qD", decl, decl);
else if (TYPE_MODE (TREE_TYPE (decl)) == BLKmode)
- error ("%Jdata type of '%D' isn't suitable for a register",
+ error ("%Jdata type of %qD isn%'t suitable for a register",
decl, decl);
else if (! HARD_REGNO_MODE_OK (reg_number, TYPE_MODE (TREE_TYPE (decl))))
- error ("%Jregister specified for '%D' isn't suitable for data type",
+ error ("%Jregister specified for %qD isn%'t suitable for data type",
decl, 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 ("volatile register variables don%'t "
+ "work as you might wish");
/* If the user specified one of the eliminables registers here,
e.g., FRAME_POINTER_REGNUM, we don't want to get this variable
return;
}
}
-
/* Now handle ordinary static variables and functions (in memory).
Also handle vars declared register invalidly. */
-
- if (reg_number >= 0 || reg_number == -3)
- error ("%Jregister name given for non-register variable '%D'", decl, decl);
+ else if (name[0] == '*')
+ {
+#ifdef REGISTER_PREFIX
+ if (strlen (REGISTER_PREFIX) != 0)
+ {
+ reg_number = decode_reg_name (name);
+ if (reg_number >= 0 || reg_number == -3)
+ error ("%Jregister name given for non-register variable %qD", decl, decl);
+ }
+#endif
+ }
/* Specifying a section attribute on a variable forces it into a
non-.bss section, and thus it cannot be common. */
between 0 and MAX_INIT_PRIORITY. */
void
-default_stabs_asm_out_destructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
+default_stabs_asm_out_destructor (rtx symbol ATTRIBUTE_UNUSED,
+ int priority ATTRIBUTE_UNUSED)
{
+#if defined DBX_DEBUGGING_INFO || defined XCOFF_DEBUGGING_INFO
/* Tell GNU LD that this is part of the static destructor set.
This will work for any system that uses stabs, most usefully
aout systems. */
- fprintf (asm_out_file, "%s\"___DTOR_LIST__\",22,0,0,", ASM_STABS_OP);
- assemble_name (asm_out_file, XSTR (symbol, 0));
- fputc ('\n', asm_out_file);
+ dbxout_begin_simple_stabs ("___DTOR_LIST__", 22 /* N_SETT */);
+ dbxout_stab_value_label (XSTR (symbol, 0));
+#else
+ sorry ("global destructors not supported on this target");
+#endif
}
void
/* Likewise for global constructors. */
void
-default_stabs_asm_out_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
+default_stabs_asm_out_constructor (rtx symbol ATTRIBUTE_UNUSED,
+ int priority ATTRIBUTE_UNUSED)
{
+#if defined DBX_DEBUGGING_INFO || defined XCOFF_DEBUGGING_INFO
/* Tell GNU LD that this is part of the static destructor set.
This will work for any system that uses stabs, most usefully
aout systems. */
- fprintf (asm_out_file, "%s\"___CTOR_LIST__\",22,0,0,", ASM_STABS_OP);
- assemble_name (asm_out_file, XSTR (symbol, 0));
- fputc ('\n', asm_out_file);
+ dbxout_begin_simple_stabs ("___CTOR_LIST__", 22 /* N_SETT */);
+ dbxout_stab_value_label (XSTR (symbol, 0));
+#else
+ sorry ("global constructors not supported on this target");
+#endif
}
void
{
int align;
- unlikely_section_label_printed = false;
+ if (unlikely_text_section_name)
+ free (unlikely_text_section_name);
+ 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. */
+
+ if (flag_reorder_blocks_and_partition)
+ {
+ unlikely_text_section ();
+ assemble_align (FUNCTION_BOUNDARY);
+ }
+
resolve_unique_section (decl, 0, flag_function_sections);
function_section (decl);
maybe_assemble_visibility (decl);
}
+ if (DECL_PRESERVE_P (decl))
+ targetm.asm_out.mark_decl_preserved (fnname);
+
/* Do any machine/system dependent processing of the function name. */
#ifdef ASM_DECLARE_FUNCTION_NAME
ASM_DECLARE_FUNCTION_NAME (asm_out_file, fnname, current_function_decl);
/* 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
destination = asm_dest_common;
}
+ if (destination != asm_dest_common)
+ {
+ resolve_unique_section (decl, 0, flag_data_sections);
+ /* Custom sections don't belong here. */
+ if (DECL_SECTION_NAME (decl))
+ return false;
+ }
+
if (destination == asm_dest_bss)
globalize_decl (decl);
- resolve_unique_section (decl, 0, flag_data_sections);
if (flag_shared_data)
{
if (!dont_output_data && DECL_SIZE (decl) == 0)
{
- error ("%Jstorage size of `%D' isn't known", decl, decl);
+ error ("%Jstorage size of %qD isn%'t known", decl, decl);
TREE_ASM_WRITTEN (decl) = 1;
return;
}
if (! dont_output_data
&& ! host_integerp (DECL_SIZE_UNIT (decl), 1))
{
- error ("%Jsize of variable '%D' is too large", decl, decl);
+ error ("%Jsize of variable %qD is too large", decl, decl);
return;
}
/* Some object file formats have a maximum alignment which they support.
In particular, a.out format supports a maximum alignment of 4. */
-#ifndef MAX_OFILE_ALIGNMENT
-#define MAX_OFILE_ALIGNMENT BIGGEST_ALIGNMENT
-#endif
if (align > MAX_OFILE_ALIGNMENT)
{
- warning ("%Jalignment of '%D' is greater than maximum object "
+ warning ("%Jalignment of %qD is greater than maximum object "
"file alignment. Using %d", decl, decl,
MAX_OFILE_ALIGNMENT/BITS_PER_UNIT);
align = MAX_OFILE_ALIGNMENT;
if (TREE_PUBLIC (decl))
maybe_assemble_visibility (decl);
- /* Output any data that we will need to use the address of. */
- if (DECL_INITIAL (decl) == error_mark_node)
- reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0;
- else if (DECL_INITIAL (decl))
- {
- reloc = compute_reloc_for_constant (DECL_INITIAL (decl));
- output_addressed_constants (DECL_INITIAL (decl));
- }
- resolve_unique_section (decl, reloc, flag_data_sections);
+ if (DECL_PRESERVE_P (decl))
+ targetm.asm_out.mark_decl_preserved (name);
/* Handle uninitialized definitions. */
* (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
#if !defined(ASM_OUTPUT_ALIGNED_COMMON) && !defined(ASM_OUTPUT_ALIGNED_DECL_COMMON) && !defined(ASM_OUTPUT_ALIGNED_BSS)
- if ((unsigned HOST_WIDE_INT) DECL_ALIGN (decl) / BITS_PER_UNIT > rounded)
- warning ("%Jrequested alignment for '%D' is greater than "
+ 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);
#endif
if (TREE_PUBLIC (decl) && DECL_NAME (decl))
globalize_decl (decl);
+ /* Output any data that we will need to use the address of. */
+ if (DECL_INITIAL (decl) == error_mark_node)
+ reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0;
+ else if (DECL_INITIAL (decl))
+ {
+ reloc = compute_reloc_for_constant (DECL_INITIAL (decl));
+ output_addressed_constants (DECL_INITIAL (decl));
+ }
+
/* Switch to the appropriate section. */
+ resolve_unique_section (decl, reloc, flag_data_sections);
variable_section (decl, reloc);
/* dbxout.c needs to know this. */
/* Output the alignment of this data. */
if (align > BITS_PER_UNIT)
- {
- ASM_OUTPUT_ALIGN (asm_out_file,
- floor_log2 (DECL_ALIGN (decl) / BITS_PER_UNIT));
- }
+ ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl)));
/* Do any machine/system dependent processing of the object. */
#ifdef ASM_DECLARE_OBJECT_NAME
}
}
+/* In unit-at-a-time mode, we delay assemble_external processing until
+ the compilation unit is finalized. This is the best we can do for
+ right now (i.e. stage 3 of GCC 4.0) - the right thing is to delay
+ it all the way to final. See PR 17982 for further discussion. */
+static GTY(()) tree pending_assemble_externals;
+
#ifdef ASM_OUTPUT_EXTERNAL
/* True if DECL is a function decl for which no out-of-line copy exists.
It is assumed that DECL's assembler name has been set. */
}
return false;
}
+
+/* Actually do the tests to determine if this is necessary, and invoke
+ ASM_OUTPUT_EXTERNAL. */
+static void
+assemble_external_real (tree decl)
+{
+ rtx rtl = DECL_RTL (decl);
+
+ if (MEM_P (rtl) && GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF
+ && !SYMBOL_REF_USED (XEXP (rtl, 0))
+ && !incorporeal_function_p (decl))
+ {
+ /* Some systems do require some output. */
+ SYMBOL_REF_USED (XEXP (rtl, 0)) = 1;
+ ASM_OUTPUT_EXTERNAL (asm_out_file, decl, XSTR (XEXP (rtl, 0), 0));
+ }
+}
+#endif
+
+void
+process_pending_assemble_externals (void)
+{
+#ifdef ASM_OUTPUT_EXTERNAL
+ tree list;
+ for (list = pending_assemble_externals; list; list = TREE_CHAIN (list))
+ assemble_external_real (TREE_VALUE (list));
+
+ pending_assemble_externals = 0;
#endif
+}
/* Output something to declare an external symbol to the assembler.
(Most assemblers don't need this, so we normally output nothing.)
main body of this code is only rarely exercised. To provide some
testing, on all platforms, we make sure that the ASM_OUT_FILE is
open. If it's not, we should not be calling this function. */
- if (!asm_out_file)
- abort ();
+ gcc_assert (asm_out_file);
#ifdef ASM_OUTPUT_EXTERNAL
- if (DECL_P (decl) && DECL_EXTERNAL (decl) && TREE_PUBLIC (decl))
- {
- rtx rtl = DECL_RTL (decl);
+ if (!DECL_P (decl) || !DECL_EXTERNAL (decl) || !TREE_PUBLIC (decl))
+ return;
- if (MEM_P (rtl) && GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF
- && !SYMBOL_REF_USED (XEXP (rtl, 0))
- && !incorporeal_function_p (decl))
- {
- /* Some systems do require some output. */
- SYMBOL_REF_USED (XEXP (rtl, 0)) = 1;
- ASM_OUTPUT_EXTERNAL (asm_out_file, decl, XSTR (XEXP (rtl, 0), 0));
- }
- }
+ if (flag_unit_at_a_time)
+ pending_assemble_externals = tree_cons (0, decl,
+ pending_assemble_externals);
+ else
+ assemble_external_real (decl);
#endif
}
which do not need to be marked. */
}
-/* Output to FILE a reference to the assembler name of a C-level name NAME.
- If NAME starts with a *, the rest of NAME is output verbatim.
- Otherwise NAME is transformed in an implementation-defined way
- (usually by the addition of an underscore).
- Many macros in the tm file are defined to call this function. */
+/* 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
+ addition of an underscore). */
+
+void
+assemble_name_raw (FILE *file, const char *name)
+{
+ if (name[0] == '*')
+ fputs (&name[1], file);
+ else
+ ASM_OUTPUT_LABELREF (file, name);
+}
+
+/* Like assemble_name_raw, but should be used when NAME might refer to
+ an entity that is also represented as a tree (like a function or
+ variable). If NAME does refer to such an entity, that entity will
+ be marked as referenced. */
void
assemble_name (FILE *file, const char *name)
if (id)
mark_referenced (id);
- if (name[0] == '*')
- fputs (&name[1], file);
- else
- ASM_OUTPUT_LABELREF (file, name);
+ assemble_name_raw (file, name);
}
/* Allocate SIZE bytes writable static space with a gensym name
int aligned_p ATTRIBUTE_UNUSED)
{
const char *op = integer_asm_op (size, aligned_p);
+ /* Avoid GAS bugs for large values. Specifically negative values whose
+ absolute value fits in a bfd_vma, but not in a bfd_signed_vma. */
+ if (size > UNITS_PER_WORD && size > POINTER_SIZE / BITS_PER_UNIT)
+ return false;
return op && (assemble_integer_with_op (op, x), true);
}
+ const_hash_1 (TREE_IMAGPART (exp)));
case CONSTRUCTOR:
- if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
- {
- char *tmp;
-
- len = int_size_in_bytes (TREE_TYPE (exp));
- tmp = alloca (len);
- get_set_constructor_bytes (exp, (unsigned char *) tmp, len);
- p = tmp;
- break;
- }
- else
- {
- tree link;
-
- 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));
-
- return hi;
- }
+ {
+ tree link;
+
+ 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));
+
+ return hi;
+ }
case ADDR_EXPR:
case FDESC_EXPR:
&& compare_constant (TREE_IMAGPART (t1), TREE_IMAGPART (t2)));
case CONSTRUCTOR:
- typecode = TREE_CODE (TREE_TYPE (t1));
- if (typecode != TREE_CODE (TREE_TYPE (t2)))
- return 0;
-
- if (typecode == SET_TYPE)
- {
- int len = int_size_in_bytes (TREE_TYPE (t2));
- unsigned char *tmp1, *tmp2;
-
- if (int_size_in_bytes (TREE_TYPE (t1)) != len)
- return 0;
-
- tmp1 = alloca (len);
- tmp2 = alloca (len);
-
- if (get_set_constructor_bytes (t1, tmp1, len) != NULL_TREE)
- return 0;
- if (get_set_constructor_bytes (t2, tmp2, len) != NULL_TREE)
- return 0;
-
- return memcmp (tmp1, tmp2, len) == 0;
- }
- else
- {
- tree l1, l2;
-
- if (typecode == ARRAY_TYPE)
- {
- HOST_WIDE_INT size_1 = int_size_in_bytes (TREE_TYPE (t1));
- /* For arrays, check that the sizes all match. */
- if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2))
- || size_1 == -1
- || size_1 != int_size_in_bytes (TREE_TYPE (t2)))
- return 0;
- }
- else
- {
- /* For record and union constructors, require exact type
- equality. */
- if (TREE_TYPE (t1) != TREE_TYPE (t2))
- return 0;
- }
+ {
+ tree l1, l2;
+
+ typecode = TREE_CODE (TREE_TYPE (t1));
+ if (typecode != TREE_CODE (TREE_TYPE (t2)))
+ return 0;
- for (l1 = CONSTRUCTOR_ELTS (t1), l2 = CONSTRUCTOR_ELTS (t2);
- l1 && l2;
- l1 = TREE_CHAIN (l1), l2 = TREE_CHAIN (l2))
- {
- /* Check that each value is the same... */
- if (! compare_constant (TREE_VALUE (l1), TREE_VALUE (l2)))
- return 0;
- /* ... and that they apply to the same fields! */
- if (typecode == ARRAY_TYPE)
- {
- if (! compare_constant (TREE_PURPOSE (l1),
- TREE_PURPOSE (l2)))
- return 0;
- }
- else
- {
- if (TREE_PURPOSE (l1) != TREE_PURPOSE (l2))
- return 0;
- }
- }
+ if (typecode == ARRAY_TYPE)
+ {
+ HOST_WIDE_INT size_1 = int_size_in_bytes (TREE_TYPE (t1));
+ /* For arrays, check that the sizes all match. */
+ if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2))
+ || size_1 == -1
+ || size_1 != int_size_in_bytes (TREE_TYPE (t2)))
+ return 0;
+ }
+ else
+ {
+ /* For record and union constructors, require exact type
+ equality. */
+ if (TREE_TYPE (t1) != TREE_TYPE (t2))
+ return 0;
+ }
- return l1 == NULL_TREE && l2 == NULL_TREE;
- }
+ for (l1 = CONSTRUCTOR_ELTS (t1), l2 = CONSTRUCTOR_ELTS (t2);
+ l1 && l2;
+ l1 = TREE_CHAIN (l1), l2 = TREE_CHAIN (l2))
+ {
+ /* Check that each value is the same... */
+ if (! compare_constant (TREE_VALUE (l1), TREE_VALUE (l2)))
+ return 0;
+ /* ... and that they apply to the same fields! */
+ if (typecode == ARRAY_TYPE)
+ {
+ if (! compare_constant (TREE_PURPOSE (l1),
+ TREE_PURPOSE (l2)))
+ return 0;
+ }
+ else
+ {
+ if (TREE_PURPOSE (l1) != TREE_PURPOSE (l2))
+ return 0;
+ }
+ }
+
+ return l1 == NULL_TREE && l2 == NULL_TREE;
+ }
case ADDR_EXPR:
case FDESC_EXPR:
case ADDR_EXPR:
/* For ADDR_EXPR, we do not want to copy the decl whose address
is requested. We do want to copy constants though. */
- if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == 'c')
+ if (CONSTANT_CLASS_P (TREE_OPERAND (exp, 0)))
return build1 (TREE_CODE (exp), TREE_TYPE (exp),
copy_constant (TREE_OPERAND (exp, 0)));
else
CONSTRUCTOR_ELTS (copy) = list;
for (tail = list; tail; tail = TREE_CHAIN (tail))
TREE_VALUE (tail) = copy_constant (TREE_VALUE (tail));
- if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
- for (tail = list; tail; tail = TREE_CHAIN (tail))
- TREE_PURPOSE (tail) = copy_constant (TREE_PURPOSE (tail));
return copy;
}
int reloc = compute_reloc_for_constant (exp);
/* Align the location counter as required by EXP's data type. */
- int align = TYPE_ALIGN (TREE_TYPE (exp));
+ unsigned int align = TYPE_ALIGN (TREE_TYPE (exp));
#ifdef CONSTANT_ALIGNMENT
align = CONSTANT_ALIGNMENT (exp, align);
#endif
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;
*slot = desc;
/* Construct the MEM. */
- desc->mem = def = gen_rtx_MEM (mode, symbol);
+ desc->mem = def = gen_const_mem (mode, symbol);
set_mem_attributes (def, lang_hooks.types.type_for_mode (mode, 0), 1);
- RTX_UNCHANGING_P (def) = 1;
+ set_mem_align (def, align);
/* If we're dropping a label to the constant pool, make sure we
don't delete it. */
return find_pool_constant (cfun->varasm->pool, addr)->mode;
}
-enum machine_mode
-get_pool_mode_for_function (struct function *f, rtx addr)
-{
- return find_pool_constant (f->varasm->pool, addr)->mode;
-}
-
-/* Similar, return the offset in the constant pool. */
-
-int
-get_pool_offset (rtx addr)
-{
- return find_pool_constant (cfun->varasm->pool, addr)->offset;
-}
-
/* Return the size of the constant pool. */
int
tem = TREE_OPERAND (tem, 0))
;
- if (TREE_CODE_CLASS (TREE_CODE (tem)) == 'c'
- || TREE_CODE (tem) == CONSTRUCTOR)
+ /* If we have an initialized CONST_DECL, retrieve the initializer. */
+ if (TREE_CODE (tem) == CONST_DECL && DECL_INITIAL (tem))
+ tem = DECL_INITIAL (tem);
+
+ if (CONSTANT_CLASS_P (tem) || TREE_CODE (tem) == CONSTRUCTOR)
output_constant_def (tem, 0);
break;
case ADDR_EXPR:
case FDESC_EXPR:
- return staticp (TREE_OPERAND (value, 0)) ? TREE_OPERAND (value, 0) : 0;
+ value = staticp (TREE_OPERAND (value, 0));
+ /* "&(*a).f" is like unto pointer arithmetic. If "a" turns out to
+ be a constant, this is old-skool offsetof-like nonsense. */
+ if (value
+ && TREE_CODE (value) == INDIRECT_REF
+ && TREE_CONSTANT (TREE_OPERAND (value, 0)))
+ return null_pointer_node;
+ /* Taking the address of a nested function involves a trampoline. */
+ if (value
+ && TREE_CODE (value) == FUNCTION_DECL
+ && ((decl_function_context (value) && !DECL_NO_STATIC_CHAIN (value))
+ || DECL_NON_ADDR_CONST_P (value)))
+ return NULL_TREE;
+ return value;
case VIEW_CONVERT_EXPR:
case NON_LVALUE_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);
+
+ /* 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 (TREE_TYPE (value)) == RECORD_TYPE
- || TREE_CODE (TREE_TYPE (value)) == UNION_TYPE)
- return initializer_constant_valid_p (TREE_OPERAND (value, 0),
- 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:
/* Since GCC guarantees that string constants are unique in the
generated code, a subtraction between two copies of the same
constant string is absolute. */
- if (valid0 && TREE_CODE (valid0) == STRING_CST &&
- valid1 && TREE_CODE (valid1) == STRING_CST &&
- TREE_STRING_POINTER (valid0) == TREE_STRING_POINTER (valid1))
+ if (valid0 && TREE_CODE (valid0) == STRING_CST
+ && valid1 && TREE_CODE (valid1) == STRING_CST
+ && operand_equal_p (valid0, valid1, 1))
return null_pointer_node;
}
- /* Support differences between labels. */
+ /* Support narrowing differences. */
if (INTEGRAL_TYPE_P (endtype))
{
tree op0, op1;
+
op0 = TREE_OPERAND (value, 0);
op1 = TREE_OPERAND (value, 1);
op1 = inner;
}
- if (TREE_CODE (op0) == ADDR_EXPR
- && TREE_CODE (TREE_OPERAND (op0, 0)) == LABEL_DECL
- && TREE_CODE (op1) == ADDR_EXPR
- && TREE_CODE (TREE_OPERAND (op1, 0)) == LABEL_DECL)
- return null_pointer_node;
+ op0 = initializer_constant_valid_p (op0, endtype);
+ op1 = initializer_constant_valid_p (op1, endtype);
+
+ /* Both initializers must be known. */
+ if (op0 && op1)
+ {
+ if (op0 == op1)
+ return null_pointer_node;
+
+ /* Support differences between labels. */
+ if (TREE_CODE (op0) == LABEL_DECL
+ && TREE_CODE (op1) == LABEL_DECL)
+ return null_pointer_node;
+
+ if (TREE_CODE (op0) == STRING_CST
+ && TREE_CODE (op1) == STRING_CST
+ && operand_equal_p (op0, op1, 1))
+ return null_pointer_node;
+ }
}
break;
abort ();
return;
- case SET_TYPE:
- if (TREE_CODE (exp) == INTEGER_CST)
- assemble_integer (expand_expr (exp, NULL_RTX,
- VOIDmode, EXPAND_INITIALIZER),
- thissize, align, 1);
- else if (TREE_CODE (exp) == CONSTRUCTOR)
- {
- unsigned char *buffer = alloca (thissize);
- if (get_set_constructor_bytes (exp, buffer, thissize))
- abort ();
- assemble_string ((char *) buffer, thissize);
- }
- else
- error ("unknown set constructor type");
- return;
-
case ERROR_MARK:
return;
total_bytes += fieldsize;
}
else if (val != 0 && TREE_CODE (val) != INTEGER_CST)
- error ("invalid initial value for member `%s'",
+ error ("invalid initial value for member %qs",
IDENTIFIER_POINTER (DECL_NAME (field)));
else
{
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 '%D' must precede definition",
+ error ("%Jweak declaration of %qD must precede definition",
newdecl, newdecl);
/* If we've already generated rtl referencing OLDDECL, we may
a weak symbol. */
else if (TREE_USED (olddecl)
&& TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (olddecl)))
- warning ("%Jweak declaration of '%D' after first use results "
+ warning ("%Jweak declaration of %qD after first use results "
"in unspecified behavior", newdecl, newdecl);
if (SUPPORTS_WEAK)
declare_weak (tree decl)
{
if (! TREE_PUBLIC (decl))
- error ("%Jweak declaration of '%D' must be public", decl, decl);
+ error ("%Jweak declaration of %qD must be public", decl, decl);
else if (TREE_CODE (decl) == FUNCTION_DECL && TREE_ASM_WRITTEN (decl))
- error ("%Jweak declaration of '%D' must precede definition", decl, decl);
+ error ("%Jweak declaration of %qD must precede definition", decl, decl);
else if (SUPPORTS_WEAK)
{
if (! DECL_WEAK (decl))
weak_decls = tree_cons (NULL, decl, weak_decls);
}
else
- warning ("%Jweak declaration of '%D' not supported", decl, decl);
+ warning ("%Jweak declaration of %qD not supported", decl, decl);
mark_weak (decl);
}
targetm.asm_out.globalize_label (asm_out_file, name);
}
+/* Some targets do not allow a forward or undefined reference in a
+ ASM_OUTPUT_DEF. Thus, a mechanism is needed to defer the output of
+ this assembler code. The following struct holds the declaration
+ and target for a deferred output define. */
+struct output_def_pair GTY(())
+{
+ tree decl;
+ tree target;
+};
+typedef struct output_def_pair *output_def_pair;
+
+/* Define gc'd vector type. */
+DEF_VEC_GC_P(output_def_pair);
+
+/* Vector of output_def_pair pointers. */
+static GTY(()) VEC(output_def_pair) *output_defs;
+
+#ifdef ASM_OUTPUT_DEF
+/* 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
+assemble_output_def (tree decl ATTRIBUTE_UNUSED, tree target ATTRIBUTE_UNUSED)
+{
+#ifdef ASM_OUTPUT_DEF_FROM_DECLS
+ ASM_OUTPUT_DEF_FROM_DECLS (asm_out_file, decl, target);
+#else
+ ASM_OUTPUT_DEF (asm_out_file,
+ IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
+ IDENTIFIER_POINTER (target));
+#endif
+}
+#endif
+
+/* Process the vector of pending assembler defines. */
+
+void
+process_pending_assemble_output_defs (void)
+{
+#ifdef ASM_OUTPUT_DEF
+ unsigned i;
+ output_def_pair p;
+
+ for (i = 0; VEC_iterate (output_def_pair, output_defs, i, p); i++)
+ assemble_output_def (p->decl, p->target);
+
+ output_defs = NULL;
+#endif
+}
+
/* Emit an assembler directive to make the symbol for DECL an alias to
the symbol for TARGET. */
void
-assemble_alias (tree decl, tree target ATTRIBUTE_UNUSED)
+assemble_alias (tree decl, tree target)
{
- const char *name;
-
/* We must force creation of DECL_RTL for debug info generation, even though
we don't use it here. */
- make_decl_rtl (decl, NULL);
-
- name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+ make_decl_rtl (decl);
#ifdef ASM_OUTPUT_DEF
/* Make name accessible from other files, if appropriate. */
maybe_assemble_visibility (decl);
}
-#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
+ if (TARGET_DEFERRED_OUTPUT_DEFS (decl, target))
+ {
+ output_def_pair p;
+
+ p = ggc_alloc (sizeof (struct output_def_pair));
+ p->decl = decl;
+ p->target = target;
+ VEC_safe_push (output_def_pair, output_defs, p);
+ }
+ else
+ assemble_output_def (decl, target);
#else /* !ASM_OUTPUT_DEF */
#if defined (ASM_OUTPUT_WEAK_ALIAS) || defined (ASM_WEAKEN_DECL)
if (DECL_WEAK (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
#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)
+ {
+ 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)
+ cgraph_mark_needed_node (fnode);
+ else
+ {
+ vnode = cgraph_varpool_node_for_asm (target);
+ if (vnode != NULL)
+ cgraph_varpool_mark_needed_node (vnode);
+ }
+ }
+ 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);
+ }
+ }
+
+ if (fnode == NULL && vnode == NULL)
+ warning ("%qD aliased to undefined symbol %qE", decl, target);
+ }
+
TREE_USED (decl) = 1;
TREE_ASM_WRITTEN (decl) = 1;
TREE_ASM_WRITTEN (DECL_ASSEMBLER_NAME (decl)) = 1;
const_alias_set = new_alias_set ();
}
-enum tls_model
+static enum tls_model
decl_tls_model (tree decl)
{
enum tls_model kind;
flags = SECTION_CODE;
else if (decl && decl_readonly_section_1 (decl, reloc, shlib))
flags = 0;
- else if (strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0)
+ else if (unlikely_text_section_name
+ && strcmp (name, unlikely_text_section_name) == 0)
flags = SECTION_CODE;
else
flags = SECTION_WRITE;
|| 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
void
default_no_named_section (const char *name ATTRIBUTE_UNUSED,
- unsigned int flags ATTRIBUTE_UNUSED)
+ unsigned int flags ATTRIBUTE_UNUSED,
+ tree decl ATTRIBUTE_UNUSED)
{
/* Some object formats don't support named sections at all. The
front-end should already have flagged this as an error. */
}
void
-default_elf_asm_named_section (const char *name, unsigned int flags)
+default_elf_asm_named_section (const char *name, unsigned int flags,
+ tree decl ATTRIBUTE_UNUSED)
{
char flagchars[10], *f = flagchars;
- if (! named_section_first_declaration (name))
+ /* If we have already declared this section, we can use an
+ 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))
{
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))
+ *f++ = 'G';
*f = '\0';
fprintf (asm_out_file, "\t.section\t%s,\"%s\"", name, flagchars);
if (!(flags & SECTION_NOTYPE))
{
const char *type;
+ const char *format;
if (flags & SECTION_BSS)
type = "nobits";
else
type = "progbits";
- fprintf (asm_out_file, ",@%s", type);
+ format = ",@%s";
+#ifdef ASM_COMMENT_START
+ /* On platforms that use "@" as the assembly comment character,
+ use "%" instead. */
+ if (strcmp (ASM_COMMENT_START, "@") == 0)
+ format = ",%%%s";
+#endif
+ fprintf (asm_out_file, format, type);
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",
+ lang_hooks.decls.comdat_group (decl));
}
putc ('\n', asm_out_file);
}
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;
}
void
-default_pe_asm_named_section (const char *name, unsigned int flags)
+default_pe_asm_named_section (const char *name, unsigned int flags,
+ tree decl)
{
- default_coff_asm_named_section (name, flags);
+ default_coff_asm_named_section (name, flags, decl);
if (flags & SECTION_LINKONCE)
{
default_elf_select_section_1 (tree decl, int reloc,
unsigned HOST_WIDE_INT align, int shlib)
{
+ const char *sname;
switch (categorize_decl_for_section (decl, reloc, shlib))
{
case SECCAT_TEXT:
abort ();
case SECCAT_RODATA:
readonly_data_section ();
- break;
+ return;
case SECCAT_RODATA_MERGE_STR:
mergeable_string_section (decl, align, 0);
- break;
+ return;
case SECCAT_RODATA_MERGE_STR_INIT:
mergeable_string_section (DECL_INITIAL (decl), align, 0);
- break;
+ return;
case SECCAT_RODATA_MERGE_CONST:
mergeable_constant_section (DECL_MODE (decl), align, 0);
- break;
+ return;
case SECCAT_SRODATA:
- named_section (NULL_TREE, ".sdata2", reloc);
+ sname = ".sdata2";
break;
case SECCAT_DATA:
data_section ();
- break;
+ return;
case SECCAT_DATA_REL:
- named_section (NULL_TREE, ".data.rel", reloc);
+ sname = ".data.rel";
break;
case SECCAT_DATA_REL_LOCAL:
- named_section (NULL_TREE, ".data.rel.local", reloc);
+ sname = ".data.rel.local";
break;
case SECCAT_DATA_REL_RO:
- named_section (NULL_TREE, ".data.rel.ro", reloc);
+ sname = ".data.rel.ro";
break;
case SECCAT_DATA_REL_RO_LOCAL:
- named_section (NULL_TREE, ".data.rel.ro.local", reloc);
+ sname = ".data.rel.ro.local";
break;
case SECCAT_SDATA:
- named_section (NULL_TREE, ".sdata", reloc);
+ sname = ".sdata";
break;
case SECCAT_TDATA:
- named_section (NULL_TREE, ".tdata", reloc);
+ sname = ".tdata";
break;
case SECCAT_BSS:
#ifdef BSS_SECTION_ASM_OP
bss_section ();
+ return;
#else
- named_section (NULL_TREE, ".bss", reloc);
-#endif
+ sname = ".bss";
break;
+#endif
case SECCAT_SBSS:
- named_section (NULL_TREE, ".sbss", reloc);
+ sname = ".sbss";
break;
case SECCAT_TBSS:
- named_section (NULL_TREE, ".tbss", reloc);
+ sname = ".tbss";
break;
default:
abort ();
}
+
+ if (!DECL_P (decl))
+ decl = NULL_TREE;
+ named_section (decl, sname, reloc);
}
/* Construct a unique section name based on the decl name and the
flags |= SYMBOL_FLAG_FUNCTION;
if (targetm.binds_local_p (decl))
flags |= SYMBOL_FLAG_LOCAL;
- if (targetm.in_small_data_p (decl))
- flags |= SYMBOL_FLAG_SMALL;
if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (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
being PUBLIC, the thing *must* be defined in this translation unit.
Prevent this buglet from being propagated into rtl code as well. */
/* Static variables are always local. */
else if (! TREE_PUBLIC (exp))
local_p = true;
- /* A variable is local if the user tells us so. */
- else if (DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
+ /* A variable is local if the user explicitly tells us so. */
+ else if (DECL_VISIBILITY_SPECIFIED (exp) && DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
local_p = true;
/* Otherwise, variables defined outside this object may not be local. */
else if (DECL_EXTERNAL (exp))
/* 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. */
+ else if (DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
+ local_p = true;
/* If PIC, then assume that any global name can be overridden by
symbols resolved from other modules. */
else if (shlib)
{
char *const buf = alloca (40 + strlen (prefix));
ASM_GENERATE_INTERNAL_LABEL (buf, prefix, labelno);
- ASM_OUTPUT_LABEL (stream, buf);
+ ASM_OUTPUT_INTERNAL_LABEL (stream, buf);
}
/* This is the default behavior at the beginning of a file. It's