aboutsummaryrefslogtreecommitdiff
path: root/gcc/symtab.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/symtab.c')
-rw-r--r--gcc/symtab.c96
1 files changed, 96 insertions, 0 deletions
diff --git a/gcc/symtab.c b/gcc/symtab.c
index a46ebd4..3833734 100644
--- a/gcc/symtab.c
+++ b/gcc/symtab.c
@@ -1908,3 +1908,99 @@ symtab_node::address_matters_p ()
gcc_assert (!alias);
return call_for_symbol_and_aliases (address_matters_1, NULL, true);
}
+
+/* Return ture if symbol's alignment may be increased. */
+
+bool
+symtab_node::can_increase_alignment_p (void)
+{
+ symtab_node *target = ultimate_alias_target ();
+
+ /* For now support only variables. */
+ if (TREE_CODE (decl) != VAR_DECL)
+ return false;
+
+ /* With -fno-toplevel-reorder we may have already output the constant. */
+ if (TREE_ASM_WRITTEN (target->decl))
+ return false;
+
+ /* Constant pool entries may be shared. */
+ if (DECL_IN_CONSTANT_POOL (target->decl))
+ return false;
+
+ /* We cannot change alignment of symbols that may bind to symbols
+ in other translation unit that may contain a definition with lower
+ alignment. */
+ if (!decl_binds_to_current_def_p (decl))
+ return false;
+
+ /* When compiling partition, be sure the symbol is not output by other
+ partition. */
+ if (flag_ltrans
+ && (target->in_other_partition
+ || target->get_partitioning_class () == SYMBOL_DUPLICATE))
+ return false;
+
+ /* Do not override the alignment as specified by the ABI when the used
+ attribute is set. */
+ if (DECL_PRESERVE_P (decl) || DECL_PRESERVE_P (target->decl))
+ return false;
+
+ /* Do not override explicit alignment set by the user when an explicit
+ section name is also used. This is a common idiom used by many
+ software projects. */
+ if (DECL_SECTION_NAME (target->decl) != NULL && !target->implicit_section)
+ return false;
+
+ return true;
+}
+
+/* Worker for symtab_node::increase_alignment. */
+
+static bool
+increase_alignment_1 (symtab_node *n, void *v)
+{
+ unsigned int align = (size_t)v;
+ if (DECL_ALIGN (n->decl) < align
+ && n->can_increase_alignment_p ())
+ {
+ DECL_ALIGN (n->decl) = align;
+ DECL_USER_ALIGN (n->decl) = 1;
+ }
+ return false;
+}
+
+/* Increase alignment of THIS to ALIGN. */
+
+void
+symtab_node::increase_alignment (unsigned int align)
+{
+ gcc_assert (can_increase_alignment_p () && align < MAX_OFILE_ALIGNMENT);
+ ultimate_alias_target()->call_for_symbol_and_aliases (increase_alignment_1,
+ (void *)(size_t) align,
+ true);
+ gcc_assert (DECL_ALIGN (decl) >= align);
+}
+
+/* Helper for symtab_node::definition_alignment. */
+
+static bool
+get_alignment_1 (symtab_node *n, void *v)
+{
+ *((unsigned int *)v) = MAX (*((unsigned int *)v), DECL_ALIGN (n->decl));
+ return false;
+}
+
+/* Return desired alignment of the definition. This is NOT alignment useful
+ to access THIS, because THIS may be interposable and DECL_ALIGN should
+ be used instead. It however must be guaranteed when output definition
+ of THIS. */
+
+unsigned int
+symtab_node::definition_alignment ()
+{
+ unsigned int align = 0;
+ gcc_assert (!alias);
+ call_for_symbol_and_aliases (get_alignment_1, &align, true);
+ return align;
+}