This is an archive of the discontinued LLVM Phabricator instance.

PR18513: make gcc compatible layout for bit-fields with explicit aligned attribute
ClosedPublic

Authored by DmitryPolukhin on Nov 25 2015, 2:57 AM.

Diff Detail

Repository
rL LLVM

Event Timeline

DmitryPolukhin retitled this revision from to PR18513: make gcc compatible layout for bit-fields with explicit aligned attribute.
DmitryPolukhin updated this object.
DmitryPolukhin added a reviewer: rjmccall.
DmitryPolukhin added a subscriber: cfe-commits.

Friendly ping, any comments about this patch?

rsmith added a subscriber: rsmith.Nov 30 2015, 11:24 AM

GCC's behavior (aligned on a field specifies the alignment of the start of that field) makes a little more sense to me than Clang's behavior (the type and alignment of a field specify a flavour of storage unit, and the field goes in the next such storage unit that it fits into), but both seem defensible.

John, are we intentionally deviating from GCC's behaviour here?

lib/AST/RecordLayoutBuilder.cpp
1606 ↗(On Diff #41120)

You should round up to FieldAlign here.

rjmccall edited edge metadata.Nov 30 2015, 11:27 AM

Well, this is a really nasty bug.

Please check how this interacts with #pragma pack, which normally takes precedence over even explicit alignment attributes. If that's the case here, then what you really want to do is just add the same "ExplicitFieldAlign ||" clause to the main computation that you do to the diagnostic computation.

GCC's behavior (aligned on a field specifies the alignment of the start of that field) makes a little more sense to me than Clang's behavior (the type and alignment of a field specify a flavour of storage unit, and the field goes in the next such storage unit that it fits into), but both seem defensible.

Are you saying that aligned on a bit-field always starts new storage on GCC?

John, are we intentionally deviating from GCC's behaviour here?

No. I consider this to be GCC's extension, with which we are required to be ABI-compatible. This is just a bug.

DmitryPolukhin edited edge metadata.

Added more testcases to cover combination of explicit alignment of bit-filed with packed attribute. Also added testing on ARM for bit-filed layout test.

I added more testcases and they all pass identically on GCC and clang with my patch. Please let me know if you think, that some cases are not covered or doesn't work with my patch. Perhaps we can reduce number of test-cases because some of them almost duplicates but for now I added them all.

As for MS compatibility mode, I think we shouldn't worry about them because MS does't support attrbute(aligned) and #pragma pack seems to have no influence on bit-filed layout as far as I tested. If you think that attrbute(aligned) should work in MS compatibility mode and use GCC semantic, please let me know, I'll update my patch accordingly.

lib/AST/RecordLayoutBuilder.cpp
1606 ↗(On Diff #41120)

Unfortunately, I cannot use FieldAlign here because FieldAlign = max(ExplicitFieldAlign, alignof(field_type)). But GCC allows to specify alignment less than normal type alignment for bit-field, see 'struct g2' case in my testcase (it will fail if I round up to FieldAlign here).

I don't mean the actual layout used by Windows targets; I mean the layout used by the ms_struct pragma / attribute.

lib/AST/RecordLayoutBuilder.cpp
1606 ↗(On Diff #41481)

It does still seem to be limited by platforms that ignore natural alignment, though, and by #pragma pack (2) and so on, so at least some of the modifications made to FieldAlign need to be reflected in ExplicitFieldAlign.

I had to spend some time trying to work out counter-examples, but I did convince myself that the effect of the fallback here is correct. My concern was that there was a way we might round up to FieldAlign when we only needed to round up to ExplicitFieldAlign, which could matter if there were another properly-aligned position within the current storage unit. However, the second clause of the first condition will only trigger at the very end of a storage unit, which means that there cannot be any other properly-aligned positions within it.

It might be wrong for zero-width bit-fields, though, since we'll always round up to FieldAlign instead of ExplicitFieldAlign.

1614 ↗(On Diff #41481)

This should follow the same logic that you use for FieldOffset, unless I'm missing something.

DmitryPolukhin marked an inline comment as done.

Fixed logic for warning calculation and added even more test-cases.

This CL doesn't changes anything for ms_struct cases and ms_struct seems to be broken for bit-fields even for very simple cases so filed separate bug https://llvm.org/bugs/show_bug.cgi?id=25707

PTAL

lib/AST/RecordLayoutBuilder.cpp
1606 ↗(On Diff #41481)

I think compiler can ignore natural type alignment here because it is bit-field and therefore compiler has to generate shift/mask sequence for accessing unaligned field anyway. I tried examples like:

struct attribute((packed)) B {

char AField;
__attribute__((aligned(1))) __int128 i : 124;
char BField;

};

Both GCC and Clang with my patch generates the same result on x86 and ARM:
sizeof(struct B) = 18
offsetof(struct B, BField) = 17
__alignof(struct B) = 1

Also tried zero-width bit-filed, my patch works fine. So I was not able to find arch that requires round up for ExplicitFieldAlign and what is required. All examples that I can think of work identical on GCC and Clang.

rjmccall added inline comments.Dec 2 2015, 9:42 AM
lib/AST/RecordLayoutBuilder.cpp
1606 ↗(On Diff #41611)

Be sure to test specifically with an APCS ARM target; newer ARM ABIs don't ignore bit-field layout. Sorry, I should have been more explicit about that. (You can figure this stuff out by looking at the various targets in Targets.cpp that set UseBitFieldTypeAlignment.)

DmitryPolukhin added inline comments.Dec 3 2015, 6:35 AM
lib/AST/RecordLayoutBuilder.cpp
1606 ↗(On Diff #41611)

'-triple=arm-apcs-gnu' does give difference with GCC '-target=arm -mabi=apcs-gnu -mfloat-abi=softfp'. But even without my patch I see bunch of difference in layout (i.e. structs a2, a3, c, d, s0). So I just disabled my changes for APCS because it requires more attention than just fix explicit alignment case and I'm not sure that it is used enough nowadays.

rjmccall added inline comments.Dec 4 2015, 1:15 AM
lib/AST/RecordLayoutBuilder.cpp
1606 ↗(On Diff #41748)

No, that's what I meant by needing a rebuilt GCC; GCC apparently doesn't apply the APCS struct layout rules correctly when you just set -mabi, because the GCC design configures those things at build time.

I agree that it's most reasonable not to worry about it; however, I wouldn't disable your changes under APCS, because that suggests something misleading: it suggests you actually did the investigation to decide that APCS layout ignores explicit alignment. I find it unlikely that GCC's APCS layout completely ignores these attributes.

DmitryPolukhin added inline comments.Dec 4 2015, 1:28 AM
lib/AST/RecordLayoutBuilder.cpp
1606 ↗(On Diff #41748)

So do you suggest just add TODO here and remove checks for APCS as it was in previous patch set?

Yes, I think that's a reasonable approach.

Added TODO, any other comments or suggestions?

John and Richard,

I think this patch fixes important ABI compatibility issue with GCC and if there are no more comments, I think it makes sense to commit it. Could you please approve this CL?

Thanks,
Dmitry

Friendly ping.

I don't think this change makes APCS mode worse. As an alternative I could return to the variant that doesn't change anything for APCS case. Please let me know if APCS case must be resolved and TODO is not enough for committing this change.

John and Richard,

I would like to proceed with this patch one way or another. If this patch cannot be accepted in upstream, I'll discard it. On the other hand I'm ready to improve this patch further if it is OK in principle but needs more work. Please let me know how you would like to proceed?

Thanks,
Dmitry

Sorry, holidays. I'm comfortable with taking this patch as-is.

This revision was automatically updated to reflect the committed changes.