You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
/* This file handles generation of all the assembler code
#include "tree-mudflap.h"
#include "cgraph.h"
#include "cfglayout.h"
+#include "basic-block.h"
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h" /* Needed for external data
#endif
/* The (assembler) name of the first globally-visible object output. */
+extern GTY(()) const char *first_global_object_name;
+extern GTY(()) const char *weak_global_object_name;
+
const char *first_global_object_name;
const char *weak_global_object_name;
tree last_assemble_variable_decl;
-/* The following global variable indicates if the section label for the
- "cold" section of code has been output yet to the assembler. The
- label is useful when running gdb. This is part of the optimization that
- partitions hot and cold basic blocks into separate sections of the .o
- file. */
-
-static bool unlikely_section_label_printed = false;
-
-/* The following global variable indicates the label name to be put at
- the start of the first cold section within each function, when
- partitioning basic blocks into hot and cold sections. */
+/* The following global variable indicates if the first basic block
+ in a function belongs to the cold partition or not. */
-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 *stripped_name;
+ char *name, *buffer;
+ tree dsn;
+
+ gcc_assert (cfun && current_function_decl);
+ if (cfun->unlikely_text_section_name)
+ return;
+
+ dsn = DECL_SECTION_NAME (current_function_decl);
+ if (flag_function_sections && dsn)
+ {
+ name = alloca (TREE_STRING_LENGTH (dsn) + 1);
+ memcpy (name, TREE_STRING_POINTER (dsn), TREE_STRING_LENGTH (dsn) + 1);
+
+ 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))
- {
- 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
+ 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))))
{
- 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;
}
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.
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);
+ && 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. */
{
flags = get_named_section_flags (name);
if ((flags & SECTION_OVERRIDE) == 0)
- error ("%J%D causes a section type conflict", decl, decl);
+ error ("%+D causes a section type conflict", decl);
}
named_section_real (name, flags, decl);
void
function_section (tree decl)
{
- if (decl == NULL_TREE)
- text_section ();
+ 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
- {
- /* ??? 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);
+ text_section ();
+#endif
+}
+void
+current_function_section (tree decl)
+{
#ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
- targetm.asm_out.select_section (decl, unlikely, DECL_ALIGN (decl));
+ 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 (unlikely)
- unlikely_text_section ();
- else if (DECL_SECTION_NAME (decl))
- named_section (decl, 0, 0);
- else
- text_section ();
+ 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);
= ADDITIONAL_REGISTER_NAMES;
for (i = 0; i < (int) ARRAY_SIZE (table); i++)
- if (! strcmp (asmspec, table[i].name))
+ if (table[i].name[0]
+ && ! strcmp (asmspec, table[i].name))
return table[i].number;
}
#endif /* ADDITIONAL_REGISTER_NAMES */
}
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-
-
- if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
+
+ if (name[0] != '*' && TREE_CODE (decl) != FUNCTION_DECL
+ && DECL_REGISTER (decl))
+ {
+ error ("register name not specified for %q+D", decl);
+ }
+ else if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
{
- reg_number = decode_reg_name (name);
+ const char *asmspec = name+1;
+ reg_number = decode_reg_name (asmspec);
/* First detect errors in declaring global registers. */
if (reg_number == -1)
- error ("%Jregister name not specified for %qD", decl, decl);
+ error ("register name not specified for %q+D", decl);
else if (reg_number < 0)
- error ("%Jinvalid register name for %qD", decl, decl);
+ error ("invalid register name for %q+D", decl);
else if (TYPE_MODE (TREE_TYPE (decl)) == BLKmode)
- error ("%Jdata type of %qD isn%'t suitable for a register",
- decl, decl);
+ error ("data type of %q+D isn%'t suitable for a register",
+ decl);
else if (! HARD_REGNO_MODE_OK (reg_number, TYPE_MODE (TREE_TYPE (decl))))
- error ("%Jregister specified for %qD isn%'t suitable for data type",
- decl, decl);
+ error ("register specified for %q+D isn%'t suitable for data type",
+ decl);
/* Now handle properly declared static register variables. */
else
{
error ("global register variable has initial value");
}
if (TREE_THIS_VOLATILE (decl))
- warning ("volatile register variables don%'t "
+ warning (0, "volatile register variables don%'t "
"work as you might wish");
/* If the user specified one of the eliminables registers here,
/* Make this register global, so not usable for anything
else. */
#ifdef ASM_DECLARE_REGISTER_GLOBAL
+ name = IDENTIFIER_POINTER (DECL_NAME (decl));
ASM_DECLARE_REGISTER_GLOBAL (asm_out_file, decl, reg_number, name);
#endif
nregs = hard_regno_nregs[reg_number][DECL_MODE (decl)];
{
reg_number = decode_reg_name (name);
if (reg_number >= 0 || reg_number == -3)
- error ("%Jregister name given for non-register variable %qD", decl, decl);
+ error ("register name given for non-register variable %q+D", decl);
}
#endif
}
if (!*type)
{
const char *p;
- char *name;
+ const char *name;
rtx decl_rtl = DECL_RTL (decl);
p = targetm.strip_name_encoding (XSTR (XEXP (decl_rtl, 0), 0));
- name = xstrdup (p);
+ name = ggc_strdup (p);
*type = name;
}
assemble_start_function (tree decl, const char *fnname)
{
int align;
+ char tmp_label[100];
+ bool hot_label_written = false;
- if (unlikely_text_section_name)
- free (unlikely_text_section_name);
+ cfun->unlikely_text_section_name = NULL;
+
+ first_function_block_is_cold = false;
+ if (flag_reorder_blocks_and_partition)
+ {
+ ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LHOTB", const_labelno);
+ cfun->hot_section_label = ggc_strdup (tmp_label);
+ ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LCOLDB", const_labelno);
+ cfun->cold_section_label = ggc_strdup (tmp_label);
+ ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LHOTE", const_labelno);
+ cfun->hot_section_end_label = ggc_strdup (tmp_label);
+ ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LCOLDE", const_labelno);
+ cfun->cold_section_end_label = ggc_strdup (tmp_label);
+ const_labelno++;
+ }
+ else
+ {
+ cfun->hot_section_label = NULL;
+ cfun->cold_section_label = NULL;
+ cfun->hot_section_end_label = NULL;
+ cfun->cold_section_end_label = NULL;
+ }
- unlikely_section_label_printed = false;
- unlikely_text_section_name = NULL;
-
- unlikely_section_label = reconcat (unlikely_section_label,
- fnname, ".unlikely_section", NULL);
-
/* The following code does not need preprocessing in the assembler. */
app_disable ();
if (CONSTANT_POOL_BEFORE_FUNCTION)
output_constant_pool (fnname, decl);
- /* Make sure the cold text (code) section is properly aligned. This
- is necessary here in the case where the function has both hot and
- cold sections, because we don't want to re-set the alignment when the
- section switch happens mid-function. We don't need to set the hot
- section alignment here, because code further down in this function
- sets the alignment for whichever section comes first, and if there
- is a hot section it is guaranteed to be first. */
+ resolve_unique_section (decl, 0, flag_function_sections);
+
+ /* Make sure the not and cold text (code) sections are properly
+ aligned. This is necessary here in the case where the function
+ has both hot and cold sections, because we don't want to re-set
+ the alignment when the section switch happens mid-function. */
if (flag_reorder_blocks_and_partition)
{
unlikely_text_section ();
assemble_align (FUNCTION_BOUNDARY);
+ ASM_OUTPUT_LABEL (asm_out_file, cfun->cold_section_label);
+
+ /* When the function starts with a cold section, we need to explicitly
+ align the hot section and write out the hot section label.
+ But if the current function is a thunk, we do not have a CFG. */
+ if (!current_function_is_thunk
+ && BB_PARTITION (ENTRY_BLOCK_PTR->next_bb) == BB_COLD_PARTITION)
+ {
+ 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. */
+
+ initialize_cold_section_name ();
+
+ if (cfun->unlikely_text_section_name
+ && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
+ cfun->unlikely_text_section_name) == 0)
+ first_function_block_is_cold = true;
+ }
+
+ 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);
/* Standard thing is just output label for the function. */
ASM_OUTPUT_LABEL (asm_out_file, fnname);
#endif /* ASM_DECLARE_FUNCTION_NAME */
-
- if (in_unlikely_text_section ()
- && !unlikely_section_label_printed)
- {
- ASM_OUTPUT_LABEL (asm_out_file, unlikely_section_label);
- unlikely_section_label_printed = true;
- }
}
/* Output assembler code associated with defining the size of the
assemble_end_function (tree decl, const char *fnname)
{
#ifdef ASM_DECLARE_FUNCTION_SIZE
+ /* We could have switched section in the middle of the function. */
+ if (flag_reorder_blocks_and_partition)
+ function_section (decl);
ASM_DECLARE_FUNCTION_SIZE (asm_out_file, fnname, decl);
#endif
if (! CONSTANT_POOL_BEFORE_FUNCTION)
output_constant_pool (fnname, decl);
function_section (decl); /* need to switch back */
}
+ /* 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. */
if (!dont_output_data && DECL_SIZE (decl) == 0)
{
- error ("%Jstorage size of %qD isn%'t known", decl, decl);
+ error ("storage size of %q+D isn%'t known", decl);
TREE_ASM_WRITTEN (decl) = 1;
return;
}
if (! dont_output_data
&& ! host_integerp (DECL_SIZE_UNIT (decl), 1))
{
- error ("%Jsize of variable %qD is too large", decl, decl);
+ error ("size of variable %q+D is too large", decl);
return;
}
In particular, a.out format supports a maximum alignment of 4. */
if (align > MAX_OFILE_ALIGNMENT)
{
- warning ("%Jalignment of %qD is greater than maximum object "
- "file alignment. Using %d", decl, decl,
+ warning (0, "alignment of %q+D is greater than maximum object "
+ "file alignment. Using %d", decl,
MAX_OFILE_ALIGNMENT/BITS_PER_UNIT);
align = MAX_OFILE_ALIGNMENT;
}
if (DECL_SECTION_NAME (decl) || dont_output_data)
;
/* We don't implement common thread-local data at present. */
- else if (DECL_THREAD_LOCAL (decl))
+ else if (DECL_THREAD_LOCAL_P (decl))
{
if (DECL_COMMON (decl))
sorry ("thread-local COMMON data not implemented");
#if !defined(ASM_OUTPUT_ALIGNED_COMMON) && !defined(ASM_OUTPUT_ALIGNED_DECL_COMMON) && !defined(ASM_OUTPUT_ALIGNED_BSS)
if ((unsigned HOST_WIDE_INT) DECL_ALIGN_UNIT (decl) > rounded)
- warning ("%Jrequested alignment for %qD is greater than "
- "implemented alignment of %d", decl, decl, rounded);
+ warning (0, "requested alignment for %q+D is greater than "
+ "implemented alignment of %wu", decl, rounded);
#endif
/* If the target cannot output uninitialized but not common global data
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. */
}
/* 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)
/* 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:
/* The value of the constant. */
tree value;
+
+ /* Hash of value. Computing the hash from value each time
+ hashfn is called can't work properly, as that means recursive
+ use of the hash table during hash table expansion. */
+ hashval_t hash;
};
static GTY((param_is (struct constant_descriptor_tree)))
static hashval_t
const_desc_hash (const void *ptr)
{
- return const_hash_1 (((struct constant_descriptor_tree *)ptr)->value);
+ return ((struct constant_descriptor_tree *)ptr)->hash;
}
static hashval_t
case CONSTRUCTOR:
{
- tree link;
+ unsigned HOST_WIDE_INT idx;
+ tree value;
hi = 5 + int_size_in_bytes (TREE_TYPE (exp));
- for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
- if (TREE_VALUE (link))
- hi = hi * 603 + const_hash_1 (TREE_VALUE (link));
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
+ if (value)
+ hi = hi * 603 + const_hash_1 (value);
return hi;
}
static int
const_desc_eq (const void *p1, const void *p2)
{
- return compare_constant (((struct constant_descriptor_tree *)p1)->value,
- ((struct constant_descriptor_tree *)p2)->value);
+ const struct constant_descriptor_tree *c1 = p1;
+ const struct constant_descriptor_tree *c2 = p2;
+ if (c1->hash != c2->hash)
+ return 0;
+ return compare_constant (c1->value, c2->value);
}
/* Compare t1 and t2, and return 1 only if they are known to result in
case CONSTRUCTOR:
{
- tree l1, l2;
+ VEC(constructor_elt, gc) *v1, *v2;
+ unsigned HOST_WIDE_INT idx;
typecode = TREE_CODE (TREE_TYPE (t1));
if (typecode != TREE_CODE (TREE_TYPE (t2)))
return 0;
}
- for (l1 = CONSTRUCTOR_ELTS (t1), l2 = CONSTRUCTOR_ELTS (t2);
- l1 && l2;
- l1 = TREE_CHAIN (l1), l2 = TREE_CHAIN (l2))
+ v1 = CONSTRUCTOR_ELTS (t1);
+ v2 = CONSTRUCTOR_ELTS (t2);
+ if (VEC_length (constructor_elt, v1)
+ != VEC_length (constructor_elt, v2))
+ return 0;
+
+ for (idx = 0; idx < VEC_length (constructor_elt, v1); ++idx)
{
+ constructor_elt *c1 = VEC_index (constructor_elt, v1, idx);
+ constructor_elt *c2 = VEC_index (constructor_elt, v2, idx);
+
/* Check that each value is the same... */
- if (! compare_constant (TREE_VALUE (l1), TREE_VALUE (l2)))
+ if (!compare_constant (c1->value, c2->value))
return 0;
/* ... and that they apply to the same fields! */
if (typecode == ARRAY_TYPE)
{
- if (! compare_constant (TREE_PURPOSE (l1),
- TREE_PURPOSE (l2)))
+ if (!compare_constant (c1->index, c2->index))
return 0;
}
else
{
- if (TREE_PURPOSE (l1) != TREE_PURPOSE (l2))
+ if (c1->index != c2->index)
return 0;
}
}
- return l1 == NULL_TREE && l2 == NULL_TREE;
+ return 1;
}
case ADDR_EXPR:
case CONSTRUCTOR:
{
tree copy = copy_node (exp);
- tree list = copy_list (CONSTRUCTOR_ELTS (exp));
- tree tail;
-
- CONSTRUCTOR_ELTS (copy) = list;
- for (tail = list; tail; tail = TREE_CHAIN (tail))
- TREE_VALUE (tail) = copy_constant (TREE_VALUE (tail));
-
+ VEC(constructor_elt, gc) *v;
+ unsigned HOST_WIDE_INT idx;
+ tree purpose, value;
+
+ v = VEC_alloc(constructor_elt, gc, VEC_length(constructor_elt,
+ CONSTRUCTOR_ELTS (exp)));
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (exp), idx, purpose, value)
+ {
+ constructor_elt *ce = VEC_quick_push (constructor_elt, v, NULL);
+ ce->index = purpose;
+ ce->value = copy_constant (value);
+ }
+ CONSTRUCTOR_ELTS (copy) = v;
return copy;
}
/* 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);
}
case NOP_EXPR:
case CONVERT_EXPR:
case NON_LVALUE_EXPR:
+ case VIEW_CONVERT_EXPR:
reloc = compute_reloc_for_constant (TREE_OPERAND (exp, 0));
break;
case CONSTRUCTOR:
- for (tem = CONSTRUCTOR_ELTS (exp); tem; tem = TREE_CHAIN (tem))
- if (TREE_VALUE (tem) != 0)
- reloc |= compute_reloc_for_constant (TREE_VALUE (tem));
-
+ {
+ unsigned HOST_WIDE_INT idx;
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, tem)
+ if (tem != 0)
+ reloc |= compute_reloc_for_constant (tem);
+ }
break;
default:
case NOP_EXPR:
case CONVERT_EXPR:
case NON_LVALUE_EXPR:
+ case VIEW_CONVERT_EXPR:
output_addressed_constants (TREE_OPERAND (exp, 0));
break;
case CONSTRUCTOR:
- for (tem = CONSTRUCTOR_ELTS (exp); tem; tem = TREE_CHAIN (tem))
- if (TREE_VALUE (tem) != 0)
- output_addressed_constants (TREE_VALUE (tem));
-
+ {
+ unsigned HOST_WIDE_INT idx;
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, tem)
+ if (tem != 0)
+ output_addressed_constants (tem);
+ }
break;
default:
if ((TREE_CODE (TREE_TYPE (value)) == UNION_TYPE
|| TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE)
&& TREE_CONSTANT (value)
- && CONSTRUCTOR_ELTS (value))
+ && !VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (value)))
{
+ unsigned HOST_WIDE_INT idx;
tree elt;
bool absolute = true;
- for (elt = CONSTRUCTOR_ELTS (value); elt; elt = TREE_CHAIN (elt))
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (value), idx, elt)
{
tree reloc;
- value = TREE_VALUE (elt);
- reloc = initializer_constant_valid_p (value, TREE_TYPE (value));
+ reloc = initializer_constant_valid_p (elt, TREE_TYPE (elt));
if (!reloc)
return NULL_TREE;
if (reloc != null_pointer_node)
if (value
&& TREE_CODE (value) == FUNCTION_DECL
&& ((decl_function_context (value) && !DECL_NO_STATIC_CHAIN (value))
- || DECL_NON_ADDR_CONST_P (value)))
+ || DECL_DLLIMPORT_P (value)))
return NULL_TREE;
return value;
if (size == 0 || flag_syntax_only)
return;
+ /* See if we're trying to initialize a pointer in a non-default mode
+ to the address of some declaration somewhere. If the target says
+ the mode is valid for pointers, assume the target has a way of
+ resolving it. */
+ if (TREE_CODE (exp) == NOP_EXPR
+ && POINTER_TYPE_P (TREE_TYPE (exp))
+ && targetm.valid_pointer_mode (TYPE_MODE (TREE_TYPE (exp))))
+ {
+ tree saved_type = TREE_TYPE (exp);
+
+ /* Peel off any intermediate conversions-to-pointer for valid
+ pointer modes. */
+ while (TREE_CODE (exp) == NOP_EXPR
+ && POINTER_TYPE_P (TREE_TYPE (exp))
+ && targetm.valid_pointer_mode (TYPE_MODE (TREE_TYPE (exp))))
+ exp = TREE_OPERAND (exp, 0);
+
+ /* If what we're left with is the address of something, we can
+ convert the address to the final type and output it that
+ way. */
+ if (TREE_CODE (exp) == ADDR_EXPR)
+ exp = build1 (ADDR_EXPR, saved_type, TREE_OPERAND (exp, 0));
+ }
+
/* Eliminate any conversions since we'll be outputting the underlying
constant. */
while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR
|| TREE_CODE (exp) == NON_LVALUE_EXPR
|| TREE_CODE (exp) == VIEW_CONVERT_EXPR)
- exp = TREE_OPERAND (exp, 0);
+ {
+ HOST_WIDE_INT type_size = int_size_in_bytes (TREE_TYPE (exp));
+ HOST_WIDE_INT op_size = int_size_in_bytes (TREE_TYPE (TREE_OPERAND (exp, 0)));
+
+ /* Make sure eliminating the conversion is really a no-op, except with
+ VIEW_CONVERT_EXPRs to allow for wild Ada unchecked conversions and
+ union types to allow for Ada unchecked unions. */
+ if (type_size > op_size
+ && TREE_CODE (exp) != VIEW_CONVERT_EXPR
+ && TREE_CODE (TREE_TYPE (exp)) != UNION_TYPE)
+ internal_error ("no-op convert from %wd to %wd bytes in initializer",
+ op_size, type_size);
+
+ exp = TREE_OPERAND (exp, 0);
+ }
code = TREE_CODE (TREE_TYPE (exp));
thissize = int_size_in_bytes (TREE_TYPE (exp));
/* Allow a constructor with no elements for any data type.
This means to fill the space with zeros. */
- if (TREE_CODE (exp) == CONSTRUCTOR && CONSTRUCTOR_ELTS (exp) == 0)
+ if (TREE_CODE (exp) == CONSTRUCTOR
+ && VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (exp)))
{
assemble_zeros (size);
return;
array_size_for_constructor (tree val)
{
tree max_index, i;
+ unsigned HOST_WIDE_INT cnt;
+ tree index, value;
/* This code used to attempt to handle string constants that are not
arrays of single-bytes, but nothing else does, so there's no point in
return TREE_STRING_LENGTH (val);
max_index = NULL_TREE;
- for (i = CONSTRUCTOR_ELTS (val); i; i = TREE_CHAIN (i))
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (val), cnt, index, value)
{
- tree index = TREE_PURPOSE (i);
-
if (TREE_CODE (index) == RANGE_EXPR)
index = TREE_OPERAND (index, 1);
if (max_index == NULL_TREE || tree_int_cst_lt (max_index, index))
unsigned int align)
{
tree type = TREE_TYPE (exp);
- tree link, field = 0;
+ tree field = 0;
tree min_index = 0;
/* Number of bytes output or skipped so far.
In other words, current position within the constructor. */
/* Nonzero means BYTE contains part of a byte, to be output. */
int byte_buffer_in_use = 0;
int byte = 0;
+ unsigned HOST_WIDE_INT cnt;
+ constructor_elt *ce;
gcc_assert (HOST_BITS_PER_WIDE_INT >= BITS_PER_UNIT);
There is always a maximum of one element in the chain LINK for unions
(even if the initializer in a source program incorrectly contains
more one). */
- for (link = CONSTRUCTOR_ELTS (exp);
- link;
- link = TREE_CHAIN (link),
- field = field ? TREE_CHAIN (field) : 0)
+ for (cnt = 0;
+ VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (exp), cnt, ce);
+ cnt++, field = field ? TREE_CHAIN (field) : 0)
{
- tree val = TREE_VALUE (link);
+ tree val = ce->value;
tree index = 0;
/* The element in a union constructor specifies the proper field
or index. */
if ((TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE
|| TREE_CODE (type) == QUAL_UNION_TYPE)
- && TREE_PURPOSE (link) != 0)
- field = TREE_PURPOSE (link);
+ && ce->index != 0)
+ field = ce->index;
else if (TREE_CODE (type) == ARRAY_TYPE)
- index = TREE_PURPOSE (link);
+ index = ce->index;
#ifdef ASM_COMMENT_START
if (field && flag_verbose_asm)
if each element has the proper size. */
if ((field != 0 || index != 0) && pos != total_bytes)
{
+ gcc_assert (pos >= total_bytes);
assemble_zeros (pos - total_bytes);
total_bytes = pos;
}
/* If still not at proper byte, advance to there. */
if (next_offset / BITS_PER_UNIT != total_bytes)
{
+ gcc_assert (next_offset / BITS_PER_UNIT >= total_bytes);
assemble_zeros (next_offset / BITS_PER_UNIT - total_bytes);
total_bytes = next_offset / BITS_PER_UNIT;
}
merge_weak (tree newdecl, tree olddecl)
{
if (DECL_WEAK (newdecl) == DECL_WEAK (olddecl))
- return;
+ {
+ if (DECL_WEAK (newdecl) && SUPPORTS_WEAK)
+ {
+ tree *pwd;
+ /* We put the NEWDECL on the weak_decls list at some point
+ and OLDDECL as well. Keep just OLDDECL on the list. */
+ for (pwd = &weak_decls; *pwd; pwd = &TREE_CHAIN (*pwd))
+ if (TREE_VALUE (*pwd) == newdecl)
+ {
+ *pwd = TREE_CHAIN (*pwd);
+ break;
+ }
+ }
+ return;
+ }
if (DECL_WEAK (newdecl))
{
declare_weak because the NEWDECL and OLDDECL was not yet
been merged; therefore, TREE_ASM_WRITTEN was not set. */
if (TREE_ASM_WRITTEN (olddecl))
- error ("%Jweak declaration of %qD must precede definition",
- newdecl, newdecl);
+ error ("weak declaration of %q+D must precede definition",
+ newdecl);
/* If we've already generated rtl referencing OLDDECL, we may
have done so in a way that will not function properly with
a weak symbol. */
else if (TREE_USED (olddecl)
&& TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (olddecl)))
- warning ("%Jweak declaration of %qD after first use results "
- "in unspecified behavior", newdecl, newdecl);
+ warning (0, "weak declaration of %q+D after first use results "
+ "in unspecified behavior", newdecl);
if (SUPPORTS_WEAK)
{
declare_weak (tree decl)
{
if (! TREE_PUBLIC (decl))
- error ("%Jweak declaration of %qD must be public", decl, decl);
+ error ("weak declaration of %q+D must be public", decl);
else if (TREE_CODE (decl) == FUNCTION_DECL && TREE_ASM_WRITTEN (decl))
- error ("%Jweak declaration of %qD must precede definition", decl, decl);
+ error ("weak declaration of %q+D must precede definition", decl);
else if (SUPPORTS_WEAK)
{
if (! DECL_WEAK (decl))
weak_decls = tree_cons (NULL, decl, weak_decls);
}
else
- warning ("%Jweak declaration of %qD not supported", decl, decl);
+ warning (0, "weak declaration of %q+D not supported", decl);
mark_weak (decl);
}
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
/* 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 preceed their definition have to be queued for later processing. */
+ that precede their definition have to be queued for later processing. */
-struct alias_pair GTY(())
+typedef struct alias_pair GTY(())
{
tree decl;
tree target;
-};
-typedef struct alias_pair *alias_pair;
+} alias_pair;
/* Define gc'd vector type. */
-DEF_VEC_GC_P(alias_pair);
+DEF_VEC_O(alias_pair);
+DEF_VEC_ALLOC_O(alias_pair,gc);
-static GTY(()) VEC(alias_pair) *alias_pairs;
+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. */
if (fnode)
{
- cgraph_mark_needed_node (fnode);
+ /* We can't mark function nodes as used after cgraph global info
+ is finished. This wouldn't generally be necessary, but C++
+ virtual table thunks are introduced late in the game and
+ might seem like they need marking, although in fact they
+ don't. */
+ if (! cgraph_global_info_ready)
+ cgraph_mark_needed_node (fnode);
return fnode->decl;
}
else if (vnode)
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)
+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;
finish_aliases_1 (void)
{
unsigned i;
- alias_pair p;
+ alias_pair *p;
for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); i++)
{
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);
+ error ("%q+D aliased to undefined symbol %qs",
+ p->decl, IDENTIFIER_POINTER (p->target));
else if (DECL_EXTERNAL (target_decl))
- error ("%J%qD aliased to external symbol %qE",
- p->decl, p->decl, p->target);
+ error ("%q+D aliased to external symbol %qs",
+ p->decl, IDENTIFIER_POINTER (p->target));
}
}
finish_aliases_2 (void)
{
unsigned i;
- alias_pair p;
+ alias_pair *p;
for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); i++)
do_assemble_alias (p->decl, p->target);
- alias_pairs = NULL;
+ VEC_truncate (alias_pair, alias_pairs, 0);
}
/* Emit an assembler directive to make the symbol for DECL an alias to
/* Allow aliases to aliases. */
if (TREE_CODE (decl) == FUNCTION_DECL)
- cgraph_node (decl);
+ cgraph_node (decl)->alias = true;
else
- cgraph_varpool_node (decl);
+ 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. */
do_assemble_alias (decl, target);
else
{
- alias_pair p;
-
- p = ggc_alloc (sizeof (struct alias_pair));
+ alias_pair *p = VEC_safe_push (alias_pair, gc, alias_pairs, NULL);
p->decl = decl;
p->target = target;
- VEC_safe_push (alias_pair, alias_pairs, p);
}
}
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
}
const_alias_set = new_alias_set ();
}
-static enum tls_model
-decl_tls_model (tree decl)
+enum tls_model
+decl_default_tls_model (tree decl)
{
enum tls_model kind;
- tree attr = lookup_attribute ("tls_model", DECL_ATTRIBUTES (decl));
bool is_local;
- if (attr)
- {
- attr = TREE_VALUE (TREE_VALUE (attr));
- 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"))
- kind = TLS_MODEL_INITIAL_EXEC;
- else if (!strcmp (TREE_STRING_POINTER (attr), "local-dynamic"))
- kind = optimize ? TLS_MODEL_LOCAL_DYNAMIC : TLS_MODEL_GLOBAL_DYNAMIC;
- else if (!strcmp (TREE_STRING_POINTER (attr), "global-dynamic"))
- kind = TLS_MODEL_GLOBAL_DYNAMIC;
- else
- gcc_unreachable ();
- return kind;
- }
-
is_local = targetm.binds_local_p (decl);
if (!flag_shlib)
{
else
kind = TLS_MODEL_INITIAL_EXEC;
}
+
/* Local dynamic is inefficient when we're not combining the
parts of the address. */
else if (optimize && is_local)
flags = SECTION_CODE;
else if (decl && decl_readonly_section_1 (decl, reloc, shlib))
flags = 0;
- else if (unlikely_text_section_name
- && strcmp (name, unlikely_text_section_name) == 0)
+ else if (current_function_decl
+ && cfun
+ && cfun->unlikely_text_section_name
+ && strcmp (name, cfun->unlikely_text_section_name) == 0)
flags = SECTION_CODE;
+ else if (!decl
+ && (!current_function_decl || !cfun)
+ && strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0)
+ flags = SECTION_CODE;
else
flags = SECTION_WRITE;
if (decl && DECL_ONE_ONLY (decl))
flags |= SECTION_LINKONCE;
- if (decl && TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
+ if (decl && TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
flags |= SECTION_TLS | SECTION_WRITE;
if (strcmp (name, ".bss") == 0
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));
}
data_section ();
}
-/* A helper function for default_elf_select_section and
- default_elf_unique_section. Categorizes the DECL. */
-
enum section_category
-{
- SECCAT_TEXT,
-
- SECCAT_RODATA,
- SECCAT_RODATA_MERGE_STR,
- SECCAT_RODATA_MERGE_STR_INIT,
- SECCAT_RODATA_MERGE_CONST,
- SECCAT_SRODATA,
-
- SECCAT_DATA,
-
- /* To optimize loading of shared programs, define following subsections
- of data section:
- _REL Contains data that has relocations, so they get grouped
- together and dynamic linker will visit fewer pages in memory.
- _RO Contains data that is otherwise read-only. This is useful
- with prelinking as most relocations won't be dynamically
- linked and thus stay read only.
- _LOCAL Marks data containing relocations only to local objects.
- These relocations will get fully resolved by prelinking. */
- SECCAT_DATA_REL,
- SECCAT_DATA_REL_LOCAL,
- SECCAT_DATA_REL_RO,
- SECCAT_DATA_REL_RO_LOCAL,
-
- SECCAT_SDATA,
- SECCAT_TDATA,
-
- SECCAT_BSS,
- SECCAT_SBSS,
- SECCAT_TBSS
-};
-
-static enum section_category
-categorize_decl_for_section (tree, int, int);
-
-static enum section_category
categorize_decl_for_section (tree decl, int reloc, int shlib)
{
enum section_category ret;
ret = SECCAT_RODATA;
/* There are no read-only thread-local sections. */
- if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
+ if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
{
/* Note that this would be *just* SECCAT_BSS, except that there's
no concept of a read-only thread-local-data section. */
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;
flags |= SYMBOL_FLAG_FUNCTION;
if (targetm.binds_local_p (decl))
flags |= SYMBOL_FLAG_LOCAL;
- if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
- flags |= decl_tls_model (decl) << SYMBOL_FLAG_TLS_SHIFT;
+ if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
+ flags |= DECL_TLS_MODEL (decl) << SYMBOL_FLAG_TLS_SHIFT;
else if (targetm.in_small_data_p (decl))
flags |= SYMBOL_FLAG_SMALL;
/* ??? Why is DECL_EXTERNAL ever set for non-PUBLIC names? Without
}
/* 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