Bug 63495 - struct __attribute__ ((aligned (8))) broken on x86
Summary: struct __attribute__ ((aligned (8))) broken on x86
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 4.9.1
: P3 normal
Target Milestone: 4.9.2
Assignee: Jakub Jelinek
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-10-09 06:13 UTC by Paul Eggert
Modified: 2014-10-10 18:05 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2014-10-09 00:00:00


Attachments
gcc5-pr63495.patch (730 bytes, patch)
2014-10-09 08:04 UTC, Jakub Jelinek
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Paul Eggert 2014-10-09 06:13:06 UTC
Compile and run the following two-line program with an x86 target:

struct __attribute__ ((aligned (8))) s { char c; };
_Static_assert (_Alignof (struct s) >= 8, "wrong alignment");

This should compile, but here are the symptoms I observe with GCC 4.9.1:

$ gcc -m32 t.c
t.c:2:1: error: static assertion failed: "wrong alignment"
 _Static_assert (_Alignof (struct s) >= 8, "wrong alignment");
 ^

On the buggy platform the structure's alignment is 4; it should be 8.

The program compiles fine with GCC 4.8.3, so there is a regression here.  The program also compiles fine on x86-64.

The alignment bug breaks the trunk version of GNU Emacs when built on a 32-bit platform; see <http://lists.gnu.org/archive/html/emacs-devel/2014-10/msg00261.html>.  I'll try to fix Emacs to work around the bug, but the GCC bug really should get fixed.
Comment 1 Jakub Jelinek 2014-10-09 07:58:39 UTC
This started with r205685.

The problem is in the x86 32-bit ABI, which decreases alignment of fields to 32 bits if the field has integral mode, or DFmode/DCmode or complex integral mode.

int
x86_field_alignment (tree field, int computed)
{
  enum machine_mode mode;
  tree type = TREE_TYPE (field);

  if (TARGET_64BIT || TARGET_ALIGN_DOUBLE)
    return computed;
  mode = TYPE_MODE (strip_array_types (type));
  if (mode == DFmode || mode == DCmode
      || GET_MODE_CLASS (mode) == MODE_INT
      || GET_MODE_CLASS (mode) == MODE_COMPLEX_INT)
    return MIN (32, computed);
  return computed;
}

When the struct has only a single field, it is QImode, therefore despite the
user forced alignment the alignment is lowered to 32 bits.

Now, when actually laying out struct s fields, such as:
struct T { char a; struct s s; } t = { 1, { 2 } };
it actually is given 64-bit alignment, because ADJUST_FIELD_ALIGN is not used in that case:
      if (! packed_p && ! DECL_USER_ALIGN (decl))
        {
          /* Some targets (i.e. i386, VMS) limit struct field alignment
             to a lower boundary than alignment of variables unless
             it was overridden by attribute aligned.  */
#ifdef BIGGEST_FIELD_ALIGNMENT
          DECL_ALIGN (decl)
            = MIN (DECL_ALIGN (decl), (unsigned) BIGGEST_FIELD_ALIGNMENT);
#endif
#ifdef ADJUST_FIELD_ALIGN
          DECL_ALIGN (decl) = ADJUST_FIELD_ALIGN (decl, DECL_ALIGN (decl));
#endif
        }

As do_type_align for FIELD_DECLs sets DECL_USER_ALIGN:
static inline void
do_type_align (tree type, tree decl)
{
  if (TYPE_ALIGN (type) > DECL_ALIGN (decl))
    {
      DECL_ALIGN (decl) = TYPE_ALIGN (type);
      if (TREE_CODE (decl) == FIELD_DECL)
        DECL_USER_ALIGN (decl) = TYPE_USER_ALIGN (type);
    }
}

if TYPE_USER_ALIGN is set, IMHO ADJUST_FIELD_ALIGN and corresponding 
BIGGEST_FIELD_ALIGNMENT will never be used.
Comment 2 Jakub Jelinek 2014-10-09 08:04:20 UTC
Created attachment 33670 [details]
gcc5-pr63495.patch

Untested fix.
Comment 3 Jakub Jelinek 2014-10-10 17:43:53 UTC
Author: jakub
Date: Fri Oct 10 17:43:21 2014
New Revision: 216101

URL: https://gcc.gnu.org/viewcvs?rev=216101&root=gcc&view=rev
Log:
	PR c/63495
	* stor-layout.c (min_align_of_type): Don't decrease alignment
	through BIGGEST_FIELD_ALIGNMENT or ADJUST_FIELD_ALIGN if
	TYPE_USER_ALIGN is set.

	* gcc.target/i386/pr63495.c: New test.

Added:
    trunk/gcc/testsuite/gcc.target/i386/pr63495.c
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/stor-layout.c
    trunk/gcc/testsuite/ChangeLog
Comment 4 Jakub Jelinek 2014-10-10 17:51:46 UTC
Author: jakub
Date: Fri Oct 10 17:51:14 2014
New Revision: 216102

URL: https://gcc.gnu.org/viewcvs?rev=216102&root=gcc&view=rev
Log:
	PR c/63495
	* c-common.c (min_align_of_type): Don't decrease alignment
	through BIGGEST_FIELD_ALIGNMENT or ADJUST_FIELD_ALIGN if
	TYPE_USER_ALIGN is set.

	* gcc.target/i386/pr63495.c: New test.

Added:
    branches/gcc-4_9-branch/gcc/testsuite/gcc.target/i386/pr63495.c
Modified:
    branches/gcc-4_9-branch/gcc/c-family/ChangeLog
    branches/gcc-4_9-branch/gcc/c-family/c-common.c
    branches/gcc-4_9-branch/gcc/testsuite/ChangeLog
Comment 5 Jakub Jelinek 2014-10-10 17:54:54 UTC
Should be fixed now.
Comment 6 Paul Eggert 2014-10-10 18:05:22 UTC
That was fast!  Thank you.