Skip to content

Implement support for bitfields wider than 64 bits#306

Open
davispuh wants to merge 1 commit intojacob-carlborg:masterfrom
davispuh:bits
Open

Implement support for bitfields wider than 64 bits#306
davispuh wants to merge 1 commit intojacob-carlborg:masterfrom
davispuh:bits

Conversation

@davispuh
Copy link
Copy Markdown

C allows to have structs like this:

#include <stdint.h>

typedef union {
  struct {
    uint32_t    a  : 16;
    uint32_t    b  : 16;
    uint32_t    c  : 8;
    uint32_t    d  : 8;
    uint32_t    e  : 16;
    uint32_t    f  : 32;
    uint32_t    g  : 32;
  } Bits;
  struct {
    uint64_t    Uint64;
    uint64_t    Uint64_1;
  } Uint128;
} S;

Currently it's converted like this:

union S
{
    struct _Anonymous_0
    {
        import std.bitmanip : bitfields;

        mixin(bitfields!(
            uint, "a", 16,
            uint, "b", 16,
            uint, "c", 8,
            uint, "d", 8,
            uint, "e", 16,
            uint, "f", 32,
            uint, "g", 32));
    }

    _Anonymous_0 Bits;

    struct _Anonymous_1
    {
        ulong Uint64;
        ulong Uint64_1;
    }

    _Anonymous_1 Uint128;
}

But unfortunately D doesn't support bitfields wider than 64-bits:

/usr/include/dlang/ldc/std/bitmanip.d(92): Error: shift by 64 is outside the range `0..63`
        enum ulong maskAllElse = ((~0uL) >> (64 - len)) << offset;
                                                        ^
/usr/include/dlang/ldc/std/bitmanip.d(180): Error: template instance `std.bitmanip.createAccessors!("_a_b_c_d_e_f_g_bf", uint, "f", 32LU, 64LU)` error instantiating
            = createAccessors!(store, Ts[0], Ts[1], Ts[2], offset)

This PR fixes this issue by splitting such cases. Producing D code:

union S
{
    struct _Anonymous_0
    {
        import std.bitmanip : bitfields;

        mixin(bitfields!(
            uint, "a", 16,
            uint, "b", 16,
            uint, "c", 8,
            uint, "d", 8,
            uint, "e", 16));

        mixin(bitfields!(
            uint, "f", 32,
            uint, "g", 32));
    }

    _Anonymous_0 Bits;

    struct _Anonymous_1
    {
        ulong Uint64;
        ulong Uint64_1;
    }

    _Anonymous_1 Uint128;
}

Copilot AI review requested due to automatic review settings March 19, 2026 21:54
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread dstep/translator/Record.d
Comment on lines +115 to +142
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 ? "));" : ",");
}
};
}
Copy link

Copilot AI Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment thread dstep/translator/Record.d
Comment on lines +115 to +142
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 ? "));" : ",");
}
};
}
Copy link

Copilot AI Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
@jacob-carlborg
Copy link
Copy Markdown
Owner

Perhaps time to move to the built in syntax for bit fields.

Copy link
Copy Markdown
Owner

@jacob-carlborg jacob-carlborg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no test case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants