Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 13 additions & 77 deletions dstep/translator/Record.d
Original file line number Diff line number Diff line change
Expand Up @@ -35,95 +35,34 @@ void translatePackedAttribute(Output output, Context context, Cursor cursor)
output.singleLine("align (1):");
}

struct BitField
{
string type;
string field;
uint width;
}

BitField[] translateBitFields(
void translateBitFields(
Output output,
Context context,
Cursor[] cursors)
{
static void pad(ref BitField[] bitFields, uint totalWidth)
{
uint padding = 0;

for (uint size = 8; size <= 64; size *= 2)
{
if (totalWidth <= size)
{
padding = size - totalWidth;
break;
}
}

if (padding != 0)
bitFields ~= BitField("uint", "", padding);
}
import std.range;

BitField[] bitFields;
uint totalWidth = 0;
assert(cursors.length > 0);

foreach (cursor; cursors)
{
auto type = translateType(context, cursor).makeString();
auto name = cursor.spelling();
auto width = cursor.bitFieldWidth();
auto typeWidth = cast(uint)(cursor.type.sizeOf * 8);

if (width == 0)
if (typeWidth > 64)
{
pad(bitFields, totalWidth);
totalWidth = 0;
output.singleLine("%s %s; // only %s bits used, struct's layout incompatible with C", type, name, width);
}
else
{
bitFields ~= BitField(
translateType(context, cursor).makeString(),
cursor.spelling(),
width);

totalWidth += width;
if (name.empty)
output.singleLine("%s : %d;", type, width);
else
output.singleLine("%s %s : %d;", type, name, width);
}
}

pad(bitFields, totalWidth);

return bitFields;
}

void translateBitFields(
Output output,
Context context,
Cursor[] cursors)
{
import std.range;

auto bitFields = translateBitFields(context, cursors);

if (bitFields.length == 1)
{
auto bitField = bitFields.front;

output.singleLine(
`mixin(bitfields!(%s, "%s", %s));`,
bitField.type,
bitField.field,
bitField.width);
}
else
{
output.multiLine("mixin(bitfields!(") in {
foreach (index, bitField; enumerate(bitFields))
{
output.singleLine(
`%s, "%s", %s%s`,
bitField.type,
bitField.field,
bitField.width,
index + 1 == bitFields.length ? "));" : ",");
}
};
}
}

void translateRecordDef(
Expand Down Expand Up @@ -160,9 +99,6 @@ void translateRecordDef(
auto declarations = cursor.children
.filter!(cursor => cursor.isDeclaration)();

if (declarations.any!(cursor => cursor.isBitField()))
output.singleLine("import std.bitmanip : bitfields;");

translatePackedAttribute(output, context, cursor);

foreach (chunk; declarations.chunkBy!predicate())
Expand Down
182 changes: 121 additions & 61 deletions tests/unit/BitFieldsTests.d
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,7 @@ extern (C):

struct Foo
{
import std.bitmanip : bitfields;

mixin(bitfields!(
int, "x", 4,
uint, "", 4));
int x : 4;
}
D");

Expand All @@ -44,8 +40,7 @@ extern (C):

struct Foo
{
import std.bitmanip : bitfields;
mixin(bitfields!(int, "x", 8));
int x : 8;
}
D");

Expand All @@ -65,12 +60,9 @@ extern (C):

struct bitfield
{
import std.bitmanip : bitfields;

mixin(bitfields!(
uint, "one", 4,
uint, "two", 8,
uint, "", 4));
uint one : 4;
uint two : 8;
uint : 4;
}
D");
}
Expand All @@ -86,14 +78,10 @@ extern (C):

struct Foo
{
import std.bitmanip : bitfields;

mixin(bitfields!(
ubyte, "a", 3,
ubyte, "", 2,
ubyte, "b", 6,
ubyte, "c", 2,
uint, "", 3));
ubyte a : 3;
ubyte : 2;
ubyte b : 6;
ubyte c : 2;
}
D");

Expand All @@ -111,11 +99,7 @@ extern (C):

struct Foo
{
import std.bitmanip : bitfields;

mixin(bitfields!(
short, "a", 4,
uint, "", 4));
short a : 4;

char b;
}
Expand All @@ -136,13 +120,8 @@ extern (C):

struct Foo
{
import std.bitmanip : bitfields;

short a;

mixin(bitfields!(
char, "b", 7,
uint, "", 1));
char b : 7;

char[1] c;
}
Expand All @@ -165,16 +144,11 @@ extern (C):

struct Foo
{
import std.bitmanip : bitfields;

short a;
char b;

mixin(bitfields!(
int, "c", 1,
int, "d", 4,
int, "e", 7,
uint, "", 4));
int c : 1;
int d : 4;
int e : 7;
}
D");

Expand All @@ -197,17 +171,12 @@ extern (C):

struct Foo
{
import std.bitmanip : bitfields;

short a;

mixin(bitfields!(
int, "b", 1,
int, "c", 4,
int, "d", 3,
int, "e", 7,
int, "f", 25,
uint, "", 24));
int b : 1;
int c : 4;
int d : 3;
int e : 7;
int f : 25;

char g;
}
Expand Down Expand Up @@ -235,23 +204,114 @@ extern (C):

struct Foo
{
import std.bitmanip : bitfields;

short a;

mixin(bitfields!(
int, "b", 1,
int, "c", 4,
int, "d", 3));
int b : 1;
int c : 4;
int d : 3;

c_long e;

mixin(bitfields!(
int, "f", 7,
int, "g", 25));
int f : 7;
int g : 25;

char h;
}
D");

};

unittest
{
assertTranslates(q"C
struct Foo {
unsigned int a : 16;
unsigned int b : 16;
unsigned int c : 8;
unsigned int d : 8;
unsigned int e : 16;
unsigned long long f : 42;
};
C",q"D
extern (C):

struct Foo
{
uint a : 16;
uint b : 16;
uint c : 8;
uint d : 8;
uint e : 16;
ulong f : 42;
}
D");

}

unittest
{
assertTranslates(q"C
struct Foo {
int a : 4;
int b : 8;
int c : 12;
};
C",q"D
extern (C):

struct Foo
{
int a : 4;
int b : 8;
int c : 12;
}
D");

}

unittest
{
assertTranslates(q"C
struct Foo {
int a : 1;
int b : 1;
int c : 1;
int d : 1;
};
C",q"D
extern (C):

struct Foo
{
int a : 1;
int b : 1;
int c : 1;
int d : 1;
}
D");

}

// Known limitation that layout won't match C
// Incredibly complex to get this right so leaving like this
unittest
{
assertTranslates(q"C
struct Foo
{
__int128 a : 50;
int b : 10;
__int128 c : 62;
};
C",q"D
import core.int128;

extern (C):

struct Foo
{
Cent a; // only 50 bits used, struct's layout incompatible with C
int b : 10;
Cent c; // only 62 bits used, struct's layout incompatible with C
}
D");

}
Loading