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: ICE outputting unaligned fp constant on powerpc-apple-darwin5.1


A quick analysis of http://gcc.gnu.org/ml/gcc/2001-11/msg01595.html

This static initialization fragment causes an ICE on the
TARGET_POWERPC GCC3:

         struct { int i ; double d ; } x = { 1, 42.0 } ;

The trouble seems to be an alignment check in
varasm.c:assemble_real().  BTW, "BIGGEST_FIELD_ALIGNMENT" is not
defined for TARGET_POWERPC:

1.200        (rth      18-Aug-01): assemble_real (d, mode, align)
...
1.200        (rth      18-Aug-01):   /* We cannot emit unaligned 
floating point constants.  This is slightly
1.200        (rth      18-Aug-01):      complicated in that we don't 
know what "unaligned" means exactly.  */
1.200        (rth      18-Aug-01): #ifdef BIGGEST_FIELD_ALIGNMENT
1.200        (rth      18-Aug-01):   if (align >= 
BIGGEST_FIELD_ALIGNMENT)
1.200        (rth      18-Aug-01):     ;
1.200        (rth      18-Aug-01):   else
1.200        (rth      18-Aug-01): #endif
1.200        (rth      18-Aug-01):   if (align < GET_MODE_ALIGNMENT 
(mode))
1.200        (rth      18-Aug-01):     abort ();
...

On PPC, structures are aligned to accomodate their most restrictive
member, maxing out at word alignment, except 1) if the *first* member
of the struct requires more alignment, the struct follows, and 2) if
any field has type 'vector' (AltiVec), the entire struct will be
16-byte (AltiVec) aligned.

Any field of type double that isn't the first field of a struct will
be word-aligned. Structure size is always a multiple of its alignment
(for array-of-struct indexing).

These rules have some curious properties. For example,

         /* a twelve-byte struct requiring 4-byte alignment */
         struct { int i ; double d ; } x = { 1, 42.0 } ;

         /* a sixteen-byte struct requiring 8-byte alignment */
         struct { double d ; int i ; } y = { 42.0, 1 } ;

The real problem is that PPC violates the assumption stated in the
comment: "cannot emit unaligned floating point constants." On PPC,
we're *supposed* to violate that principle.  The rest of the comment
foreshadows our current problem :-) .

My preferred solution would be for some enlightened person to explain
that I've misunderstood the PPC alignment rules :-) .

Failing that, my next idea was to delete the sanity check, and Apple
is currently using such a patch.  However, that leaves the "align"
parameter unreferenced, and presumably this is a useful check for
every other GCC target.

There are several possible fixes, all unpalatable. Either we 1) delete
the check, 2) pass down more information to facilitate a smarter
check, or 3) conditionalize it away for PPC.

1) will work, but loses this useful check for every non-PPC target.

2) is architecturally unpalatable, as it means complicating this
low-level routine in a way that is useless to every non-PPC target.

3) is ugly, as this is clearly supposed to be a target-independent file.
Nevertheless, IMHO it seems the least unpalatable of these alternatives.

Accordingly, below is a patch implementing alternative 3).

Instead of "#ifndef TARGET_POWERPC", I offer "#ifndef
IRRATIONAL_ALIGNMENT_RULES", basically a synonym for "TARGET_POWERPC"
(and TARGET_POWER, etc.). 'Tis ugly, and I dislike the
double-negative, but it's very localized.  More usefully, it imposes
no further burden on any other (rationally aligned) target, and it can
be employed by any future target with similarly baroque alignment
rules.

This patch has bootstrapped C, C++, and ObjC on powerpc-apple-darwin
and i686-pc-linux-gnu. No regressions.

I've been told that AIX (and, by inference, powerpc-linux) employs the
same alignment rules.  Since I've seen no reference to this problem
from any AIX users, I would have guessed otherwise.  How was this
resolved on AIX and powerpc-linux, or is it still undiscovered there?

I'm a bit disturbed that such a fundamental bug escaped detection for
more than three months.  (Perhaps all of our double fields have been
carefully pre-aligned by hand in our sources? Maybe nobody uses double
fields?)  I did a quick scan of the compile and execute sections of
gcc.c-torture, and didn't notice any unaligned-double-in-struct
checks. I have already posted a suitable testcase.

stuart hastings

2001-12-05 Stuart Hastings <stuart@apple.com>

         * rs6000.h (IRRATIONAL_ALIGNMENT_RULES) New macro.
         * varasm.c (assemble_real): Use it.

Index: gcc/gcc/config/rs6000/rs6000.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.h,v
retrieving revision 1.151
diff -c -d -c -5 -p -r1.151 rs6000.h
*** rs6000.h    2001/12/03 19:13:35     1.151
--- rs6000.h    2001/12/05 17:39:54
*************** extern int rs6000_altivec_abi;
*** 630,639 ****
--- 630,642 ----
   #define FUNCTION_BOUNDARY 32

   /* No data type wants to be aligned rounder than this.  */
   #define BIGGEST_ALIGNMENT 128

+ /* Structs with 64-bit doubles may be 64-bit or 32-bit aligned.  */
+ #define IRRATIONAL_ALIGNMENT_RULES 1
+
   /* A C expression to compute the alignment for a variables in the
      local store.  TYPE is the data type, and ALIGN is the alignment
      that the object would ordinarily have.  */
   #define LOCAL_ALIGNMENT(TYPE, ALIGN)                          \
         ((TARGET_ALTIVEC                                        \
Index: gcc/gcc/varasm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/varasm.c,v
retrieving revision 1.233
diff -c -d -c -5 -p -r1.233 varasm.c
*** varasm.c    2001/12/01 18:42:39     1.233
--- varasm.c    2001/12/05 17:39:54
*************** assemble_real (d, mode, align)
*** 2156,2174 ****
--- 2156,2176 ----
   {
     struct assemble_real_args args;
     args.d = &d;
     args.mode = mode;

+ #ifndef IRRATIONAL_ALIGNMENT_RULES
     /* We cannot emit unaligned floating point constants.  This is 
slightly
        complicated in that we don't know what "unaligned" means 
exactly.  */
   #ifdef BIGGEST_FIELD_ALIGNMENT
     if (align >= BIGGEST_FIELD_ALIGNMENT)
       ;
     else
   #endif
     if (align < GET_MODE_ALIGNMENT (mode))
       abort ();
+ #endif

     if (do_float_handler (assemble_real_1, (PTR) &args))
       return;

     internal_error ("floating point trap outputting a constant");


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