This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Allow DECL_ALIGN of FUNCTION_DECLs
- From: gkeating at apple dot com (Geoffrey Keating)
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 9 Jul 2007 15:50:51 -0700 (PDT)
- Subject: Allow DECL_ALIGN of FUNCTION_DECLs
This patch does two things:
- it fixes PR 32617, by giving FUNCTION_DECLs a DECL_ALIGN. I think
this is much cleaner than the previous state.
- it allows the 'aligned' attribute to be used on functions. (I
actually have a customer request for this.)
I haven't changed tree.h to check that DECL_ALIGN is now used only
FUNCTION_DECLs, VAR_DECLs, and FIELD_DECLs, as I think this patch is
already quite complicated enough, but this would be a good thing and
if I remember to do it I'll do it next.
I removed the 'u1.i' field, because I couldn't find any users of it.
If there are external front-ends using it they should use
DECL_LANG_SPECIFIC instead.
The effect of the tree.h changes is that most DECLs become smaller (on
most configurations) or at worst stay the same size, and that
FUNCTION_DECLs stay the same size on most configurations or at worst
grow by 4 bytes. (The win is because the 'u1.i' field caused the
alignment stuff to be padded to 64 bits even though it only needs 32
bits.) Anyone needing a few bits might consider making the
'function_code' field a bitfield, we'll never have 2^32 builtins (I
hope).
This is being bootstrapped & tested on powerpc-darwin8, I'll commit if
testing is successful.
--
- Geoffrey Keating <geoffk@apple.com>
===File ~/patches/gcc-functionalign.patch===================
2007-07-09 Geoffrey Keating <geoffk@apple.com>
PR 32617
* c-common.c (c_alignof_expr): Look at DECL_ALIGN of
FUNCTION_DECLs.
(handle_aligned_attribute): Allow use on FUNCTION_DECLs.
* varasm.c (assemble_start_function): Honor DECL_ALIGN
for FUNCTION_DECLs. Don't use align_functions_log if
DECL_USER_ALIGN.
* print-tree.c (print_node): Print DECL_ALIGN and DECL_USER_ALIGN
even for FUNCTION_DECLs.
* c-decl.c (merge_decls): Propagate DECL_ALIGN even for
FUNCTION_DECLs.
* tree.h (DECL_ALIGN): Update for new location of 'align'.
(DECL_FUNCTION_CODE): Update for new location and name of
'function_code'.
(DECL_OFFSET_ALIGN): Update for new location of 'off_align'.
(struct tree_decl_common): Move 'align' and 'off_align' out
of union, ensure they're still on a 32-bit boundary. Remove
other fields in union 'u1'.
(struct tree_function_decl): Add field 'function_code' replacing
'u1.f' in tree_decl_common.
* tree.c (build_decl_stat): Set initial value of DECL_ALIGN.
* doc/extend.texi (Function Attributes): Add 'aligned' attribute.
(Variable Attributes): Cross-reference 'aligned' attribute
to Function Attributes.
* flags.h (force_align_functions_log): Delete.
* toplev.c (force_align_functions_log): Delete.
Index: gcc/testsuite/ChangeLog
2007-07-09 Geoffrey Keating <geoffk@apple.com>
PR 32617
* gcc.c-torture/execute/align-3.c: New.
Index: gcc/java/ChangeLog
2007-07-09 Geoffrey Keating <geoffk@apple.com>
PR 32617
* lang.c (java_init): Remove setting of force_align_functions_log.
* class.c (add_method_1): Set DECL_ALIGN of non-static method
to cope with ptrmemfunc_vbit_in_pfn.
Index: gcc/cp/ChangeLog
2007-07-09 Geoffrey Keating <geoffk@apple.com>
PR 32617
* decl.c (cxx_init_decl_processing): Don't set
force_align_functions_log.
(grokfndecl): Honour ptrmemfunc_vbit_in_pfn.
* typeck.c (cxx_alignof_expr): When alignof is used on a plain
FUNCTION_DECL, return its alignment.
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi (revision 126496)
+++ gcc/doc/extend.texi (working copy)
@@ -1605,18 +1605,19 @@
attributes when making a declaration. This keyword is followed by an
attribute specification inside double parentheses. The following
attributes are currently defined for functions on all targets:
-@code{alloc_size}, @code{noreturn}, @code{returns_twice}, @code{noinline},
-@code{always_inline}, @code{flatten}, @code{pure}, @code{const},
-@code{nothrow}, @code{sentinel}, @code{format}, @code{format_arg},
+@code{aligned}, @code{alloc_size}, @code{noreturn},
+@code{returns_twice}, @code{noinline}, @code{always_inline},
+@code{flatten}, @code{pure}, @code{const}, @code{nothrow},
+@code{sentinel}, @code{format}, @code{format_arg},
@code{no_instrument_function}, @code{section}, @code{constructor},
@code{destructor}, @code{used}, @code{unused}, @code{deprecated},
@code{weak}, @code{malloc}, @code{alias}, @code{warn_unused_result},
@code{nonnull}, @code{gnu_inline} and @code{externally_visible},
@code{hot}, @code{cold}.
-Several other attributes are defined for functions on particular target
-systems. Other attributes, including @code{section} are supported for
-variables declarations (@pxref{Variable Attributes}) and for types (@pxref{Type
-Attributes}).
+Several other attributes are defined for functions on particular
+target systems. Other attributes, including @code{section} are
+supported for variables declarations (@pxref{Variable Attributes}) and
+for types (@pxref{Type Attributes}).
You may also specify attributes with @samp{__} preceding and following
each keyword. This allows you to use them in header files without
@@ -1645,6 +1646,27 @@
Not all target machines support this attribute.
+@item aligned (@var{alignment})
+@cindex @code{aligned} attribute
+This attribute specifies a minimum alignment for the function,
+measured in bytes.
+
+You cannot use this attribute to decrease the alignment of a function,
+only to increase it. However, when you explicitly specify a function
+alignment this will override the effect of the
+@option{-falign-functions} (@pxref{Optimize Options}) option for this
+function.
+
+Note that the effectiveness of @code{aligned} attributes may be
+limited by inherent limitations in your linker. On many systems, the
+linker is only able to arrange for functions to be aligned up to a
+certain maximum alignment. (For some linkers, the maximum supported
+alignment may be very very small.) See your linker documentation for
+further information.
+
+The @code{aligned} attribute can also be used for variables and fields
+(@pxref{Variable Attributes}.)
+
@item alloc_size
@cindex @code{alloc_size} attribute
The @code{alloc_size} attribute is used to tell the compiler that the
@@ -3202,6 +3224,9 @@
in an @code{__attribute__} will still only provide you with 8 byte
alignment. See your linker documentation for further information.
+The @code{aligned} attribute can also be used for functions
+(@pxref{Function Attributes}.)
+
@item cleanup (@var{cleanup_function})
@cindex @code{cleanup} attribute
The @code{cleanup} attribute runs a function when the variable goes
Index: gcc/flags.h
===================================================================
--- gcc/flags.h (revision 126496)
+++ gcc/flags.h (working copy)
@@ -250,10 +250,6 @@
extern int align_labels_max_skip;
extern int align_functions_log;
-/* Like align_functions_log above, but used by front-ends to force the
- minimum function alignment. Zero means no alignment is forced. */
-extern int force_align_functions_log;
-
/* Nonzero if we dump in VCG format, not plain text. */
extern int dump_for_graph;
Index: gcc/java/class.c
===================================================================
--- gcc/java/class.c (revision 126496)
+++ gcc/java/class.c (working copy)
@@ -725,6 +725,14 @@
TREE_CHAIN (fndecl) = TYPE_METHODS (this_class);
TYPE_METHODS (this_class) = fndecl;
+ /* If pointers to member functions use the least significant bit to
+ indicate whether a function is virtual, ensure a pointer
+ to this function will have that bit clear. */
+ if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn
+ && !(access_flags & ACC_STATIC)
+ && DECL_ALIGN (fndecl) < 2 * BITS_PER_UNIT)
+ DECL_ALIGN (fndecl) = 2 * BITS_PER_UNIT;
+
/* Notice that this is a finalizer and update the class type
accordingly. This is used to optimize instance allocation. */
if (name == finalize_identifier_node
Index: gcc/java/lang.c
===================================================================
--- gcc/java/lang.c (revision 126496)
+++ gcc/java/lang.c (working copy)
@@ -355,13 +355,6 @@
if (!flag_indirect_dispatch)
flag_indirect_classes = false;
- /* Force minimum function alignment if g++ uses the least significant
- bit of function pointers to store the virtual bit. This is required
- to keep vtables compatible. */
- if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn
- && force_align_functions_log < 1)
- force_align_functions_log = 1;
-
jcf_path_seal (v_flag);
java_init_decl_processing ();
Index: gcc/tree.c
===================================================================
--- gcc/tree.c (revision 126496)
+++ gcc/tree.c (working copy)
@@ -3312,7 +3312,10 @@
if (code == VAR_DECL || code == PARM_DECL || code == RESULT_DECL)
layout_decl (t, 0);
else if (code == FUNCTION_DECL)
- DECL_MODE (t) = FUNCTION_MODE;
+ {
+ DECL_MODE (t) = FUNCTION_MODE;
+ DECL_ALIGN (t) = FUNCTION_BOUNDARY;
+ }
return t;
}
Index: gcc/tree.h
===================================================================
--- gcc/tree.h (revision 126496)
+++ gcc/tree.h (working copy)
@@ -2586,7 +2586,7 @@
/* Likewise for the size in bytes. */
#define DECL_SIZE_UNIT(NODE) (DECL_COMMON_CHECK (NODE)->decl_common.size_unit)
/* Holds the alignment required for the datum, in bits. */
-#define DECL_ALIGN(NODE) (DECL_COMMON_CHECK (NODE)->decl_common.u1.a.align)
+#define DECL_ALIGN(NODE) (DECL_COMMON_CHECK (NODE)->decl_common.align)
/* The alignment of NODE, in bytes. */
#define DECL_ALIGN_UNIT(NODE) (DECL_ALIGN (NODE) / BITS_PER_UNIT)
/* For FIELD_DECLs, off_align holds the number of low-order bits of
@@ -2603,7 +2603,8 @@
operation it is. Note, however, that this field is overloaded, with
DECL_BUILT_IN_CLASS as the discriminant, so the latter must always be
checked before any access to the former. */
-#define DECL_FUNCTION_CODE(NODE) (FUNCTION_DECL_CHECK (NODE)->decl_common.u1.f)
+#define DECL_FUNCTION_CODE(NODE) \
+ (FUNCTION_DECL_CHECK (NODE)->function_decl.function_code)
#define DECL_DEBUG_EXPR_IS_FROM(NODE) \
(DECL_COMMON_CHECK (NODE)->decl_common.debug_expr_is_from)
@@ -2735,21 +2736,12 @@
unsigned gimple_reg_flag : 1;
/* In a DECL with pointer type, set if no TBAA should be done. */
unsigned no_tbaa_flag : 1;
+ /* Padding so that 'align' can be on a 32-bit boundary. */
+ unsigned decl_common_unused : 2;
- union tree_decl_u1 {
- /* In a FUNCTION_DECL for which DECL_BUILT_IN holds, this is
- DECL_FUNCTION_CODE. */
- enum built_in_function f;
- /* In a FUNCTION_DECL for which DECL_BUILT_IN does not hold, this
- is used by language-dependent code. */
- HOST_WIDE_INT i;
- /* DECL_ALIGN and DECL_OFFSET_ALIGN. (These are not used for
- FUNCTION_DECLs). */
- struct tree_decl_u1_a {
- unsigned int align : 24;
- unsigned int off_align : 8;
- } a;
- } GTY ((skip)) u1;
+ unsigned int align : 24;
+ /* DECL_OFFSET_ALIGN, used only for FIELD_DECLs. */
+ unsigned int off_align : 8;
tree size_unit;
tree initial;
@@ -2834,11 +2826,11 @@
DECL_OFFSET_ALIGN thus returns the alignment that DECL_FIELD_OFFSET
has. */
#define DECL_OFFSET_ALIGN(NODE) \
- (((unsigned HOST_WIDE_INT)1) << FIELD_DECL_CHECK (NODE)->decl_common.u1.a.off_align)
+ (((unsigned HOST_WIDE_INT)1) << FIELD_DECL_CHECK (NODE)->decl_common.off_align)
/* Specify that DECL_ALIGN(NODE) is a multiple of X. */
#define SET_DECL_OFFSET_ALIGN(NODE, X) \
- (FIELD_DECL_CHECK (NODE)->decl_common.u1.a.off_align = exact_log2 ((X) & -(X)))
+ (FIELD_DECL_CHECK (NODE)->decl_common.off_align = exact_log2 ((X) & -(X)))
/* 1 if the alignment for this type was requested by "aligned" attribute,
0 if it is the default for this type. */
@@ -3277,6 +3269,10 @@
{
struct tree_decl_non_common common;
+ /* In a FUNCTION_DECL for which DECL_BUILT_IN holds, this is
+ DECL_FUNCTION_CODE. Otherwise unused. */
+ enum built_in_function function_code;
+
unsigned static_ctor_flag : 1;
unsigned static_dtor_flag : 1;
unsigned uninlinable : 1;
Index: gcc/toplev.c
===================================================================
--- gcc/toplev.c (revision 126496)
+++ gcc/toplev.c (working copy)
@@ -357,10 +357,35 @@
int align_labels_max_skip;
int align_functions_log;
-/* Like align_functions_log above, but used by front-ends to force the
- minimum function alignment. Zero means no alignment is forced. */
-int force_align_functions_log;
-
typedef struct
{
const char *const string;
Index: gcc/testsuite/gcc.c-torture/execute/align-3.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/align-3.c (revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/align-3.c (revision 0)
@@ -0,0 +1,14 @@
+void func(void) __attribute__((aligned(256)));
+
+void func(void)
+{
+}
+
+int main()
+{
+ if (((long)func & 0xFF) != 0)
+ abort ();
+ if (__alignof__(func) != 256)
+ abort ();
+ return 0;
+}
Index: gcc/cp/typeck.c
===================================================================
--- gcc/cp/typeck.c (revision 126496)
+++ gcc/cp/typeck.c (working copy)
@@ -1361,7 +1361,10 @@
{
pedwarn ("ISO C++ forbids applying %<__alignof%> to an expression of "
"function type");
- t = size_one_node;
+ if (TREE_CODE (e) == FUNCTION_DECL)
+ t = size_int (DECL_ALIGN_UNIT (e));
+ else
+ t = size_one_node;
}
else if (type_unknown_p (e))
{
Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c (revision 126496)
+++ gcc/cp/decl.c (working copy)
@@ -3182,12 +3182,6 @@
if (flag_visibility_ms_compat)
default_visibility = VISIBILITY_HIDDEN;
- /* Force minimum function alignment if using the least significant
- bit of function pointers to store the virtual bit. */
- if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn
- && force_align_functions_log < 1)
- force_align_functions_log = 1;
-
/* Initially, C. */
current_lang_name = lang_name_c;
@@ -6146,6 +6140,14 @@
break;
}
+ /* If pointers to member functions use the least significant bit to
+ indicate whether a function is virtual, ensure a pointer
+ to this function will have that bit clear. */
+ if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn
+ && TREE_CODE (type) == METHOD_TYPE
+ && DECL_ALIGN (decl) < 2 * BITS_PER_UNIT)
+ DECL_ALIGN (decl) = 2 * BITS_PER_UNIT;
+
if (friendp
&& TREE_CODE (orig_declarator) == TEMPLATE_ID_EXPR)
{
Index: gcc/c-decl.c
===================================================================
--- gcc/c-decl.c (revision 126496)
+++ gcc/c-decl.c (working copy)
@@ -1664,12 +1664,11 @@
DECL_SIZE (newdecl) = DECL_SIZE (olddecl);
DECL_SIZE_UNIT (newdecl) = DECL_SIZE_UNIT (olddecl);
DECL_MODE (newdecl) = DECL_MODE (olddecl);
- if (TREE_CODE (olddecl) != FUNCTION_DECL)
- if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl))
- {
- DECL_ALIGN (newdecl) = DECL_ALIGN (olddecl);
- DECL_USER_ALIGN (newdecl) |= DECL_ALIGN (olddecl);
- }
+ if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl))
+ {
+ DECL_ALIGN (newdecl) = DECL_ALIGN (olddecl);
+ DECL_USER_ALIGN (newdecl) |= DECL_ALIGN (olddecl);
+ }
}
Index: gcc/print-tree.c
===================================================================
--- gcc/print-tree.c (revision 126496)
+++ gcc/print-tree.c (working copy)
@@ -441,18 +441,16 @@
|| DECL_INLINE (node) || DECL_BUILT_IN (node))
indent_to (file, indent + 3);
- if (TREE_CODE (node) != FUNCTION_DECL)
+ if (DECL_USER_ALIGN (node))
+ fprintf (file, " user");
+
+ fprintf (file, " align %d", DECL_ALIGN (node));
+ if (TREE_CODE (node) == FIELD_DECL)
+ fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED,
+ DECL_OFFSET_ALIGN (node));
+
+ if (TREE_CODE (node) == FUNCTION_DECL && DECL_BUILT_IN (node))
{
- if (DECL_USER_ALIGN (node))
- fprintf (file, " user");
-
- fprintf (file, " align %d", DECL_ALIGN (node));
- if (TREE_CODE (node) == FIELD_DECL)
- fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED,
- DECL_OFFSET_ALIGN (node));
- }
- else if (DECL_BUILT_IN (node))
- {
if (DECL_BUILT_IN_CLASS (node) == BUILT_IN_MD)
fprintf (file, " built-in BUILT_IN_MD %d", DECL_FUNCTION_CODE (node));
else
Index: gcc/varasm.c
===================================================================
--- gcc/varasm.c (revision 126496)
+++ gcc/varasm.c (working copy)
@@ -1679,18 +1679,17 @@
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);
- if (align < force_align_functions_log)
- align = force_align_functions_log;
+ align = floor_log2 (DECL_ALIGN (decl) / BITS_PER_UNIT);
if (align > 0)
{
ASM_OUTPUT_ALIGN (asm_out_file, align);
}
/* Handle a user-specified function alignment.
- Note that we still need to align to FUNCTION_BOUNDARY, as above,
+ Note that we still need to align to DECL_ALIGN, as above,
because ASM_OUTPUT_MAX_SKIP_ALIGN might not do any alignment at all. */
- if (align_functions_log > align
+ if (! DECL_USER_ALIGN (decl)
+ && align_functions_log > align
&& cfun->function_frequency != FUNCTION_FREQUENCY_UNLIKELY_EXECUTED)
{
#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
Index: gcc/c-common.c
===================================================================
--- gcc/c-common.c (revision 126496)
+++ gcc/c-common.c (working copy)
@@ -3245,16 +3245,16 @@
}
/* Implement the __alignof keyword: Return the minimum required
- alignment of EXPR, measured in bytes. For VAR_DECL's and
- FIELD_DECL's return DECL_ALIGN (which can be set from an
- "aligned" __attribute__ specification). */
+ alignment of EXPR, measured in bytes. For VAR_DECLs,
+ FUNCTION_DECLs and FIELD_DECLs return DECL_ALIGN (which can be set
+ from an "aligned" __attribute__ specification). */
tree
c_alignof_expr (tree expr)
{
tree t;
- if (TREE_CODE (expr) == VAR_DECL)
+ if (VAR_OR_FUNCTION_DECL_P (expr))
t = size_int (DECL_ALIGN_UNIT (expr));
else if (TREE_CODE (expr) == COMPONENT_REF
@@ -5206,12 +5206,24 @@
TYPE_ALIGN (*type) = (1 << i) * BITS_PER_UNIT;
TYPE_USER_ALIGN (*type) = 1;
}
- else if (TREE_CODE (decl) != VAR_DECL
+ else if (! VAR_OR_FUNCTION_DECL_P (decl)
&& TREE_CODE (decl) != FIELD_DECL)
{
error ("alignment may not be specified for %q+D", decl);
*no_add_attrs = true;
}
+ else if (TREE_CODE (decl) == FUNCTION_DECL
+ && DECL_ALIGN (decl) > (1 << i) * BITS_PER_UNIT)
+ {
+ if (DECL_USER_ALIGN (decl))
+ error ("alignment for %q+D was previously specified as %d "
+ "and may not be decreased", decl,
+ DECL_ALIGN (decl) / BITS_PER_UNIT);
+ else
+ error ("alignment for %q+D must be at least %d", decl,
+ DECL_ALIGN (decl) / BITS_PER_UNIT);
+ *no_add_attrs = true;
+ }
else
{
DECL_ALIGN (decl) = (1 << i) * BITS_PER_UNIT;
============================================================