On 11/26/18 3:37 PM, Jeff Law wrote:
On 11/23/18 12:31 PM, Martin Sebor wrote:
GCC currently accepts the declaration of f0 below but ignores
the attribute.  On aarch64 (and I presume on other targets with
a default function alignment greater than 1), GCC rejects f1
with an error, even though it accepts -falign-functions=1
without as much as a warning.

Clang, on the other hand, rejects f0 with a hard error because
the alignment is not a power of two, but accepts f1 and appears
to honor the attribute.  It also accepts -falign-functions=1.

I think diagnosing f0 with a warning is helpful because an explicit
zero alignment is most likely a mistake (especially when it comes
from a macro or some computation).

But I don't see a good reason to reject a program that specifies
a smaller alignment for a function when the default (or minimum)
alignment is greater.  A smaller alignment is trivially satisfied
by a greater alignment so either accepting it or dropping it seems
preferable to failing with an error (either could be with or without
a warning).

   __attribute__ ((aligned (0))) void f0 (void);   // accepted, ignored
   __attribute__ ((aligned (1))) void f1 (void);   // aarch64 error
   __attribute__ ((aligned (4))) void f4 (void);   // okay

Does anyone know why GCC rejects the program, or can anyone think
of a reason why GCC should not behave as suggested above?
Note we have targets that support single byte opcodes and do not have
any requirements for functions starting on any boundary.  mn103 comes to
mind.

However, the attribute can't be used to decrease a function's alignment,
so values of 0 or 1 are in practice totally uninteresting and one could
make an argument to warn for them.

The attribute does reduce the default alignment at least on some
targets.  For instance, on x86_64 it lowers it from the default
16 to as little as 2, but it silently ignores 1.

At the same time, the following passes on x86_64:

  __attribute__ ((aligned (1))) void f1 (void) { }
  _Static_assert (__alignof__ (f1) == 1);   // wrong alignof result

  __attribute__ ((aligned)) void f0 (void) { }
  _Static_assert (__alignof__ (f0) == 16);

  __attribute__ ((aligned (2))) void f2 (void) { }
  _Static_assert (__alignof__ (f2) == 2);

but the assembly shows no .align directive for f1, .align 16 for
f0, and .align 2 for f2, and the object file shows f1 first with
padding up to 16-bytes, followed by f0 padded to a 2 byte
boundary, followed by f2.  The picture stays the same when f1()
is declared without the attribute (i.e., it's 16-byte aligned
by default).  So __alignof__ reports the wrong alignment for
the f1 declared aligned (1).


Whether or not to warn in general if the alignment attribute is smaller
than the default may be subject to debate.  I guess it depends on the
general intent that we'd find in real world codes.

I would expect real world code to care about achieving at least
the specified alignment.

A less restrictive alignment requirement is satisfied by providing
a more restrictive one, and (the above notwithstanding) the manual
documents that

  You cannot use this attribute to decrease the alignment of
  a function, only to increase it.

So I wouldn't expect real code to be relying on decreasing
the alignment.

That said, since GCC does make it possible to decrease the default
alignment of functions, I can think of no reason for it not to
continue when it's possible.  I.e., on targets with underaligned
instruction reads to be honor requests for underaligned functions.
On strictly aligned targets I think the safe thing to do is to
quietly ignore requests for smaller alignments by default, and
perhaps provide a new option to request a warning (with the warning
being disabled by default).

Do you see a problem with this approach?

Martin

Reply via email to