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]

Forced alignment of arrays


I'd like to test the water on the patch below, which was developed
internally against a 4.2-based branch.  It introduces a new flag that
forces the minimum alignment of array variables to be the largest power
of two less than or equal to their total storage size, or the biggest
alignment used on the machine, whichever is smaller.

This patch was developed in response to a request from a customer who
has a large body of code using type punning in non-strictly-conforming
(in the sense of the C standard) ways such as this:

	char foo[4];
	*(int *) foo = 42;

Use of the new -falign-arrays option clearly does not guarantee that
all code using dubious type punning will work; it just provides
alignment guarantees about the start of arrays.

Note that this patch requires that callers of DATA_ALIGNMENT and
LOCAL_ALIGNMENT now go via calculate_data_alignment and
calculate_local_alignment respectively rather than using the macros
directly.

Is the consensus that this patch, suitably tested on mainline, is
acceptable -- or not?

Mark

--


2007-05-05 Mark Shinwell <shinwell@codesourcery.com>


        gcc/
        * doc/tm.texi: Document that LOCAL_ALIGNMENT and
        DATA_ALIGNMENT should not be used directly.
        * doc/invoke.texi (-falign-arrays): Document.
        * function.c (DATA_ALIGNMENT): Define to a default if
        undefined.
        (alignment_for_aligned_arrays): New.
        (calculate_local_alignment): New.
        (calculate_global_alignment): New.
        * function.h (calculate_local_alignment): New.
        (calculate_global_alignment): New.
        * cfgexpand.c (LOCAL_ALIGNMENT): Don't define to a default.
        (get_decl_align_unit): Use calculate_local_alignment.
        * common.opt (-falign-arrays): New.
        * varasm.c (assemble_variable): Use calculate_data_alignment,
        and use it irrespective of whether DATA_ALIGNMENT is defined.
Index: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi	(revision 170210)
+++ gcc/doc/tm.texi	(working copy)
@@ -1094,6 +1094,9 @@ macro is used instead of that alignment 
 
 If this macro is not defined, then @var{basic-align} is used.
 
+This macro should never be used directly; use
+@code{calculate_global_alignment} instead.
+
 @findex strcpy
 One use of this macro is to increase alignment of medium-size data to
 make it all fit in fewer cache lines.  Another is to cause character
@@ -1125,6 +1128,9 @@ If this macro is not defined, then @var{
 
 One use of this macro is to increase alignment of medium-size data to
 make it all fit in fewer cache lines.
+
+This macro should never be used directly; use
+@code{calculate_local_alignment} instead.
 @end defmac
 
 @defmac EMPTY_FIELD_BOUNDARY
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 170210)
+++ gcc/doc/invoke.texi	(working copy)
@@ -302,7 +302,7 @@ Objective-C and Objective-C++ Dialects}.
 
 @item Optimization Options
 @xref{Optimize Options,,Options that Control Optimization}.
