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]

Re: PowerPC64 alignment of long doubles


On Tue, Sep 16, 2003 at 12:06:03PM +0930, Alan Modra wrote:
> The PowerPC64 Linux ABI says "The required alignment of a double or long
> double field is word, not doubleword or quadword as might be expected
> from the size of the field."
> 
> and also
> 
> "Note: When compared to the 32-bit PowerPC Processor Supplement, the
> size and alignment of long has changed, and the alignment of double
> and long double has changed.  A compiler may provide options to use
> different sizes and alignments; however, any object compiled with
> those options will not conform to the 64-bit PowerPC Processor
> Supplement."
> 
> We currently have this wrong for long double, and I'll shortly be
> sending a patch to correct the situation.

First, let's describe the current default alignment rules for double
on powerpc gcc targets following the AXI ABI:

a) A double in a struct is aligned to a 4 byte boundary,
b) except when it's the first double in the struct, in which case it
   is aligned to an 8 byte boundary
c) except that the 8 byte alignment conferred by rule (b) does not
   apply to a nested struct when the nested struct has only only field.

Rule (c) is the really odd case, caused by stor-layout.c treating a
single field struct as if the field wasn't wrapped in a struct.  What's
more, rule (c) seems to be new with 3.4.  ie. 3.3 -> 3.4 already
contains an ABI change.

Some examples:
struct S1 { char c; double d; } s1;
struct S2 { double d; } s2;
struct S3 { char c; struct S2 s2; } s3;
struct S4 { double d; int i; } s4;
struct S5 { char c; struct S4 s4; } s5;
struct S6 { struct S2 s2; } s6;
struct S7 { char c; struct S6 s6; } s7;

s1: size=12 align=4 off=4 (off is the offset of the double)
s2: size=8 align=8 off=0
s3: size=12 align=4 off=4
s4: size=16 align=8 off=0
s5: size=24 align=8 off=8
s6: size=8 align=8 off=0
s7: size=12 align=4 off=4

IMO, rule (c) just makes things too complicated for words, and there's
no way I want this behaviour to be enshrined in the ABI.

Now, as far as I know, the reason for rule (b) is that loading a double
from an 8 byte aligned location is quicker than loading from a 4 byte
aligned location.  ie. rule (b) was introduced to counteract the
negative effects of rule (a) in the case where a struct contains a
number of fields, all of type double.  It seem to me that we can easily
accomplish this by aligning when emitting instances of such structs,
rather than playing with the alignment in the struct type.

The following also corrects alignment of complex double and complex
long double.

	* config/rs6000/rs6000.c (rs6000_adjust_field_align): New function.
	(rs6000_data_alignment): Likewise.
	* config/rs6000/rs6000-protos.h (rs6000_adjust_field_align): Declare.
	(rs6000_data_alignment): Declare.
	* config/rs6000/linux64.h (ADJUST_FIELD_ALIGN): Use
	rs6000_adjust_field_align.
	(ROUND_TYPE_ALIGN): Don't define.
	(DATA_ALIGNMENT): Define.

Index: gcc/config/rs6000/linux64.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/linux64.h,v
retrieving revision 1.48
diff -u -p -r1.48 linux64.h
--- gcc/config/rs6000/linux64.h	16 Jul 2003 11:52:51 -0000	1.48
+++ gcc/config/rs6000/linux64.h	16 Sep 2003 02:36:50 -0000
@@ -202,35 +202,17 @@
 /* We don't need to generate entries in .fixup.  */
 #undef RELOCATABLE_NEEDS_FIXUP
 
-/* This now supports a natural alignment mode. */
-/* AIX word-aligns FP doubles but doubleword-aligns 64-bit ints.  */
-#undef  ADJUST_FIELD_ALIGN
+/* PowerPC64 Linux word-aligns FP doubles, unless -malign-natural is given.  */
+#undef ADJUST_FIELD_ALIGN
 #define ADJUST_FIELD_ALIGN(FIELD, COMPUTED) \
