This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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;
============================================================


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]