-
-
Notifications
You must be signed in to change notification settings - Fork 651
add bitfields to D #13568
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
add bitfields to D #13568
Conversation
Thanks for your pull request, @WalterBright! Bugzilla referencesYour 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 locallyIf you don't have a local development environment setup, you can use Digger to test this PR: dub run digger -- build "master + dmd#13568" |
79a960c
to
9c0e97f
Compare
Very nice. This needs a few documentation changes, and a changelog entry to properly advertise it though. |
9c0e97f
to
1dbbed6
Compare
@Geod24 I agree, and I'll add it after this is working. As for bitfields.html, it won't go into Phobos2. |
1dbbed6
to
4001fe3
Compare
Added code example, and link to ddoc PR with documentation. |
4001fe3
to
a768a8c
Compare
Spec PR: dlang/dlang.org#3190 |
a768a8c
to
54f6bb9
Compare
test/fail_compilation/test17284.d
Outdated
fail_compilation/test17284.d(1): Error: no identifier for declarator `TEST_OUTPUT` | ||
fail_compilation/test17284.d(1): Error: declaration expected, not `:` | ||
fail_compilation/test17284.d(12): Error: unmatched closing brace | ||
fail_compilation/test17284.d(3): Error: semicolon needed to end declaration of `__anonBitField1`, instead of `:` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See? You're doing it wrong if users can see internal names.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Identifier.isAnonymous isn't checked in Identifier.toChars
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which is true of every use of anonymous names in the compiler.
uint x : 2, y : 3, :0; | ||
int :0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing:
- union tests
- class tests
- non-pod struct tests (postblit, copy constructors)
- static anonymous bit-field test
- zero-sized named bit-field test
- CTFE-interpreted width tests
- non-integral type tests
- template struct/class tests (
T t : 3;
) - reflection tests (can bit-fields be looked up with
__traits
same as regular fields?) - D enum bit-field tests
- alias this bit-field test
- fail compilation tests (taking address of bit-field)
- property tests (offsetof, sizeof)
- more property tests (min, max)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They all use the same code to resolved bit fields, and the same code that ImportC uses. Not even copied code, it's the same code in the same functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The whole point of this PR was to use the same code as was tested in ImportC.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That may be the case now but it still needs to be tested since it might not be the case in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The whole point of mentioning classes and non-pod structs is to ensure that it works with druntime GC.
The whole point of CTFE constants is because C doesn't have a CTFE engine. (int ctbfield : ctfeFun();
).
The whole point of mentioning __traits
is because C doesn't have reflection.
We aren't testing this currently with ImportC.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is based on a flawed assumption - the type of a bitfield is essentially a lie because the behaviour differs from the base type due to the limited size. This causes misbehaviour e.g. for overflows.
So these claims should be proven by tests instead of handwaving
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if min/max properties would work too, and if value range propagation is aware of any of this. What if I assign an int to a bitfield? Is that a narrowing conversion that requires an explicit cast? If no, i guess so much for that rule. (I hate that rule anyway and would be glad to see it abolished). If yes, how do you explicitly cast to a type you can't represent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I checked the internal type that gdc generates for bit-fields, and it correctly sets the backend properties of ie: int a:2;
to .min = -2, .max = 1
. Haven't checked the D front-end though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I added these tests, except for the template one where I don't know what you mean.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I added these tests, except for the template one where I don't know what you mean.
struct S(T)
{
T t : 3;
}
S!int good;
S!float bad;
Dammit, I hoped I would get away without having to touch LDC's glue layer, and hoped never to see native bitfields in D. :/ I wildly guess 99% of the use cases are packing bools to single bits; I don't think that justifies complicating the language. |
You'll need to implement bit-field support anyway for ImportC. |
I don't need to. :P - They're currently not supported by LDC, just like the poor C initializer lists handling. Edit: Anyway, my argument is the language complication. Just because C has it and now DMD+GDC for ImportC, doesn't mean it's a no-brainer to add this to D too, just because we easily can. |
You will for sure get away with it until someone attempts (from D code), import Cfile; I'm currently blessed by that With any luck, bit-fields are the same as normal fields, you just set a width flag and llvm will take care of the rest.
We've been sitting on this for a month now, so it was was only a matter of time before someone tried to hook the two together. |
I don't want to derail here too much, but as you know, I'm not convinced ImportC is the right approach. Wrt. bitfields, we've been fine all this time without them (there's some library thing in Phobos IIRC), so I'm just raising my concerns here wrt. a clean language for the future. Bitfields seem 1960s tech in my eyes, where wasting bytes was presumably
Nope, LLVM has no such thing in their IR, at least AFAIK. |
Rationale for D bitfields:
that should be replaced with bit flags. But bit flags are a nuisance because they introduce another named scope, and adding/removing flags requires renumbering the rest. It's not self-documenting if the flags are inclusive or exclusive. Bit fields eliminate this problem. As for wasting a byte, the creator of Zig pointed out how saving a byte in a heavily used struct had a significant effect on runtime speed and memory consumption. The dmd backend will replace the bit field operations with shifts and masks: Feel free to reuse in your glue layer. |
The library thing in Phobos https://dlang.org/phobos/std_bitmanip.html is incompatible with the way gcc/clang lay out bit fields. |
Okay so your #1 rationale seems to be the C interop. I don't think that's of high priority given the rareness of bit fields (right?). People/tools are currently using a dummy field of appropriate type and size when mapping a C bitfield to D. Wrt. packing bools, e.g. in DMD source, there are surely cases where packing pays off, but I think they aren't many. I can fit 8 scalar bools inbetween 2 word-aligned members for 64-bit code and gain nothing from packing them into a single byte (but uglify in the source in the process). The existing struct S {
mixin(packedBools!("a", "b", "c"));
}
…
S s;
if (s.a) s.b = true;
Generally speaking, an alternative would be moving this to the frontend. Then the glue layer can stay as it is, and no future D compilers would have to deal with such C ancestry. |
Anything we can do that makes that better will pay off. All it takes is for some user to try using a C library with a bit field, and he's faced with a non-trivial amount of work to deal with it. And much worse is the portability problem with bit field layouts, as it will cause the poor user hidden bugs. I understand the nuisance this is for you, but the code to solve it is all there for you to use. It's just some shifting and masking. @ibuclaw and I have already solved the tedious problem of duplicating the target layout.
That's on my list of things to do. |
Right, because they are forced to. But the problem with it is is what is the "appropriate type and size" ? This is a non-trivial and non-portable problem, as I found out when trying to implement that in the compiler. Alignment and padding are also an issue, as this is all implementation-defined. But to support it in LDC, this work is already done for you. The back end is supplied the byte offset, the bit position, the width, and the signedness. Everything needed to shift & mask. |
We're talking about a new language feature, that's not just 'anything' :) - leaving aside the unpleasant implications for current and future compiler backends. I've incidentally had to map a C++ bitfield to D for interop a while ago, can't remember where, but in the end it was simply a matter of declaring a I found no request for native bitfields: https://issues.dlang.org/buglist.cgi?quicksearch=bitfield&list_id=239169 (also searched for
And of course that's not enough and raises further desires: https://issues.dlang.org/show_bug.cgi?id=22248, one of the 5 open issues about bit fields returned by above query |
For the same reason that other features are behind preview flags (i.e: |
1721c41
to
0c6d79f
Compare
0a35857
to
19cf464
Compare
19cf464
to
d2bc6ad
Compare
* DM is 32 bit only | ||
*/ | ||
printf(" DM | MS | P32 | P64\n"); | ||
printf("T0 = %2d %d || 1 1 | 1 1 | 1 1 | 1 1\n", cast(int)T0.sizeof, cast(int)T0.alignof); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't it be better to just use asserts here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's just easier to do it this way. The text representations are easier to edit, compare and understand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't really help my end because the testsuite framework I use doesn't support comparing ad-hoc text, that can be worked around.
fba1618
to
1c046b2
Compare
ping @ibuclaw |
1c046b2
to
a593261
Compare
Since @ibuclaw and I already did the work to implement bitfields for ImportC, and they'll be of significant value to add to D, might as well enable them!