Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarify definition of HFA in AAPCS64 #206

Open
moon-chilled opened this issue Jul 16, 2023 · 8 comments
Open

Clarify definition of HFA in AAPCS64 #206

moon-chilled opened this issue Jul 16, 2023 · 8 comments

Comments

@moon-chilled
Copy link

moon-chilled commented Jul 16, 2023

Consider the following definitions:

typedef struct { double a; double __attribute__((aligned(16))) c; } __attribute__((aligned(16))) T;
typedef struct { double a; double b; double c; } __attribute__((aligned(16))) U;
typedef struct { double a; double b; double c; double d; } __attribute__((aligned(16))) V;

Gcc and clang consider V to be an HFA, and not T and U. There is the following statement (§5.9.5):

The overall size [of the Homogeneous Aggregate] is the size of the Base Type multiplied by the number uniquely addressable Members; its alignment will be the alignment of the Base Type

If this is intended to be a requirement for homogeneous aggregates, then it disqualifies V from being one, since V's alignment is not that of double. If that is the case, then it should be stated more prominently. However, this seems unlikely (§C.4):

If the argument is an HFA, an HVA, a Quad-precision Floating-point or short vector type then the NSAA is rounded up to the next multiple of 8 if its natural alignment is ≤ 8 or the next multiple of 16 if its natural alignment is ≥ 16.

explicitly making allowances for HFAs with alignment >16, even though there is no floating-point type with such alignment. If the intent of the specification was that V should be an HFA, then it is not clear why T and U should not be. It is made clear that padding is not a member, for (§5.9):

A Composite Type can be any of: [...] An aggregate, where the members are laid out sequentially in memory (possibly with inter-member padding).

There are ambiguities in the spec. The best move is probably to change it to be clearly aligned with the behaviour of gcc and clang, but more minimal changes which clearly break gcc and clang are also plausible.

@moon-chilled
Copy link
Author

Another litmus test:

typedef union {
	struct { double a, b; } x;
	struct { double a; double __attribute__((aligned(16))) c; double d; } y;
} __attribute__((aligned(16))) T;

Gcc and clang don't consider this to be an HFA.

@smithp35
Copy link
Contributor

I agree this is an area that could do with further clarification, having been confused by it myself before.

If this is intended to be a requirement for homogeneous aggregates, then it disqualifies V from being one, since V's alignment is not that of double. If that is the case, then it should be stated more prominently. However, this seems unlikely (§C.4):

It is not intended to be a requirement. We consider V to be an alignment modified HFA.

To give you some idea of why clang/gcc are not classifying certain structures as aggregates.

typedef struct { double a; double __attribute__((aligned(16))) c; } __attribute__((aligned(16))) T;
typedef struct { double a; double b; double c; } __attribute__((aligned(16))) U;
typedef struct { double a; double b; double c; double d; } __attribute__((aligned(16))) V;

T is not a HFA as there is padding within the structure. While padding is not important for it to be considered a composite type, it is important for it being considered a HFA.
U is not a HFA as its size is not a multiple of its alignment so there is post-padding.

The best part of the text that describes this is The test for homogeneity is applied after data layout is completed. So effectively we have
T double, double, padding, double
U double, double, double, padding

Neither of which are considered homogenous.

Again I agree that this could be improved. Possibly in an external rationale with examples rather than in the document directly.

@moon-chilled
Copy link
Author

moon-chilled commented Jul 17, 2023

alignment modified HFA

What about struct outer { struct { double a, b; } __attribute__((aligned(16))) inner; }? Or simply struct { double __attribute__((aligned(16))) a; double b; }? In those cases, the structure's natural alignment isn't that of double. (It seems to me that the mention of alignment is just not very useful or interesting; is there a reason for having it?)

While padding is not important for it to be considered a composite type, it is important for it being considered a HFA.

But HFA is defined in terms of uniquely addressable members, and:

  1. Language like 'members are laid out sequentially in memory (possibly with inter-member padding)' makes it clear that padding is not considered a member.
  2. Padding is not addressable. (There is an address where the padding is, but that is not the same thing; for instance, there is an address where the high 32 bits of one of the double floats are—a fact which is arguably a lot more useful—but it's not considered addressable under the semantics.)
  3. To strengthen the above point: consider that 'after layout', in my union example above, it is possible to address after the end of x, but this is not a problem because there is 'nothing' rather than 'padding' there. Why does the 'nothing' after the end of a short union member not count, but the padding in between y.a and y.c does (even though there is a double there, being x.b)?

It seems to me that this is very specifically an issue of padding, and needs to be spelt out as such.

Hence

Possibly in an external rationale with examples rather than in the document directly.

I still think the document itself is ambiguous.

@rearnsha
Copy link

Since I was the original author of the HFA rules in the AAPCS, I'll chime in here.

I've reviewed the text in the AAPCS and I agree that some additional clarity is warranted: the handling of alignment modifiers was added to the specification as a result of the updates to support C11 and in retrospect it's clear that we missed some changes here.

We will need to ensure that any wording changes do not affect existing implementations (excepting, of course, any cases where they do not agree with each other). This may take us some time as we will need to do some careful validation.

@moon-chilled
Copy link
Author

Another litmus test: union { double a[1]; float b[0]; } is not an HFA.

@rearnsha
Copy link

That's not valid C (zero sized arrays are a GNU extension). Perhaps you mean the C11 flexible array float b[];?
Either way, this is not an HFA because the size is not statically determinable at compile time by both the caller and callee, so must be passed by reference.

@moon-chilled
Copy link
Author

moon-chilled commented Jul 22, 2023

That's not valid C (zero sized arrays are a GNU extension).

Right.

Perhaps you mean the C11 flexible array float b[];? Either way, this is not an HFA because the size is not statically determinable at compile time by both the caller and callee, so must be passed by reference.

No; the type struct { double a; float b[]; } has the same size as double (assuming the size and alignment of float are <=those of double, which they are). This makes it dangerous and usually undesirable to pass them around by value, but you can do it. Actually, gcc/clang seem to consider even struct { double a; double b[]; } not an hfa; they pass/return it in a gpr.

@rearnsha
Copy link

Both a and b are addressable in your example, and it is wrong to suggest that b has no size from an ABI perspective - it just isn't known statically. So this is not an homogeneous agregate because the two elements have different types. Secondly, because the size can't be determined statically by both caller and callee, this is never passed by value in a procedure call, but passed by reference per rule B.2.
Homogeneous aggregates are only interesting in the ABI for the specific case of function call arguments passing the special case of small sized HFA. They have no other use, so there's no value in trying to refine the details further.,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants