dmd
dmd copied to clipboard
Implement C-style atomic alignment rules for shared types
@kinke this is trivially done. As it's target-specific, I'm not keen on adding tests for it.
struct S
{
size_t[2] values;
}
struct T
{
shared(S) field;
}
pragma(msg, S.alignof); // 8u
pragma(msg, shared(S).alignof); // 16u
In C, _Atomic
overrides any explicit alignment too, however I don't think we should follow that example, so align(8) struct S
still has an alignment of 8 when it is qualified shared
.
Thanks for your pull request, @ibuclaw!
Bugzilla references
Your PR doesn't reference any Bugzilla issue.
If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.
Testing this PR locally
If you don't have a local development environment setup, you can use Digger to test this PR:
dub run digger -- build "stable + dmd#16072"
What about basic types like integers?
What about basic types like integers?
They have the same alignment as their nonatomic equivalent. Any potential deviations don't apply to targets DMD cares about (ie. SystemZ) - GDC and LDC can deal with this in their own vendor implementation of Target::alignsize
.
What about basic types like integers?
They have the same alignment as their nonatomic equivalent. Any potential deviations don't apply to targets DMD cares about (ie. SystemZ) - GDC and LDC can deal with this in their own vendor implementation of
Target::alignsize
.
Saying that, you've just reminded me that I didn't consider i386.
https://cpp.godbolt.org/z/Trq38qdPn
What about basic types like integers?
They have the same alignment as their nonatomic equivalent. Any potential deviations don't apply to targets DMD cares about (ie. SystemZ) - GDC and LDC can deal with this in their own vendor implementation of
Target::alignsize
.Saying that, you've just reminded me that I didn't consider i386.
https://cpp.godbolt.org/z/Trq38qdPn
Right, this isn't about the type.
Atomics does not care about the type.
The CPU cares about the size and the pointer address alignment.
This is why I kinda think the storage class for atomic is well worth it. We can encode the restriction surrounding size and pointer to make it work appropriately for the target.
What about basic types like integers? The CPU cares about the size and the pointer address alignment.
So then the question is not just basic types, but also all derived types too, all of which are usually pointer aligned, but are sized 2 * size_t.sizeof
.
What about basic types like integers? The CPU cares about the size and the pointer address alignment.
So then the question is not just basic types, but also all derived types too, all of which are usually pointer aligned, but are sized
2 * size_t.sizeof
.
I already covered that interestingly enough.
atomic(size_t[2])*
The pointer is not atomic, but the type it points to is. It would not be transitive like shared
is.
This also covers another question, regarding validation. Maximum sizes of the type is just as important for a CT error as alignment is (which should be forced based upon target).
This also covers another question, regarding validation. Maximum sizes of the type is just as important for a CT error as alignment is (which should be forced based upon target).
Well, anything that can't be done in CPU is just becomes a soft implementation.
This also covers another question, regarding validation. Maximum sizes of the type is just as important for a CT error as alignment is (which should be forced based upon target).
Well, anything that can't be done in CPU is just becomes a soft implementation.
As far as I'm aware only GDC supports that. But that is ok, it can be compiler-specific (since it is already target-specific). Unless more work is done for the compilers as fallback.
However, I'm more inclined to think that it is better to error, so that people can write their own fallbacks. So that such a decision is informed, rather than an uninformed surprise.
This won't work due to the transitiveness of shared
. Suppose we have a struct S { int dummy; void[] slice; }
on a 64-bit target, with S.slice.offsetof == 8
and S.alignof == 8
. Now when declaring a shared S global
var, the type of global.slice
is shared(void[])
, but its alignment is 8, not 16 as a standalone shared void[]
var.
I'm not sure we need to tackle this at the language level, mainly because I think the problem is almost entirely restricted to aggregates with double-word size. Aligning those manually or using some Atomic!T
library wrapper might not be too bad.