Fix binary compatibility issue with GCC.
Details
Diff Detail
- Repository
- rL LLVM
Event Timeline
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. |
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.
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.
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. |
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: 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. |
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.) |
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. |
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. |
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? |
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