Implement support for bitfields wider than 64 bits#306
Implement support for bitfields wider than 64 bits#306davispuh wants to merge 1 commit intojacob-carlborg:masterfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the C→D record translator to support C bitfield sequences whose total width exceeds 64 bits by splitting them into multiple std.bitmanip.bitfields mixins, avoiding D compilation errors when offsets would reach 64.
Changes:
- Split translated bitfield lists into multiple
bitfields!mixins when the cumulative width would exceed 64 bits. - Preserve existing codegen behavior for <=64-bit bitfield sequences while enabling wider overall sequences to compile.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| BitField[][] bitFieldsList = [[]]; | ||
| int bits = 0; | ||
| int i = 0; | ||
| foreach (bitField; bitFields) | ||
| { | ||
| if (bits + bitField.width > 64) | ||
| { | ||
| output.singleLine( | ||
| `%s, "%s", %s%s`, | ||
| bitField.type, | ||
| bitField.field, | ||
| bitField.width, | ||
| index + 1 == bitFields.length ? "));" : ","); | ||
| bits = 0; | ||
| bitFieldsList ~= [[]]; | ||
| i++; | ||
| } | ||
| }; | ||
| bits += bitField.width; | ||
| bitFieldsList[i] ~= bitField; | ||
| } | ||
| foreach (bitFieldsItem; bitFieldsList) | ||
| { | ||
| output.multiLine("mixin(bitfields!(") in { | ||
| foreach (index, bitField; enumerate(bitFieldsItem)) | ||
| { | ||
| output.singleLine( | ||
| `%s, "%s", %s%s`, | ||
| bitField.type, | ||
| bitField.field, | ||
| bitField.width, | ||
| index + 1 == bitFieldsItem.length ? "));" : ","); | ||
| } | ||
| }; | ||
| } |
There was a problem hiding this comment.
The splitting logic can produce empty bitFieldsItem groups (e.g., if a bitfield width itself is > 64, or if translateBitFields returns an empty array for sequences of only :0 bitfields). Emitting mixin(bitfields!(... with no field triplets will generate invalid D code. Consider guarding against bitFieldsItem.length == 0 (skip), and explicitly handling bitField.width > 64 with a clear error or a different translation strategy so the output always compiles.
| BitField[][] bitFieldsList = [[]]; | ||
| int bits = 0; | ||
| int i = 0; | ||
| foreach (bitField; bitFields) | ||
| { | ||
| if (bits + bitField.width > 64) | ||
| { | ||
| output.singleLine( | ||
| `%s, "%s", %s%s`, | ||
| bitField.type, | ||
| bitField.field, | ||
| bitField.width, | ||
| index + 1 == bitFields.length ? "));" : ","); | ||
| bits = 0; | ||
| bitFieldsList ~= [[]]; | ||
| i++; | ||
| } | ||
| }; | ||
| bits += bitField.width; | ||
| bitFieldsList[i] ~= bitField; | ||
| } | ||
| foreach (bitFieldsItem; bitFieldsList) | ||
| { | ||
| output.multiLine("mixin(bitfields!(") in { | ||
| foreach (index, bitField; enumerate(bitFieldsItem)) | ||
| { | ||
| output.singleLine( | ||
| `%s, "%s", %s%s`, | ||
| bitField.type, | ||
| bitField.field, | ||
| bitField.width, | ||
| index + 1 == bitFieldsItem.length ? "));" : ","); | ||
| } | ||
| }; | ||
| } |
There was a problem hiding this comment.
This change introduces new behavior (splitting bitfield sequences into multiple bitfields! mixins when the total width exceeds 64), but there is no unit test covering the >64-bit case. Adding a focused test in tests/unit/BitFieldsTests.d (e.g., 3+3+... totaling >64, or the example from the PR description) would prevent regressions and verify the generated output format.
|
Perhaps time to move to the built in syntax for bit fields. |
C allows to have structs like this:
Currently it's converted like this:
But unfortunately D doesn't support bitfields wider than 64-bits:
This PR fixes this issue by splitting such cases. Producing D code: