summaryrefslogtreecommitdiff
path: root/gcc/varasm.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/varasm.c')
-rw-r--r--gcc/varasm.c262
1 files changed, 166 insertions, 96 deletions
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 81552fe6fed..b4048b5b4dd 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -307,19 +307,22 @@ get_section (const char *name, unsigned int flags, tree decl)
return sect;
}
/* Sanity check user variables for flag changes. */
- if (decl == 0)
- decl = sect->named.decl;
- gcc_assert (decl);
- if (sect->named.decl == NULL)
- error ("%+D causes a section type conflict", decl);
- else
+ if (sect->named.decl != NULL
+ && DECL_P (sect->named.decl)
+ && decl != sect->named.decl)
{
- error ("%+D causes a section type conflict with %D",
- decl, sect->named.decl);
- if (decl != sect->named.decl)
- inform (DECL_SOURCE_LOCATION (sect->named.decl),
- "%qD was declared here", sect->named.decl);
+ if (decl != NULL && DECL_P (decl))
+ error ("%+D causes a section type conflict with %D",
+ decl, sect->named.decl);
+ else
+ error ("section type conflict with %D", sect->named.decl);
+ inform (DECL_SOURCE_LOCATION (sect->named.decl),
+ "%qD was declared here", sect->named.decl);
}
+ else if (decl != NULL && DECL_P (decl))
+ error ("%+D causes a section type conflict", decl);
+ else
+ error ("section type conflict");
/* Make sure we don't error about one section multiple times. */
sect->common.flags |= SECTION_OVERRIDE;
}
@@ -409,9 +412,6 @@ get_named_section (tree decl, const char *name, int reloc)
}
flags = targetm.section_type_flags (decl, name, reloc);
-
- if (decl && !DECL_P (decl))
- decl = NULL_TREE;
return get_section (name, flags, decl);
}
@@ -966,13 +966,80 @@ align_variable (tree decl, bool dont_output_data)
align = MAX_OFILE_ALIGNMENT;
}
- /* On some machines, it is good to increase alignment sometimes. */
if (! DECL_USER_ALIGN (decl))
{
+#ifdef DATA_ABI_ALIGNMENT
+ unsigned int data_abi_align
+ = DATA_ABI_ALIGNMENT (TREE_TYPE (decl), align);
+ /* For backwards compatibility, don't assume the ABI alignment for
+ TLS variables. */
+ if (! DECL_THREAD_LOCAL_P (decl) || data_abi_align <= BITS_PER_WORD)
+ align = data_abi_align;
+#endif
+
+ /* On some machines, it is good to increase alignment sometimes.
+ But as DECL_ALIGN is used both for actually emitting the variable
+ and for code accessing the variable as guaranteed alignment, we
+ can only increase the alignment if it is a performance optimization
+ if the references to it must bind to the current definition. */
+ if (decl_binds_to_current_def_p (decl))
+ {
+#ifdef DATA_ALIGNMENT
+ unsigned int data_align = DATA_ALIGNMENT (TREE_TYPE (decl), align);
+ /* Don't increase alignment too much for TLS variables - TLS space
+ is too precious. */
+ if (! DECL_THREAD_LOCAL_P (decl) || data_align <= BITS_PER_WORD)
+ align = data_align;
+#endif
+#ifdef CONSTANT_ALIGNMENT
+ if (DECL_INITIAL (decl) != 0
+ && DECL_INITIAL (decl) != error_mark_node)
+ {
+ unsigned int const_align
+ = CONSTANT_ALIGNMENT (DECL_INITIAL (decl), align);
+ /* Don't increase alignment too much for TLS variables - TLS
+ space is too precious. */
+ if (! DECL_THREAD_LOCAL_P (decl) || const_align <= BITS_PER_WORD)
+ align = const_align;
+ }
+#endif
+ }
+ }
+
+ /* Reset the alignment in case we have made it tighter, so we can benefit
+ from it in get_pointer_alignment. */
+ DECL_ALIGN (decl) = align;
+}
+
+/* Return DECL_ALIGN (decl), possibly increased for optimization purposes
+ beyond what align_variable returned. */
+
+static unsigned int
+get_variable_align (tree decl)
+{
+ unsigned int align = DECL_ALIGN (decl);
+
+ /* For user aligned vars or static vars align_variable already did
+ everything. */
+ if (DECL_USER_ALIGN (decl) || !TREE_PUBLIC (decl))
+ return align;
+
+#ifdef DATA_ABI_ALIGNMENT
+ if (DECL_THREAD_LOCAL_P (decl))
+ align = DATA_ABI_ALIGNMENT (TREE_TYPE (decl), align);
+#endif
+
+ /* For decls that bind to the current definition, align_variable
+ did also everything, except for not assuming ABI required alignment
+ of TLS variables. For other vars, increase the alignment here
+ as an optimization. */
+ if (!decl_binds_to_current_def_p (decl))
+ {
+ /* On some machines, it is good to increase alignment sometimes. */
#ifdef DATA_ALIGNMENT
unsigned int data_align = DATA_ALIGNMENT (TREE_TYPE (decl), align);
/* Don't increase alignment too much for TLS variables - TLS space
- is too precious. */
+ is too precious. */
if (! DECL_THREAD_LOCAL_P (decl) || data_align <= BITS_PER_WORD)
align = data_align;
#endif
@@ -989,9 +1056,7 @@ align_variable (tree decl, bool dont_output_data)
#endif
}
- /* Reset the alignment in case we have made it tighter, so we can benefit
- from it in get_pointer_alignment. */
- DECL_ALIGN (decl) = align;
+ return align;
}
/* Return the section into which the given VAR_DECL or CONST_DECL
@@ -1043,7 +1108,8 @@ get_variable_section (tree decl, bool prefer_noswitch_p)
return bss_noswitch_section;
}
- return targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
+ return targetm.asm_out.select_section (decl, reloc,
+ get_variable_align (decl));
}
/* Return the block into which object_block DECL should be placed. */
@@ -1780,7 +1846,8 @@ emit_bss (tree decl ATTRIBUTE_UNUSED,
unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
{
#if defined ASM_OUTPUT_ALIGNED_BSS
- ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size, DECL_ALIGN (decl));
+ ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size,
+ get_variable_align (decl));
return true;
#endif
}
@@ -1796,10 +1863,11 @@ emit_common (tree decl ATTRIBUTE_UNUSED,
{
#if defined ASM_OUTPUT_ALIGNED_DECL_COMMON
ASM_OUTPUT_ALIGNED_DECL_COMMON (asm_out_file, decl, name,
- size, DECL_ALIGN (decl));
+ size, get_variable_align (decl));
return true;
#elif defined ASM_OUTPUT_ALIGNED_COMMON
- ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size, DECL_ALIGN (decl));
+ ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size,
+ get_variable_align (decl));
return true;
#else
ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded);
@@ -1828,7 +1896,8 @@ emit_tls_common (tree decl ATTRIBUTE_UNUSED,
NAME is the name of DECL's SYMBOL_REF. */
static void
-assemble_noswitch_variable (tree decl, const char *name, section *sect)
+assemble_noswitch_variable (tree decl, const char *name, section *sect,
+ unsigned int align)
{
unsigned HOST_WIDE_INT size, rounded;
@@ -1850,7 +1919,7 @@ assemble_noswitch_variable (tree decl, const char *name, section *sect)
* (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
if (!sect->noswitch.callback (decl, name, size, rounded)
- && (unsigned HOST_WIDE_INT) DECL_ALIGN_UNIT (decl) > rounded)
+ && (unsigned HOST_WIDE_INT) (align / BITS_PER_UNIT) > rounded)
warning (0, "requested alignment for %q+D is greater than "
"implemented alignment of %wu", decl, rounded);
}
@@ -1880,7 +1949,7 @@ assemble_variable_contents (tree decl, const char *name,
/* Output the actual data. */
output_constant (DECL_INITIAL (decl),
tree_low_cst (DECL_SIZE_UNIT (decl), 1),
- DECL_ALIGN (decl));
+ get_variable_align (decl));
else
/* Leave space for it. */
assemble_zeros (tree_low_cst (DECL_SIZE_UNIT (decl), 1));
@@ -1904,6 +1973,7 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
const char *name;
rtx decl_rtl, symbol;
section *sect;
+ unsigned int align;
bool asan_protected = false;
/* This function is supposed to handle VARIABLES. Ensure we have one. */
@@ -2003,6 +2073,8 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
set_mem_align (decl_rtl, DECL_ALIGN (decl));
+ align = get_variable_align (decl);
+
if (TREE_PUBLIC (decl))
maybe_assemble_visibility (decl);
@@ -2032,9 +2104,19 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
place_block_symbol (symbol);
}
else if (SECTION_STYLE (sect) == SECTION_NOSWITCH)
- assemble_noswitch_variable (decl, name, sect);
+ assemble_noswitch_variable (decl, name, sect, align);
else
{
+ /* The following bit of code ensures that vtable_map
+ variables are not only in the comdat section, but that
+ each variable has its own unique comdat name. If this
+ code is removed, the variables end up in the same section
+ with a single comdat name.
+
+ FIXME: resolve_unique_section needs to deal better with
+ decls with both DECL_SECTION_NAME and DECL_ONE_ONLY. Once
+ that is fixed, this if-else statement can be replaced with
+ a single call to "switch_to_section (sect)". */
if (sect->named.name
&& (strcmp (sect->named.name, ".vtable_map_vars") == 0))
{
@@ -2049,9 +2131,9 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
#endif
}
else
- switch_to_section (sect);
- if (DECL_ALIGN (decl) > BITS_PER_UNIT)
- ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl)));
+ switch_to_section (sect);
+ if (align > BITS_PER_UNIT)
+ ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
assemble_variable_contents (decl, name, dont_output_data);
if (asan_protected)
{
@@ -4501,7 +4583,7 @@ static unsigned HOST_WIDE_INT
output_constructor (tree, unsigned HOST_WIDE_INT, unsigned int,
oc_outer_state *);
-/* Output assembler code for constant EXP to FILE, with no label.
+/* Output assembler code for constant EXP, with no label.
This includes the pseudo-op such as ".int" or ".byte", and a newline.
Assumes output_addressed_constants has been done on EXP already.
@@ -4643,28 +4725,21 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
switch (TREE_CODE (exp))
{
case CONSTRUCTOR:
- output_constructor (exp, size, align, NULL);
+ output_constructor (exp, size, align, NULL);
return;
case STRING_CST:
- thissize = MIN ((unsigned HOST_WIDE_INT)TREE_STRING_LENGTH (exp),
- size);
+ thissize
+ = MIN ((unsigned HOST_WIDE_INT)TREE_STRING_LENGTH (exp), size);
assemble_string (TREE_STRING_POINTER (exp), thissize);
break;
-
case VECTOR_CST:
{
- int elt_size;
- unsigned int i, 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);
-
+ enum machine_mode inner = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
+ unsigned int nalign = MIN (align, GET_MODE_ALIGNMENT (inner));
+ int elt_size = GET_MODE_SIZE (inner);
output_constant (VECTOR_CST_ELT (exp, 0), elt_size, align);
thissize = elt_size;
- for (i = 1; i < VECTOR_CST_NELTS (exp); ++i)
+ for (unsigned int i = 1; i < VECTOR_CST_NELTS (exp); i++)
{
output_constant (VECTOR_CST_ELT (exp, i), elt_size, nalign);
thissize += elt_size;
@@ -4744,25 +4819,22 @@ typedef struct {
/* Received arguments. */
tree exp; /* Constructor expression. */
+ tree type; /* Type of constructor expression. */
unsigned HOST_WIDE_INT size; /* # bytes to output - pad if necessary. */
unsigned int align; /* Known initial alignment. */
-
- /* Constructor expression data. */
- tree type; /* Expression type. */
- tree field; /* Current field decl in a record. */
- tree min_index; /* Lower bound if specified for an array. */
+ tree min_index; /* Lower bound if specified for an array. */
/* Output processing state. */
HOST_WIDE_INT total_bytes; /* # bytes output so far / current position. */
- bool byte_buffer_in_use; /* Whether byte ... */
- int byte; /* ... contains part of a bitfield byte yet to
- be output. */
-
+ int byte; /* Part of a bitfield byte yet to be output. */
int last_relative_index; /* Implicit or explicit index of the last
array element output within a bitfield. */
+ bool byte_buffer_in_use; /* Whether BYTE is in use. */
+
/* Current element. */
- tree val; /* Current element value. */
- tree index; /* Current element index. */
+ tree field; /* Current field decl in a record. */
+ tree val; /* Current element value. */
+ tree index; /* Current element index. */
} oc_local_state;
@@ -4884,11 +4956,12 @@ output_constructor_regular_field (oc_local_state *local)
local->total_bytes += fieldsize;
}
-/* Helper for output_constructor. From the current LOCAL and OUTER states,
- output an element that is a true bitfield or part of an outer one. */
+/* Helper for output_constructor. From the LOCAL state, output an element
+ that is a true bitfield or part of an outer one. BIT_OFFSET is the offset
+ from the start of a possibly ongoing outer byte buffer. */
static void
-output_constructor_bitfield (oc_local_state *local, oc_outer_state *outer)
+output_constructor_bitfield (oc_local_state *local, unsigned int bit_offset)
{
/* Bit size of this element. */
HOST_WIDE_INT ebitsize
@@ -4915,7 +4988,7 @@ output_constructor_bitfield (oc_local_state *local, oc_outer_state *outer)
/* Bit position of this element from the start of a possibly ongoing
outer byte buffer. */
HOST_WIDE_INT byte_relative_ebitpos
- = ((outer ? outer->bit_offset : 0) + constructor_relative_ebitpos);
+ = bit_offset + constructor_relative_ebitpos;
/* From the start of a possibly ongoing outer byte buffer, offsets to
the first bit of this element and to the first bit past the end of
@@ -4939,8 +5012,7 @@ output_constructor_bitfield (oc_local_state *local, oc_outer_state *outer)
return;
}
- /* If this field does not start in this (or, next) byte,
- skip some bytes. */
+ /* If this field does not start in this (or next) byte, skip some bytes. */
if (next_offset / BITS_PER_UNIT != local->total_bytes)
{
/* Output remnant of any bit field in previous bytes. */
@@ -4972,13 +5044,12 @@ output_constructor_bitfield (oc_local_state *local, oc_outer_state *outer)
pending data, then retrieve the new pending data afterwards. */
if (TREE_CODE (local->val) == CONSTRUCTOR)
{
- oc_outer_state output_state;
-
- output_state.bit_offset = next_offset % BITS_PER_UNIT;
- output_state.byte = local->byte;
+ oc_outer_state temp_state;
+ temp_state.bit_offset = next_offset % BITS_PER_UNIT;
+ temp_state.byte = local->byte;
local->total_bytes
- += output_constructor (local->val, 0, 0, &output_state);
- local->byte = output_state.byte;
+ += output_constructor (local->val, 0, 0, &temp_state);
+ local->byte = temp_state.byte;
return;
}
@@ -4993,8 +5064,7 @@ output_constructor_bitfield (oc_local_state *local, oc_outer_state *outer)
HOST_WIDE_INT next_byte = next_offset / BITS_PER_UNIT;
HOST_WIDE_INT next_bit = next_offset % BITS_PER_UNIT;
- /* Advance from byte to byte
- within this element when necessary. */
+ /* Advance from byte to byte within this element when necessary. */
while (next_byte != local->total_bytes)
{
assemble_integer (GEN_INT (local->byte), 1, BITS_PER_UNIT, 1);
@@ -5002,10 +5072,8 @@ output_constructor_bitfield (oc_local_state *local, oc_outer_state *outer)
local->byte = 0;
}
- /* Number of bits we can process at once
- (all part of the same byte). */
- this_time = MIN (end_offset - next_offset,
- BITS_PER_UNIT - next_bit);
+ /* Number of bits we can process at once (all part of the same byte). */
+ this_time = MIN (end_offset - next_offset, BITS_PER_UNIT - next_bit);
if (BYTES_BIG_ENDIAN)
{
/* On big-endian machine, take the most significant bits
@@ -5084,7 +5152,7 @@ output_constructor_bitfield (oc_local_state *local, oc_outer_state *outer)
static unsigned HOST_WIDE_INT
output_constructor (tree exp, unsigned HOST_WIDE_INT size,
- unsigned int align, oc_outer_state * outer)
+ unsigned int align, oc_outer_state *outer)
{
unsigned HOST_WIDE_INT cnt;
constructor_elt *ce;
@@ -5093,22 +5161,20 @@ output_constructor (tree exp, unsigned HOST_WIDE_INT size,
/* Setup our local state to communicate with helpers. */
local.exp = exp;
+ local.type = TREE_TYPE (exp);
local.size = size;
local.align = align;
+ if (TREE_CODE (local.type) == ARRAY_TYPE && TYPE_DOMAIN (local.type))
+ local.min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (local.type));
+ else
+ local.min_index = NULL_TREE;
local.total_bytes = 0;
local.byte_buffer_in_use = outer != NULL;
local.byte = outer ? outer->byte : 0;
- local.type = TREE_TYPE (exp);
-
local.last_relative_index = -1;
- local.min_index = NULL_TREE;
- if (TREE_CODE (local.type) == ARRAY_TYPE
- && TYPE_DOMAIN (local.type) != NULL_TREE)
- local.min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (local.type));
-
gcc_assert (HOST_BITS_PER_WIDE_INT >= BITS_PER_UNIT);
/* As CE goes through the elements of the constant, FIELD goes through the
@@ -5120,9 +5186,10 @@ output_constructor (tree exp, unsigned HOST_WIDE_INT size,
(even if the initializer in a source program incorrectly contains
more one). */
- local.field = NULL_TREE;
if (TREE_CODE (local.type) == RECORD_TYPE)
local.field = TYPE_FIELDS (local.type);
+ else
+ local.field = NULL_TREE;
for (cnt = 0;
vec_safe_iterate (CONSTRUCTOR_ELTS (exp), cnt, &ce);
@@ -5175,7 +5242,7 @@ output_constructor (tree exp, unsigned HOST_WIDE_INT size,
build_nonstandard_integer_type
(TYPE_PRECISION (TREE_TYPE (local.val)), 0),
local.val);
- output_constructor_bitfield (&local, outer);
+ output_constructor_bitfield (&local, outer ? outer->bit_offset : 0);
}
}
@@ -5591,13 +5658,6 @@ assemble_alias (tree decl, tree target)
if (alias == target)
error ("weakref %q+D ultimately targets itself", decl);
- else
- {
-#ifndef ASM_OUTPUT_WEAKREF
- IDENTIFIER_TRANSPARENT_ALIAS (alias) = 1;
- TREE_CHAIN (alias) = target;
-#endif
- }
if (TREE_PUBLIC (decl))
error ("weakref %q+D must have static linkage", decl);
}
@@ -6764,10 +6824,10 @@ bool
decl_binds_to_current_def_p (tree decl)
{
gcc_assert (DECL_P (decl));
- if (!TREE_PUBLIC (decl))
- return true;
if (!targetm.binds_local_p (decl))
return false;
+ if (!TREE_PUBLIC (decl))
+ return true;
/* When resolution is available, just use it. */
if (TREE_CODE (decl) == VAR_DECL
&& (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
@@ -6785,10 +6845,20 @@ decl_binds_to_current_def_p (tree decl)
return resolution_to_local_definition_p (node->symbol.resolution);
}
/* Otherwise we have to assume the worst for DECL_WEAK (hidden weaks
- binds locally but still can be overwritten).
+ binds locally but still can be overwritten), DECL_COMMON (can be merged
+ with a non-common definition somewhere in the same module) or
+ DECL_EXTERNAL.
This rely on fact that binds_local_p behave as decl_replaceable_p
for all other declaration types. */
- return !DECL_WEAK (decl);
+ if (DECL_WEAK (decl))
+ return false;
+ if (DECL_COMMON (decl)
+ && (DECL_INITIAL (decl) == NULL
+ || DECL_INITIAL (decl) == error_mark_node))
+ return false;
+ if (DECL_EXTERNAL (decl))
+ return false;
+ return true;
}
/* A replaceable function or variable is one which may be replaced
@@ -7014,7 +7084,7 @@ place_block_symbol (rtx symbol)
else
{
decl = SYMBOL_REF_DECL (symbol);
- alignment = DECL_ALIGN (decl);
+ alignment = get_variable_align (decl);
size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
if (flag_asan && asan_protect_global (decl))
{