Skip to content

Commit

Permalink
ImportC: posix bit field layout
Browse files Browse the repository at this point in the history
  • Loading branch information
WalterBright committed Aug 27, 2021
1 parent 669ae8a commit 60c1a0d
Show file tree
Hide file tree
Showing 7 changed files with 361 additions and 22 deletions.
74 changes: 61 additions & 13 deletions src/dmd/declaration.d
Original file line number Diff line number Diff line change
Expand Up @@ -1736,7 +1736,16 @@ extern (C++) class BitFieldDeclaration : VarDeclaration

override final void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
{
//printf("BitFieldDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars());
//printf("BitFieldDeclaration::setFieldOffset(ad: %s, field: %s)\n", ad.toChars(), toChars());
static void print(const ref FieldState fieldState)
{
printf("FieldState.offset = %d bytes\n", fieldState.offset);
printf(" .fieldOffset = %d bytes\n", fieldState.fieldOffset);
printf(" .bitOffset = %d bits\n", fieldState.bitOffset);
printf(" .fieldSize = %d bytes\n", fieldState.fieldSize);
printf(" .inFlight = %d\n\n", fieldState.inFlight);
}
//print(fieldState);

Type t = type.toBasetype();

Expand All @@ -1758,11 +1767,32 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
if (fieldWidth > memsize * 8)
error(loc, "bit field width %d is larger than type", fieldWidth);

if (target.c.bitFieldStyle == BitFieldStyle.Gcc_Clang)
{
if (ad.alignsize < memalignsize)
ad.alignsize = memalignsize;
}

void startNewField()
{
uint alignsize;
if (target.c.bitFieldStyle == BitFieldStyle.Gcc_Clang)
{
if (fieldWidth > 32)
alignsize = memalignsize;
else if (fieldWidth > 16)
alignsize = 4;
else if (fieldWidth > 8)
alignsize = 2;
else
alignsize = 1;
}
else
alignsize = memalignsize;

offset = AggregateDeclaration.placeField(
&fieldState.offset,
memsize, memalignsize, alignment,
memsize, alignsize, alignment,
&ad.structsize, &ad.alignsize,
isunion);

Expand All @@ -1772,23 +1802,36 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
fieldState.fieldSize = memsize;
}

if (!fieldState.inFlight || fieldWidth == 0)
if (fieldWidth == 0)
{
fieldState.inFlight = false;
return;
}
else if (!fieldState.inFlight)
{
startNewField();
}
else if (target.os & Target.OS.Posix)
else if (target.c.bitFieldStyle == BitFieldStyle.Gcc_Clang)
{
if (fieldState.fieldSize == 8 &&
fieldState.bitOffset + fieldWidth > 64)
if (fieldState.bitOffset + fieldWidth > memsize * 8)
{
//printf("start1 fieldState.bitOffset:%u fieldWidth:%u memsize:%u\n", fieldState.bitOffset, fieldWidth, memsize);
startNewField();
}
else if (fieldState.bitOffset + fieldWidth > int.sizeof * 8)
else
{
startNewField();
// if alignment boundary is crossed
uint start = fieldState.fieldOffset * 8 + fieldState.bitOffset;
uint end = start + fieldWidth;
//printf("%s start: %d end: %d memalignsize: %d\n", ad.toChars(), start, end, memalignsize);
if (start / (memalignsize * 8) != (end - 1) / (memalignsize * 8))
{
//printf("alignment is crossed\n");
startNewField();
}
}
}
else if (target.os == Target.OS.Windows)
else if (target.c.bitFieldStyle == BitFieldStyle.Dm_Ms)
{
if (memsize != fieldState.fieldSize ||
fieldState.bitOffset + fieldWidth > fieldState.fieldSize * 8)
Expand All @@ -1803,13 +1846,18 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
bitOffset = fieldState.bitOffset;

const pastField = bitOffset + fieldWidth;
if (target.os & Target.OS.Posix)
if (target.c.bitFieldStyle == BitFieldStyle.Gcc_Clang)
{
fieldState.fieldSize = (pastField + 7) / 8;
ad.structsize = offset + fieldState.fieldSize;
auto size = (pastField + 7) / 8;
fieldState.fieldSize = size;
//printf(" offset: %d, size: %d\n", offset, size);
ad.structsize = offset + size;
}
else
fieldState.fieldSize = memsize;
//printf("at end: ad.structsize = %d\n", cast(int)ad.structsize);
//print(fieldState);

//fieldState.fieldSize = memsize;
if (!isunion)
{
fieldState.bitOffset = pastField;
Expand Down
8 changes: 5 additions & 3 deletions src/dmd/dsymbol.d
Original file line number Diff line number Diff line change
Expand Up @@ -225,11 +225,13 @@ enum : int
*/
struct FieldState
{
uint offset; /// offset for next field
uint offset; /// byte offset for next field

uint fieldOffset; /// offset for the start of the bit field
uint fieldOffset; /// byte offset for the start of the bit field
uint fieldSize; /// byte size of field
uint fieldAlign; /// byte alignment of field
uint bitOffset; /// bit offset for field
uint fieldSize; /// size of field in bytes

bool inFlight; /// bit field is in flight
}

Expand Down
4 changes: 3 additions & 1 deletion src/dmd/dsymbol.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,10 @@ struct FieldState
unsigned offset;

unsigned fieldOffset;
unsigned fieldSize;
unsigned fieldAlign;
unsigned bitOffset;
unsigned fieldSice;

bool inFlight;
};

Expand Down
11 changes: 7 additions & 4 deletions src/dmd/frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -2483,22 +2483,25 @@ struct FieldState final
{
uint32_t offset;
uint32_t fieldOffset;
uint32_t bitOffset;
uint32_t fieldSize;
uint32_t fieldAlign;
uint32_t bitOffset;
bool inFlight;
FieldState() :
offset(),
fieldOffset(),
bitOffset(),
fieldSize(),
fieldAlign(),
bitOffset(),
inFlight()
{
}
FieldState(uint32_t offset, uint32_t fieldOffset = 0u, uint32_t bitOffset = 0u, uint32_t fieldSize = 0u, bool inFlight = false) :
FieldState(uint32_t offset, uint32_t fieldOffset = 0u, uint32_t fieldSize = 0u, uint32_t fieldAlign = 0u, uint32_t bitOffset = 0u, bool inFlight = false) :
offset(offset),
fieldOffset(fieldOffset),
bitOffset(bitOffset),
fieldSize(fieldSize),
fieldAlign(fieldAlign),
bitOffset(bitOffset),
inFlight(inFlight)
{}
};
Expand Down
8 changes: 7 additions & 1 deletion src/dmd/todt.d
Original file line number Diff line number Diff line change
Expand Up @@ -900,7 +900,13 @@ private void membersToDt(AggregateDeclaration ad, ref DtBuilder dtb,
finishInFlightBitField();
}
// This relies on all bit fields in the same storage location have the same type
bitFieldSize = cast(uint)vd.type.size();
if (bf)
{
if (target.c.bitFieldStyle == BitFieldStyle.Gcc_Clang)
bitFieldSize = (bitOffset + bf.fieldWidth + 7) / 8;
else
bitFieldSize = cast(uint)vd.type.size();
}

assert(offset <= vd.offset);
if (offset < vd.offset)
Expand Down
139 changes: 139 additions & 0 deletions test/runnable/bitfieldsposix32.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/* test bitfields
* DISABLED: win32 win64 linux64 freebsd64 osx64
* TEST_OUTPUT:
---
T0 = 1 1
T1 = 2 2
T2 = 4 4
T3 = 8 4
T4 = 12 4
T5 = 8 4
S1 = 4 4
S2 = 4 4
S3 = 4 4
S4 = 4 4
S5 = 4 4
S6 = 2 2
S7 = 4 4
S8 = 2 2
S8A = 2 2
S8B = 2 2
S8C = 4 4
S9 = 4 2
S10 = 0 1
S11 = 0 1
S12 = 4 4
S13 = 8 4
S14 = 8 4
S15 = 4 4
A0 = 12 4
S9 = x30200
S14 = x300000201
S15 = xe01
A0 = xf00000001
---
*/

int printf(const char *fmt, ...);
void exit(int);

void assert(int n, int b)
{
if (!b)
{
printf("assert fail %d\n", n);
exit(1);
}
}

/*************************************************************/

struct T0 { char x:1; }; // 1 1
struct T1 { short x:1; }; // 2 2
struct T2 { int x:1; }; // 4 4
struct T3 { char a,b,c,d; long long x:1; }; // 8 8
struct T4 { char a,b,c,d,e,f,g,h; long long x:1; }; // 16 8
struct T5 { char a,b,c,d,e,f,g; long long x:1; }; // 8 8
struct S1 { long long int f:1; }; // 8 8
struct S2 { int x:1; int y:1; }; // 4 4
struct S3 { short c; int x:1; unsigned y:1; }; // 4 4
struct S4 { int x:1; short y:1; }; // 4 4
struct S5 { short x:1; int y:1; }; // 4 4
struct S6 { short x:1; short y:1; }; // 2 2
struct S7 { short x:1; int y:1; long long z:1; }; // 8 8
struct S8 { char a; char b:1; short c:2; }; // 2 2
struct S8A { char b:1; short c:2; }; // 2 2
struct S8B { char a; short b:1; char c:2; }; // 2 2
struct S8C { char a; int b:1; }; // 4 4
struct S9 { char a; char b:2; short c:9; }; // 4 2 x30201
struct S10 { }; // 0 1
struct S11 { int :0; }; // 0 1
struct S12 { int :0; int x; }; // 4 4
struct S13 { unsigned x:12; unsigned x1:1; unsigned x2:1; unsigned x3:1; unsigned x4:1; int w; }; // 8 4
struct S14 { char a; char b:4; int c:30; }; // 8 4
struct S15 { char a; char b:2; int c:9; }; // 4 4 xe01
struct A0 { int a; long long b:34, c:4; }; // 12 4 (32 bit) 16 8 (64 bit)

int main()
{
printf("T0 = %d %d\n", (int)sizeof(struct T0), (int)_Alignof(struct T0));
printf("T1 = %d %d\n", (int)sizeof(struct T1), (int)_Alignof(struct T1));
printf("T2 = %d %d\n", (int)sizeof(struct T2), (int)_Alignof(struct T2));
printf("T3 = %d %d\n", (int)sizeof(struct T3), (int)_Alignof(struct T3));
printf("T4 = %d %d\n", (int)sizeof(struct T4), (int)_Alignof(struct T4));
printf("T5 = %d %d\n", (int)sizeof(struct T5), (int)_Alignof(struct T5));
printf("S1 = %d %d\n", (int)sizeof(struct S1), (int)_Alignof(struct S1));
printf("S2 = %d %d\n", (int)sizeof(struct S2), (int)_Alignof(struct S2));
printf("S3 = %d %d\n", (int)sizeof(struct S3), (int)_Alignof(struct S3));
printf("S4 = %d %d\n", (int)sizeof(struct S4), (int)_Alignof(struct S4));
printf("S5 = %d %d\n", (int)sizeof(struct S5), (int)_Alignof(struct S5));
printf("S6 = %d %d\n", (int)sizeof(struct S6), (int)_Alignof(struct S6));
printf("S7 = %d %d\n", (int)sizeof(struct S7), (int)_Alignof(struct S7));
printf("S8 = %d %d\n", (int)sizeof(struct S8), (int)_Alignof(struct S8));
printf("S8A = %d %d\n", (int)sizeof(struct S8A), (int)_Alignof(struct S8A));
printf("S8B = %d %d\n", (int)sizeof(struct S8B), (int)_Alignof(struct S8B));
printf("S8C = %d %d\n", (int)sizeof(struct S8C), (int)_Alignof(struct S8C));
printf("S9 = %d %d\n", (int)sizeof(struct S9), (int)_Alignof(struct S9));
printf("S10 = %d %d\n", (int)sizeof(struct S10), (int)_Alignof(struct S10));
printf("S11 = %d %d\n", (int)sizeof(struct S11), (int)_Alignof(struct S11));
printf("S12 = %d %d\n", (int)sizeof(struct S12), (int)_Alignof(struct S12));
printf("S13 = %d %d\n", (int)sizeof(struct S13), (int)_Alignof(struct S13));
printf("S14 = %d %d\n", (int)sizeof(struct S14), (int)_Alignof(struct S14));
printf("S15 = %d %d\n", (int)sizeof(struct S15), (int)_Alignof(struct S15));
printf("A0 = %d %d\n", (int)sizeof(struct A0), (int)_Alignof(struct A0));

{
struct S9 s;
*(unsigned *)&s = 0;
s.b = 2; s.c = 3;
unsigned x = *(unsigned *)&s;
printf("S9 = x%x\n", x);
}
{
struct S14 s = { 1, 2, 3 };
*(long long *)&s = 0;
s.a = 1;
s.b = 2;
s.c = 3;
unsigned long long v = *(unsigned long long *)&s;
printf("S14 = x%llx\n", v);
}
{
struct S15 s = { 1,2,3 };
*(unsigned *)&s = 0;
s.a = 1; s.b = 2; s.c = 3;
unsigned x = *(unsigned *)&s;
printf("S15 = x%x\n", x);
}
{
struct A0 s;
*(long long *)&s = 0;
s.a = 1; s.b = 15;
long long x = *(long long *)&s;
printf("A0 = x%llx\n", x);
}

return 0;
}


0 comments on commit 60c1a0d

Please sign in to comment.