-  ((TARGET_ALTIVEC && TREE_CODE (TREE_TYPE (FIELD)) == VECTOR_TYPE)	\
-   ? 128								\
-   : (TARGET_64BIT							\
-      && TARGET_ALIGN_NATURAL == 0					\
-      && TYPE_MODE (TREE_CODE (TREE_TYPE (FIELD)) == ARRAY_TYPE		\
-		    ? get_inner_array_type (FIELD)			\
-		    : TREE_TYPE (FIELD)) == DFmode)			\
-   ? MIN ((COMPUTED), 32)						\
-   : (COMPUTED))
-
-/* AIX increases natural record alignment to doubleword if the first
-   field is an FP double while the FP fields remain word aligned.  */
-#undef  ROUND_TYPE_ALIGN
-#define ROUND_TYPE_ALIGN(STRUCT, COMPUTED, SPECIFIED)		\
-  ((TARGET_ALTIVEC && TREE_CODE (STRUCT) == VECTOR_TYPE)	\
-   ? MAX (MAX ((COMPUTED), (SPECIFIED)), 128)			\
-   : (TARGET_64BIT						\
-      && (TREE_CODE (STRUCT) == RECORD_TYPE			\
-	  || TREE_CODE (STRUCT) == UNION_TYPE			\
-	  || TREE_CODE (STRUCT) == QUAL_UNION_TYPE)		\
-      && TYPE_FIELDS (STRUCT) != 0				\
-      && TARGET_ALIGN_NATURAL == 0				\
-      && DECL_MODE (TYPE_FIELDS (STRUCT)) == DFmode)		\
-   ? MAX (MAX ((COMPUTED), (SPECIFIED)), 64)			\
-   : MAX ((COMPUTED), (SPECIFIED)))
+  rs6000_adjust_field_align (FIELD, COMPUTED)
+
+/* Align vectors to 128 bits.  Make arrays of chars word-aligned.
+   Increase alignment to doubleword if the first field of an aggregate
+   is a double.  */
+#undef DATA_ALIGNMENT
+#define DATA_ALIGNMENT(TYPE, ALIGN)					\
+  rs6000_data_alignment (TYPE, ALIGN)
 
 /* Indicate that jump tables go in the text section.  */
 #undef  JUMP_TABLES_IN_TEXT_SECTION
Index: gcc/config/rs6000/rs6000-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000-protos.h,v
retrieving revision 1.62
diff -u -p -r1.62 rs6000-protos.h
--- gcc/config/rs6000/rs6000-protos.h	12 Sep 2003 19:00:45 -0000	1.62
+++ gcc/config/rs6000/rs6000-protos.h	16 Sep 2003 02:36:50 -0000
@@ -199,6 +199,8 @@ extern int rs6000_register_move_cost (en
 extern int rs6000_memory_move_cost (enum machine_mode, enum reg_class, int);
 extern bool rs6000_tls_referenced_p (rtx);
 extern int rs6000_tls_symbol_ref (rtx, enum machine_mode);
+extern unsigned int rs6000_adjust_field_align (tree, unsigned int);
+extern unsigned int rs6000_data_alignment (tree, unsigned int);
 
 /* Declare functions in rs6000-c.c */
 
Index: gcc/config/rs6000/rs6000.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.518
diff -u -p -r1.518 rs6000.c
--- gcc/config/rs6000/rs6000.c	15 Sep 2003 04:53:00 -0000	1.518
+++ gcc/config/rs6000/rs6000.c	16 Sep 2003 02:36:57 -0000
@@ -14389,6 +14389,65 @@ rs6000_dwarf_register_span (rtx reg)
 		      : gen_rtvec (2,
 				   gen_rtx_REG (SImode, regno),
 				   gen_rtx_REG (SImode, regno + 1200)));
+}
+
+/* PowerPC64 Linux word-aligns FP doubles and long-doubles, unless
+   -malign-natural is given.  */
+unsigned int
+rs6000_adjust_field_align (tree field, unsigned int computed)
+{
+  tree t = TREE_TYPE (field);
+
+  if (TARGET_ALTIVEC && TREE_CODE (t) == VECTOR_TYPE)
+    return 128;
+
+  if (TARGET_64BIT && !TARGET_ALIGN_NATURAL)
+    {
+      if (TREE_CODE (t) == ARRAY_TYPE)
+	t = get_inner_array_type (t);
+      if (FLOAT_TYPE_P (t) && computed > 32)
+	return 32;
+    }
+  return computed;
+}
+
+/* Align vectors to 128 bits.  Make arrays of chars word-aligned.
+   For PowerPC64 Linux, increase alignment to doubleword if the first
+   field of an aggregate is a double or long-double.  */
+unsigned int
+rs6000_data_alignment (tree type, unsigned int align)
+{
+  if (TREE_CODE (type) == VECTOR_TYPE)
+    return TARGET_SPE_ABI ? 64 : 128;
+
+  if (TREE_CODE (type) == ARRAY_TYPE
+      && TYPE_MODE (TREE_TYPE (type)) == QImode
+      && align < BITS_PER_WORD)
+    return BITS_PER_WORD;
+
+  if (TARGET_64BIT && !TARGET_ALIGN_NATURAL && align < 64)
+    {
+      while (1)
+	{
+	  if ((TREE_CODE (type) == RECORD_TYPE
+	       || TREE_CODE (type) == UNION_TYPE
+	       || TREE_CODE (type) == QUAL_UNION_TYPE)
+	      && TYPE_FIELDS (type) != 0
+	      && TREE_CODE (TYPE_FIELDS (type)) == FIELD_DECL
+	      && TREE_TYPE (TYPE_FIELDS (type)) != type)
+	    type = TREE_TYPE (TYPE_FIELDS (type));
+	  else if (TREE_CODE (type) == ARRAY_TYPE)
+	    type = TREE_TYPE (type);
+	  else
+	    break;
+	}
+
+      if (FLOAT_TYPE_P (type)
+	  && TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type)) >= 64)
+	return 64;
+    }
+
+  return align;
 }
 
 #include "gt-rs6000.h"

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre


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