/* 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.
#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
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;
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. */
+/* The following global variable indicates if the first basic block
+ in a function belongs to the cold partition or not. */
-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. */
-
-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 maybe_assemble_visibility (tree);
static int in_named_entry_eq (const void *, const void *);
static hashval_t in_named_entry_hash (const void *);
+static void initialize_cold_section_name (void);
#ifdef BSS_SECTION_ASM_OP
#ifdef ASM_OUTPUT_BSS
static void asm_output_bss (FILE *, tree, const char *,
unsigned HOST_WIDE_INT);
static void mark_weak (tree);
\f
-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;
+enum in_section last_text_section;
/* Return a nonzero value if DECL has a section attribute. */
#ifndef IN_NAMED_SECTION
/* Text of section name when in_section == in_named. */
static GTY(()) const char *in_named_name;
+const char *last_text_section_name;
/* Hash table of flags that have been used for a particular named section. */
EXTRA_SECTION_FUNCTIONS
#endif
+static void
+initialize_cold_section_name (void)
+{
+ const char *name;
+ const char *stripped_name;
+ char *buffer;
+
+ gcc_assert (cfun && current_function_decl);
+ if (cfun->unlikely_text_section_name)
+ return;
+
+ if (flag_function_sections && DECL_SECTION_NAME (current_function_decl))
+ {
+ name = alloca (TREE_STRING_LENGTH (DECL_SECTION_NAME
+ (current_function_decl)));
+ strcpy ((char *) name, TREE_STRING_POINTER (DECL_SECTION_NAME
+ (current_function_decl)));
+ stripped_name = targetm.strip_name_encoding (name);
+ buffer = ACONCAT ((stripped_name, "_unlikely", NULL));
+ cfun->unlikely_text_section_name = ggc_strdup (buffer);
+ }
+ else
+ cfun->unlikely_text_section_name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
+}
+
/* Tell assembler to switch to text section. */
void
if (in_section != in_text)
{
in_section = in_text;
+ last_text_section = in_text;
fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
}
}
void
unlikely_text_section (void)
{
- const char *name;
- int len;
-
- if (! unlikely_text_section_name)
+ if (cfun)
{
- 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))
+ if (!cfun->unlikely_text_section_name)
+ initialize_cold_section_name ();
+
+ if (flag_function_sections
+ || ((in_section != in_unlikely_executed_text)
+ && (in_section != in_named
+ || (strcmp (in_named_name, cfun->unlikely_text_section_name)
+ != 0))))
{
- 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);
+ named_section (NULL_TREE, cfun->unlikely_text_section_name, 0);
+ in_section = in_unlikely_executed_text;
+ last_text_section = in_unlikely_executed_text;
}
}
-
- if ((in_section != in_unlikely_executed_text)
- && (in_section != in_named
- || strcmp (in_named_name, unlikely_text_section_name) != 0))
+ else
{
- named_section (NULL_TREE, unlikely_text_section_name, 0);
+ named_section (NULL_TREE, UNLIKELY_EXECUTED_TEXT_SECTION_NAME, 0);
in_section = in_unlikely_executed_text;
-
- if (!unlikely_section_label_printed)
- {
- ASM_OUTPUT_LABEL (asm_out_file, unlikely_section_label);
- unlikely_section_label_printed = true;
- }
+ last_text_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));
+ if (cfun)
+ {
+ ret_val = ((in_section == in_unlikely_executed_text)
+ || (in_section == in_named
+ && cfun->unlikely_text_section_name
+ && strcmp (in_named_name,
+ cfun->unlikely_text_section_name) == 0));
+ }
+ else
+ {
+ ret_val = ((in_section == in_unlikely_executed_text)
+ || (in_section == in_named
+ && strcmp (in_named_name,
+ UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0));
+ }
return ret_val;
}
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;
{
if (in_section != in_named || strcmp (name, in_named_name) != 0)
{
- if (! set_named_section_flags (name, flags))
- abort ();
+ bool unchanged = set_named_section_flags (name, flags);
+
+ gcc_assert (unchanged);
targetm.asm_out.named_section (name, flags, decl);
in_section = in_named;
}
}
+
+ if (in_text_section () || in_unlikely_text_section ())
+ {
+ last_text_section = in_section;
+ last_text_section_name = name;
+ }
}
/* Tell assembler to change to section NAME for DECL.
{
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);
- }
+ && cfun
+ && ! cfun->unlikely_text_section_name)
+ cfun->unlikely_text_section_name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
flags = targetm.section_type_flags (decl, name, reloc);
/* Sanity check user variables for flag changes. Non-user
- section flag changes will abort in named_section_flags.
+ section flag changes will die in named_section_flags.
However, don't complain if SECTION_OVERRIDE is set.
We trust that the setter knows that it is safe to ignore
the default flags for this decl. */
/* 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 ();
- else if (decl != NULL_TREE
- && DECL_SECTION_NAME (decl) != NULL_TREE)
+ int reloc = 0;
+
+ if (first_function_block_is_cold)
+ reloc = 1;
+
+#ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
+ targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
+#else
+ if (decl != NULL_TREE
+ && DECL_SECTION_NAME (decl) != NULL_TREE
+ && targetm.have_named_sections)
named_section (decl, (char *) 0, 0);
else
- text_section ();
+ text_section ();
+#endif
+}
+
+void
+current_function_section (tree decl)
+{
+#ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
+ int reloc = 0;
+
+ if (in_unlikely_text_section ()
+ || last_text_section == in_unlikely_executed_text)
+ reloc = 1;
+
+ targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
+#else
+ if (last_text_section == in_unlikely_executed_text)
+ unlikely_text_section ();
+ else if (last_text_section == in_text)
+ text_section ();
+ else if (last_text_section == in_named
+ && targetm.have_named_sections)
+ named_section (NULL_TREE, last_text_section_name, 0);
+ else
+ function_section (decl);
+#endif
}
/* Switch to read-only data section associated with function 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);
+ named_section_real (rname, SECTION_LINKONCE, decl);
+ return;
+ }
/* 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_flags (rname, SECTION_LINKONCE);
+ named_section_real (rname, SECTION_LINKONCE, decl);
return;
}
/* For .text.foo we want to use .rodata.foo. */
int
decode_reg_name (const char *asmspec)
{
- if (asmspec != 0 && strlen (asmspec) != 0)
+ if (asmspec != 0)
{
int i;
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));
- reg_number = decode_reg_name (name);
-
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 (0, "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
/* 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)];
return;
}
}
-
/* Now handle ordinary static variables and functions (in memory).
Also handle vars declared register invalidly. */
-
- if (name[0] == '*' && (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. */
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;
}
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
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, "HOTB", const_labelno);
+ cfun->hot_section_label = ggc_strdup (tmp_label);
+ ASM_GENERATE_INTERNAL_LABEL (tmp_label, "COLDB", const_labelno);
+ cfun->cold_section_label = ggc_strdup (tmp_label);
+ ASM_GENERATE_INTERNAL_LABEL (tmp_label, "HOTE", const_labelno);
+ cfun->hot_section_end_label = ggc_strdup (tmp_label);
+ ASM_GENERATE_INTERNAL_LABEL (tmp_label, "COLDE", 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 ();
assemble_align (FUNCTION_BOUNDARY);
+ ASM_OUTPUT_LABEL (asm_out_file, cfun->cold_section_label);
+ if (BB_PARTITION (ENTRY_BLOCK_PTR->next_bb) == BB_COLD_PARTITION)
+ {
+ /* Since the function starts with a cold section, we need to
+ explicitly align the hot section and write out the hot
+ section label. */
+ text_section ();
+ 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. */
+
+ int i;
+ int len;
+ char *s;
+
+ initialize_cold_section_name ();
+
+ /* The following is necessary, because 'strcmp
+ (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)), blah)' always
+ fails, presumably because TREE_STRING_POINTER is declared to
+ be an array of size 1 of char. */
+
+ len = TREE_STRING_LENGTH (DECL_SECTION_NAME (decl));
+ s = (char *) xmalloc (len + 1);
+
+ for (i = 0; i < len; i ++)
+ s[i] = (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)))[i];
+ s[len] = '\0';
+
+ if (cfun->unlikely_text_section_name
+ && (strcmp (s, cfun->unlikely_text_section_name) == 0))
+ first_function_block_is_cold = true;
+ }
+
+ last_text_section = no_section;
+
+ /* Switch to the correct text section for the start of the function. */
- resolve_unique_section (decl, 0, flag_function_sections);
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);
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;
- }
+ insert_section_boundary_note ();
}
/* Output assembler code associated with defining the size of the
output_constant_pool (fnname, decl);
function_section (decl); /* need to switch back */
}
+ /* Output labels for end of hot/cold text sections (to be used by
+ debug info.) */
+ if (flag_reorder_blocks_and_partition)
+ {
+ enum in_section save_text_section;
+
+ save_text_section = in_section;
+ unlikely_text_section ();
+ ASM_OUTPUT_LABEL (asm_out_file, cfun->cold_section_end_label);
+ if (first_function_block_is_cold)
+ text_section ();
+ else
+ function_section (decl);
+ ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_end_label);
+ if (save_text_section == in_unlikely_executed_text)
+ unlikely_text_section ();
+ }
}
\f
/* Assemble code to leave SIZE bytes of zeros. */
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)
{
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 `%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;
}
In particular, a.out format supports a maximum alignment of 4. */
if (align > MAX_OFILE_ALIGNMENT)
{
- warning ("%Jalignment of '%D' is greater than maximum object "
+ warning (0, "%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 (DECL_PRESERVE_P (decl))
targetm.asm_out.mark_decl_preserved (name);
- /* 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);
-
/* Handle uninitialized definitions. */
/* If the decl has been given an explicit section name, then it
#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 '%D' is greater than "
+ warning (0, "%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. */
}
}
+/* 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
}
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. */
}
-/* 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);
}
/* 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;
}
\f
/* 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
+ 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:
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
&& 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:
}
}
- /* Should not get here. */
- abort ();
+ gcc_unreachable ();
}
\f
/* Make a copy of the whole tree structure for a constant. This
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;
}
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;
}
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;
/* 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. */
desc->mem = def = gen_const_mem (mode, symbol);
set_mem_attributes (def, lang_hooks.types.type_for_mode (mode, 0), 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
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;
-
+ {
+ REAL_VALUE_TYPE r;
+
+ gcc_assert (GET_CODE (x) == CONST_DOUBLE);
+ REAL_VALUE_FROM_CONST_DOUBLE (r, x);
+ assemble_real (r, mode, align);
+ break;
+ }
+
case MODE_INT:
case MODE_PARTIAL_INT:
assemble_integer (x, GET_MODE_SIZE (mode), align, 1);
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:
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;
&& 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 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:
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;
-
- inner = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
- nalign = MIN (align, GET_MODE_ALIGNMENT (inner));
-
- elt_size = GET_MODE_SIZE (inner);
+ break;
- 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);
+ 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));
+
+ 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);
+ 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 ();
- 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");
+ gcc_assert (TREE_CODE (exp) == CONSTRUCTOR);
+ output_constructor (exp, size, align);
return;
case ERROR_MARK:
return;
default:
- abort ();
+ gcc_unreachable ();
}
if (size > thissize)
int byte_buffer_in_use = 0;
int byte = 0;
- 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);
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))
{
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
{
/* 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 '%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 (0, "%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 (0, "%Jweak declaration of %qD not supported", decl, decl);
mark_weak (decl);
}
ASM_WEAKEN_LABEL (asm_out_file, name);
#else
#ifdef ASM_OUTPUT_WEAK_ALIAS
- warning ("only weak aliases are supported in this configuration");
+ warning (0, "only weak aliases are supported in this configuration");
return;
#endif
#endif
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 ATTRIBUTE_UNUSED)
+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;
+
+ /* C++ thunk emitting code produces aliases late in the game.
+ Avoid confusing cgraph code in that case. */
+ if (!cgraph_global_info_ready)
+ {
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ fnode = cgraph_node_for_asm (target);
+ if (fnode == NULL)
+ vnode = cgraph_varpool_node_for_asm (target);
+ }
+ else
+ {
+ vnode = cgraph_varpool_node_for_asm (target);
+ if (vnode == NULL)
+ fnode = cgraph_node_for_asm (target);
+ }
+ }
+
+ if (fnode)
+ {
+ cgraph_mark_needed_node (fnode);
+ 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 ATTRIBUTE_UNUSED)
+{
+ if (TREE_ASM_WRITTEN (decl))
+ return;
+
+ TREE_ASM_WRITTEN (decl) = 1;
+ TREE_ASM_WRITTEN (DECL_ASSEMBLER_NAME (decl)) = 1;
#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));
+# 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);
+ }
#endif
-#else /* !ASM_OUTPUT_DEF */
-#if defined (ASM_OUTPUT_WEAK_ALIAS) || defined (ASM_WEAKEN_DECL)
- if (DECL_WEAK (decl))
+}
+
+/* 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++)
{
- 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) ; )
- if (DECL_ASSEMBLER_NAME (decl)
- == DECL_ASSEMBLER_NAME (TREE_VALUE (t)))
- *p = TREE_CHAIN (t);
- else
- p = &TREE_CHAIN (t);
+ tree target_decl;
+
+ target_decl = find_decl_and_mark_needed (p->decl, p->target);
+ if (target_decl == NULL)
+ error ("%J%qD aliased to undefined symbol %qE",
+ p->decl, p->decl, p->target);
+ else if (DECL_EXTERNAL (target_decl))
+ error ("%J%qD aliased to external symbol %qE",
+ p->decl, p->decl, p->target);
}
- else
- warning ("only weak aliases are supported in this configuration");
+}
-#else
- warning ("alias definitions not supported in this configuration; ignored");
-#endif
+/* 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;
+
+#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. */
+ 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
const_alias_set = new_alias_set ();
}
-enum tls_model
+static enum tls_model
decl_tls_model (tree decl)
{
enum tls_model kind;
if (attr)
{
attr = TREE_VALUE (TREE_VALUE (attr));
- if (TREE_CODE (attr) != STRING_CST)
- abort ();
+ gcc_assert (TREE_CODE (attr) == STRING_CST);
+
if (!strcmp (TREE_STRING_POINTER (attr), "local-exec"))
kind = TLS_MODEL_LOCAL_EXEC;
else if (!strcmp (TREE_STRING_POINTER (attr), "initial-exec"))
else if (!strcmp (TREE_STRING_POINTER (attr), "global-dynamic"))
kind = TLS_MODEL_GLOBAL_DYNAMIC;
else
- abort ();
+ gcc_unreachable ();
return kind;
}
is_local = targetm.binds_local_p (decl);
- if (!flag_pic)
+ if (!flag_shlib)
{
if (is_local)
kind = TLS_MODEL_LOCAL_EXEC;
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;
|| 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))
+ if (!(HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
&& ! named_section_first_declaration (name))
{
fprintf (asm_out_file, "\t.section\t%s\n", name);
*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))
+ if (HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
fprintf (asm_out_file, ",%s,comdat",
lang_hooks.decls.comdat_group (decl));
}
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:
/* We're not supposed to be called on FUNCTION_DECLs. */
- abort ();
+ gcc_unreachable ();
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 ();
+ gcc_unreachable ();
}
+
+ if (!DECL_P (decl))
+ decl = NULL_TREE;
+ 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.tb." : ".tbss.";
break;
default:
- abort ();
+ gcc_unreachable ();
}
plen = strlen (prefix);
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. */
}
/* 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
{
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