diff options
Diffstat (limited to 'gcc/symtab.c')
-rw-r--r-- | gcc/symtab.c | 96 |
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; +} |