-@gccoptlist{-falign-functions=@var{n}  -falign-jumps=@var{n} @gol
+@gccoptlist{-falign-arrays -falign-functions=@var{n}  -falign-jumps=@var{n} @gol
 -falign-labels=@var{n}  -falign-loops=@var{n}  @gol
 -fbounds-check -fmudflap -fmudflapth -fmudflapir @gol
 -fbranch-probabilities -fprofile-values -fvpt -fbranch-target-load-optimize @gol
@@ -5483,6 +5483,14 @@ constants, the overflowed value can stil
 The @option{-fstrict-overflow} option is enabled at levels
 @option{-O2}, @option{-O3}, @option{-Os}.
 
+@item -falign-arrays
+@opindex falign-arrays
+Set the minimum alignment for array variables to be the largest power
+of two less than or equal to their total storage size, or the biggest
+alignment used on the machine, whichever is smaller.  This option may be
+helpful when compiling legacy code that uses type punning on arrays that
+does not strictly conform to the C standard.
+
 @item -falign-functions
 @itemx -falign-functions=@var{n}
 @opindex falign-functions
Index: gcc/function.c
===================================================================
--- gcc/function.c	(revision 170210)
+++ gcc/function.c	(working copy)
@@ -69,6 +69,10 @@ Software Foundation, 51 Franklin Street,
 #define LOCAL_ALIGNMENT(TYPE, ALIGNMENT) ALIGNMENT
 #endif
 
+#ifndef DATA_ALIGNMENT
+#define DATA_ALIGNMENT(TYPE, ALIGNMENT) ALIGNMENT
+#endif
+
 #ifndef STACK_ALIGNMENT_NEEDED
 #define STACK_ALIGNMENT_NEEDED 1
 #endif
@@ -415,7 +419,7 @@ assign_stack_local_1 (enum machine_mode 
 	 stack slot.  */
       type = lang_hooks.types.type_for_mode (mode, 0);
       if (type)
-	alignment = LOCAL_ALIGNMENT (type, alignment);
+	alignment = calculate_local_alignment (type, alignment);
 
       alignment /= BITS_PER_UNIT;
     }
@@ -629,7 +633,7 @@ assign_stack_temp_for_type (enum machine
     type = lang_hooks.types.type_for_mode (mode, 0);
 
   if (type)
-    align = LOCAL_ALIGNMENT (type, align);
+    align = calculate_local_alignment (type, align);
 
   /* Try to find an available, already-allocated temporary of the proper
      mode which meets the size and alignment requirements.  Choose the
@@ -5540,6 +5544,76 @@ current_function_name (void)
 {
   return lang_hooks.decl_printable_name (cfun->decl, 2);
 }
+
+/* Helper function for below.  This function adjusts alignments as
+   appropriate according to the setting of -falign-arrays.  If that is
+   specified then the minimum alignment for array variables is set to be
+   the largest power of two less than or equal to their total storage size,
+   or the biggest alignment used on the machine, whichever is smaller.  */
+
+static unsigned int
+alignment_for_aligned_arrays (tree ty, unsigned int existing_alignment)
+{
+  unsigned int min_alignment;
+  tree size;
+
+  /* Return the existing alignment if not using -falign-arrays or if
+     the type is not an array type.  */
+  if (!flag_align_arrays || TREE_CODE (ty) != ARRAY_TYPE)
+    return existing_alignment;
+
+  /* Extract the total storage size of the array in bits.  */
+  size = TYPE_SIZE (ty);
+  gcc_assert (size);
+
+  /* At least for variable-length arrays, TREE_CODE (size) might not be an
+     integer constant; check it now.  If it is not, give the array at
+     least BIGGEST_ALIGNMENT just to be safe.   Furthermore, we assume that
+     alignments always fit into a host integer.  So if we can't fit the
+     size of the array in bits into a host integer, it must also be large
+     enough to deserve at least BIGGEST_ALIGNMENT (see below).  */
+  if (TREE_CODE (size) != INTEGER_CST || !host_integerp (size, 1))
+    min_alignment = BIGGEST_ALIGNMENT;
+  else
+    {
+      unsigned HOST_WIDE_INT bits = TREE_INT_CST_LOW (size);
+
+      /* An array with size greater than BIGGEST_ALIGNMENT is assigned
+	 at least that alignment.  In all other cases the minimum
+	 alignment of the array is set to be the largest power of two
+	 less than or equal to the total storage size of the array.
+	 We assume that BIGGEST_ALIGNMENT fits in "unsigned int"; thus,
+	 the shift below will not overflow.  */
+      if (bits >= BIGGEST_ALIGNMENT)
+	min_alignment = BIGGEST_ALIGNMENT;
+      else
+	min_alignment = 1 << (HOST_BITS_PER_WIDE_INT - 1 - CLZ_HWI (bits));
+    }
+
+  /* Having computed the minimum permissible alignment, enlarge it
+     if EXISTING_ALIGNMENT is greater.  */
+  return MAX (min_alignment, existing_alignment); 
+}
+
+/* Return the alignment in bits to be used for a local variable
+   of type TY whose usual alignment would be EXISTING_ALIGNMENT.  */
+
+unsigned int
+calculate_local_alignment (tree ty, unsigned int existing_alignment)
+{
+  return alignment_for_aligned_arrays (ty,
+    LOCAL_ALIGNMENT (ty, existing_alignment));
+}
+
+/* Return the alignment in bits to be used for a global variable
+   of type TY whose usual alignment would be EXISTING_ALIGNMENT.  */
+
+unsigned int
+calculate_global_alignment (tree ty, unsigned int existing_alignment)
+{
+  return alignment_for_aligned_arrays (ty,
+    DATA_ALIGNMENT (ty, existing_alignment));
+}
 
 
 static unsigned int
Index: gcc/function.h
===================================================================
--- gcc/function.h	(revision 170210)
+++ gcc/function.h	(working copy)
@@ -579,4 +579,9 @@ extern bool reference_callee_copied (CUM
 
 extern void used_types_insert (tree);
 
+extern unsigned int calculate_local_alignment (
+  tree ty, unsigned int existing_alignment);
+extern unsigned int calculate_global_alignment (
+  tree ty, unsigned int existing_alignment);
+
 #endif  /* GCC_FUNCTION_H */
Index: gcc/cfgexpand.c
===================================================================
--- gcc/cfgexpand.c	(revision 170210)
+++ gcc/cfgexpand.c	(working copy)
@@ -84,10 +84,6 @@ failed:
 }
 
 
-#ifndef LOCAL_ALIGNMENT
-#define LOCAL_ALIGNMENT(TYPE, ALIGNMENT) ALIGNMENT
-#endif
-
 #ifndef STACK_ALIGNMENT_NEEDED
 #define STACK_ALIGNMENT_NEEDED 1
 #endif
@@ -158,7 +154,7 @@ get_decl_align_unit (tree decl)
   unsigned int align;
 
   align = DECL_ALIGN (decl);
-  align = LOCAL_ALIGNMENT (TREE_TYPE (decl), align);
+  align = calculate_local_alignment (TREE_TYPE (decl), align);
   if (align > PREFERRED_STACK_BOUNDARY)
     align = PREFERRED_STACK_BOUNDARY;
   if (cfun->stack_alignment_needed < align)
Index: gcc/common.opt
===================================================================
--- gcc/common.opt	(revision 170210)
+++ gcc/common.opt	(working copy)
@@ -228,6 +228,12 @@ Common Separate
 fabi-version=
 Common Joined UInteger Var(flag_abi_version) Init(2)
 
+falign-arrays
+Target Report Var(flag_align_arrays)
+Set the minimum alignment for array variables to be the largest power
+of two less than or equal to their total storage size, or the biggest
+alignment used on the machine, whichever is smaller.
+
 falign-functions
 Common Report Var(align_functions,0)
 Align the start of functions
Index: gcc/varasm.c
===================================================================
--- gcc/varasm.c	(revision 170210)
+++ gcc/varasm.c	(working copy)
@@ -858,9 +858,7 @@ align_variable (tree decl, bool dont_out
   /* On some machines, it is good to increase alignment sometimes.  */
   if (! DECL_USER_ALIGN (decl))
     {
-#ifdef DATA_ALIGNMENT
-      align = DATA_ALIGNMENT (TREE_TYPE (decl), align);
-#endif
+      align = calculate_global_alignment (TREE_TYPE (decl), align);
 #ifdef CONSTANT_ALIGNMENT
       if (DECL_INITIAL (decl) != 0 && DECL_INITIAL (decl) != error_mark_node)
 	align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl), align);

@@ -1,3 +1,25 @@
2007-05-02  Mark Shinwell  <shinwell@codesourcery.com>

	gcc/
	* doc/tm.texi: Document that LOCAL_ALIGNMENT and
	DATA_ALIGNMENT should not be used directly.
	* doc/invoke.texi (-falign-arrays): Document.
	* function.c (DATA_ALIGNMENT): Define to a default if
	undefined.
	(alignment_for_aligned_arrays): New.
	(calculate_local_alignment): New.
	(calculate_global_alignment): New.
	* function.h (calculate_local_alignment): New.
	(calculate_global_alignment): New.
	* cfgexpand.c (LOCAL_ALIGNMENT): Don't define to a default.
	(get_decl_align_unit): Use calculate_local_alignment.
	* common.opt (-falign-arrays): New.
	* varasm.c (assemble_variable): Use calculate_data_alignment,
	and use it irrespective of whether DATA_ALIGNMENT is defined.

 2007-05-02  Paul Brook  <paul@codesourcery.com>
 
 	gcc/

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