Skip to content
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

Fix bugzilla 24592 - ImportC: Bitfield layout wrong for int64 on 32-b… #16590

Merged
merged 1 commit into from
Jun 17, 2024
Merged
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
6 changes: 3 additions & 3 deletions compiler/src/dmd/dsymbolsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -7270,18 +7270,18 @@
// If the bit-field spans more units of alignment than its type,
// start a new field at the next alignment boundary.
if (fieldState.bitOffset == fieldState.fieldSize * 8 &&
fieldState.bitOffset + bfd.fieldWidth > memalignsize * 8)
fieldState.bitOffset + bfd.fieldWidth > memsize * 8)

Check warning on line 7273 in compiler/src/dmd/dsymbolsem.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/dsymbolsem.d#L7273

Added line #L7273 was not covered by tests
{
if (log) printf("more units of alignment than its type\n");
startNewField(); // the bit field is full
}
else
{
// if alignment boundary is crossed
uint start = fieldState.fieldOffset * 8 + fieldState.bitOffset;
uint start = (fieldState.fieldOffset * 8 + fieldState.bitOffset) % (memalignsize * 8);

Check warning on line 7281 in compiler/src/dmd/dsymbolsem.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/dsymbolsem.d#L7281

Added line #L7281 was not covered by tests
uint end = start + bfd.fieldWidth;
//printf("%s start: %d end: %d memalignsize: %d\n", ad.toChars(), start, end, memalignsize);
if (start / (memalignsize * 8) != (end - 1) / (memalignsize * 8))
if (start / (memsize * 8) != (end - 1) / (memsize * 8))

Check warning on line 7284 in compiler/src/dmd/dsymbolsem.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/dsymbolsem.d#L7284

Added line #L7284 was not covered by tests
{
if (log) printf("alignment is crossed\n");
startNewField();
Expand Down
7 changes: 4 additions & 3 deletions compiler/src/dmd/e2ir.d
Original file line number Diff line number Diff line change
Expand Up @@ -3135,12 +3135,13 @@
{
// adjust bit offset for bitfield so the type tym encloses the bitfield
const szbits = tysize(tym) * 8;
uint memalignsize = target.fieldalign(dve.type);
auto bitOffset = bf.bitOffset;
if (bitOffset + bf.fieldWidth > szbits)
{
const advance = bf.bitOffset / szbits;
voffset += advance;
bitOffset -= advance * 8;
const advance = bf.bitOffset / (memalignsize * 8);
voffset += advance * memalignsize;
bitOffset -= advance * memalignsize * 8;

Check warning on line 3144 in compiler/src/dmd/e2ir.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/e2ir.d#L3142-L3144

Added lines #L3142 - L3144 were not covered by tests
assert(bitOffset + bf.fieldWidth <= szbits);
}
//printf("voffset %u bitOffset %u fieldWidth %u bits %u\n", cast(uint)voffset, bitOffset, bf.fieldWidth, szbits);
Expand Down
12 changes: 12 additions & 0 deletions compiler/test/runnable/bitfieldsposix32.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ A8 = 8 4 | 8 4
A9 = 16 4 | 16 4
A10 = 2 2 | 2 2
A11 = 12 4 | 12 4
Issue24592a = 8 4 | 8 4
Issue24592b = 12 4 | 12 4
Issue24592c = 24 4 | 24 4
Issue24592d = 12 4 | 12 4
S9 = x30200
S14 = x300000201
S15 = xe01
Expand Down Expand Up @@ -112,6 +116,10 @@ struct A9 { unsigned short a:8; long b:16; // 16 4 (32 bit) 16 8 (64 b
struct A10 { unsigned short a:8; char b; }; // 2 2
struct A11 { char a; int b:5, c:11, :0, d:8; // 12 4
struct { int ee:8; } e; };
struct Issue24592a { unsigned long long a:20, b:20, c:24; };
struct Issue24592b { unsigned int x; unsigned long long a:20, b:20, c:24; };
struct Issue24592c { unsigned long long a:20, b:32, c:32, d:32, e:32, f:32; };
struct Issue24592d { unsigned long long a:10, b:16, c:16, d:16, e:16, f:16; };

int main()
{
Expand Down Expand Up @@ -154,6 +162,10 @@ int main()
printf("A9 = %d %d | 16 4\n", (int)sizeof(struct A9), (int)_Alignof(struct A9));
printf("A10 = %d %d | 2 2\n", (int)sizeof(struct A10), (int)_Alignof(struct A10));
printf("A11 = %d %d | 12 4\n", (int)sizeof(struct A11), (int)_Alignof(struct A11));
printf("Issue24592a = %d %d | 8 4\n", (int)sizeof(struct Issue24592a), (int)_Alignof(struct Issue24592a));
printf("Issue24592b = %d %d | 12 4\n", (int)sizeof(struct Issue24592b), (int)_Alignof(struct Issue24592b));
printf("Issue24592c = %d %d | 24 4\n", (int)sizeof(struct Issue24592c), (int)_Alignof(struct Issue24592c));
printf("Issue24592d = %d %d | 12 4\n", (int)sizeof(struct Issue24592d), (int)_Alignof(struct Issue24592d));

{
struct S9 s;
Expand Down
12 changes: 12 additions & 0 deletions compiler/test/runnable/bitfieldsposix64.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ A8 = 8 8 | 8 8
A9 = 16 8 | 16 8
A10 = 2 2 | 2 2
A11 = 12 4 | 12 4
Issue24592a = 8 8 | 8 8
Issue24592b = 16 8 | 16 8
Issue24592c = 24 8 | 24 8
Issue24592d = 16 8 | 16 8
S9 = x30200
S14 = x300000201
S15 = xe01
Expand Down Expand Up @@ -112,6 +116,10 @@ struct A9 { unsigned short a:8; long b:16; // 16 4 (32 bit) 16 8 (64 b
struct A10 { unsigned short a:8; char b; }; // 2 2
struct A11 { char a; int b:5, c:11, :0, d:8; // 12 4
struct { int ee:8; } e; };
struct Issue24592a { unsigned long long a:20, b:20, c:24; };
struct Issue24592b { unsigned int x; unsigned long long a:20, b:20, c:24; };
struct Issue24592c { unsigned long long a:20, b:32, c:32, d:32, e:32, f:32; };
struct Issue24592d { unsigned long long a:10, b:16, c:16, d:16, e:16, f:16; };

int main()
{
Expand Down Expand Up @@ -154,6 +162,10 @@ int main()
printf("A9 = %d %d | 16 8\n", (int)sizeof(struct A9), (int)_Alignof(struct A9));
printf("A10 = %d %d | 2 2\n", (int)sizeof(struct A10), (int)_Alignof(struct A10));
printf("A11 = %d %d | 12 4\n", (int)sizeof(struct A11), (int)_Alignof(struct A11));
printf("Issue24592a = %d %d | 8 8\n", (int)sizeof(struct Issue24592a), (int)_Alignof(struct Issue24592a));
printf("Issue24592b = %d %d | 16 8\n", (int)sizeof(struct Issue24592b), (int)_Alignof(struct Issue24592b));
printf("Issue24592c = %d %d | 24 8\n", (int)sizeof(struct Issue24592c), (int)_Alignof(struct Issue24592c));
printf("Issue24592d = %d %d | 16 8\n", (int)sizeof(struct Issue24592d), (int)_Alignof(struct Issue24592d));

{
struct S9 s;
Expand Down
84 changes: 84 additions & 0 deletions compiler/test/runnable_cxx/extra-files/testbitfields_cpp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
extern "C"
{
#include "testbitfields_importc.c"
}

#include <stdio.h>
#include <string.h>

template<typename T>
size_t getStructSize();
template<typename T>
size_t getStructAlign();
template<typename T>
void resetBitfield(T &data, const char *member);

#define BEGIN_STRUCT(S) \
template<> \
size_t getStructSize<S>() \
{ \
return sizeof(S); \
} \
template<> \
size_t getStructAlign<S>() \
{ \
return alignof(S); \
} \
template<> \
void resetBitfield<S>(S &data, const char *member) \
{

#define FIELD(name) if (strcmp(member, #name) == 0) data.name = 0;
#define END_STRUCT }

BEGIN_STRUCT(T0) FIELD(x) END_STRUCT
BEGIN_STRUCT(T1) FIELD(x) END_STRUCT
BEGIN_STRUCT(T2) FIELD(x) END_STRUCT
BEGIN_STRUCT(T3) FIELD(a) FIELD(b) FIELD(c) FIELD(d) FIELD(x) END_STRUCT
BEGIN_STRUCT(T4) FIELD(a) FIELD(b) FIELD(c) FIELD(d) FIELD(e) FIELD(f) FIELD(g) FIELD(h) FIELD(x) END_STRUCT
BEGIN_STRUCT(T5) FIELD(a) FIELD(b) FIELD(c) FIELD(d) FIELD(e) FIELD(f) FIELD(g) FIELD(x) END_STRUCT
BEGIN_STRUCT(S1) FIELD(f) END_STRUCT
BEGIN_STRUCT(S2) FIELD(x) FIELD(y) END_STRUCT
BEGIN_STRUCT(S3) FIELD(c) FIELD(x) FIELD(y) END_STRUCT
BEGIN_STRUCT(S4) FIELD(x) FIELD(y) END_STRUCT
BEGIN_STRUCT(S5) FIELD(x) FIELD(y) END_STRUCT
BEGIN_STRUCT(S6) FIELD(x) FIELD(y) END_STRUCT
BEGIN_STRUCT(S7) FIELD(x) FIELD(y) FIELD(z) END_STRUCT
BEGIN_STRUCT(S8) FIELD(a) FIELD(b) FIELD(c) END_STRUCT
BEGIN_STRUCT(S8A) FIELD(b) FIELD(c) END_STRUCT
BEGIN_STRUCT(S8B) FIELD(a) FIELD(b) FIELD(c) END_STRUCT
BEGIN_STRUCT(S8C) FIELD(a) FIELD(b) END_STRUCT
BEGIN_STRUCT(S9) FIELD(a) FIELD(b) FIELD(c) END_STRUCT
//BEGIN_STRUCT(S10) END_STRUCT
//BEGIN_STRUCT(S11) END_STRUCT
BEGIN_STRUCT(S12) FIELD(x) END_STRUCT
BEGIN_STRUCT(S13) FIELD(x) FIELD(x1) FIELD(x2) FIELD(x3) FIELD(x4) FIELD(w) END_STRUCT
BEGIN_STRUCT(S14) FIELD(a) FIELD(b) FIELD(c) END_STRUCT
BEGIN_STRUCT(S15) FIELD(a) FIELD(b) FIELD(c) END_STRUCT
BEGIN_STRUCT(S16) END_STRUCT
BEGIN_STRUCT(S17) FIELD(a) END_STRUCT
BEGIN_STRUCT(S18) FIELD(a) FIELD(b) END_STRUCT
BEGIN_STRUCT(A0) FIELD(a) FIELD(b) FIELD(c) END_STRUCT
BEGIN_STRUCT(A1) FIELD(a) FIELD(b) FIELD(c) END_STRUCT
BEGIN_STRUCT(A2) FIELD(a) FIELD(b) FIELD(c) FIELD(d)
FIELD(e) END_STRUCT
BEGIN_STRUCT(A3) FIELD(a) FIELD(b) FIELD(c) FIELD(d)
FIELD(e) END_STRUCT
BEGIN_STRUCT(A4) FIELD(a) FIELD(b)
FIELD(c) END_STRUCT
BEGIN_STRUCT(A5) FIELD(a) FIELD(b) END_STRUCT
BEGIN_STRUCT(A6) FIELD(a) FIELD(b) END_STRUCT
BEGIN_STRUCT(A7) FIELD(a) FIELD(b) FIELD(c)
FIELD(d) END_STRUCT
BEGIN_STRUCT(A8) FIELD(a) FIELD(b)
FIELD(c) END_STRUCT
BEGIN_STRUCT(A9) FIELD(a) FIELD(b)
FIELD(c) FIELD(d)
FIELD(e) FIELD(f) END_STRUCT
BEGIN_STRUCT(A10) FIELD(a) FIELD(b) END_STRUCT
BEGIN_STRUCT(A11) FIELD(a) FIELD(b) FIELD(c) FIELD(d)
END_STRUCT
BEGIN_STRUCT(Issue24592a) FIELD(a) FIELD(b) FIELD(c) END_STRUCT
BEGIN_STRUCT(Issue24592b) FIELD(x) FIELD(a) FIELD(b) FIELD(c) END_STRUCT
BEGIN_STRUCT(Issue24592c) FIELD(a) FIELD(b) FIELD(c) FIELD(d) FIELD(e) FIELD(f) END_STRUCT
BEGIN_STRUCT(Issue24592d) FIELD(a) FIELD(b) FIELD(c) FIELD(d) FIELD(e) FIELD(f) END_STRUCT
52 changes: 52 additions & 0 deletions compiler/test/runnable_cxx/extra-files/testbitfields_importc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@

struct T0 { char x:1; };
struct T1 { short x:1; };
struct T2 { int x:1; };
struct T3 { char a,b,c,d; long long x:1; };
struct T4 { char a,b,c,d,e,f,g,h; long long x:1; };
struct T5 { char a,b,c,d,e,f,g; long long x:1; };
struct S1 { long long int f:1; };
struct S2 { int x:1; int y:1; };
struct S3 { short c; int x:1; unsigned y:1; };
struct S4 { int x:1; short y:1; };
struct S5 { short x:1; int y:1; };
struct S6 { short x:1; short y:1; };
struct S7 { short x:1; int y:1; long long z:1; };
struct S8 { char a; char b:1; short c:2; };
struct S8A { char b:1; short c:2; };
struct S8B { char a; short b:1; char c:2; };
struct S8C { char a; int b:1; };
struct S9 { char a; char b:2; short c:9; };
//struct S10 { };
//struct S11 { int :0; };
struct S12 { int :0; int x; };
struct S13 { unsigned x:12; unsigned x1:1; unsigned x2:1; unsigned x3:1; unsigned x4:1; int w; };
struct S14 { char a; char b:4; int c:30; };
struct S15 { char a; char b:2; int c:9; };
struct S16 { int :32; };
struct S17 { int a:32; };
struct S18 { char a; long long :0; char b; };
struct A0 { int a; long long b:34, c:4; };
struct A1 { int a; unsigned b:11; int c; };
struct A2 { int a; unsigned b:11, c:5, d:16;
int e; };
struct A3 { int a; unsigned b:11, c:5, :0, d:16;
int e; };
struct A4 { int a:8; short b:7;
unsigned int c:29; };
struct A5 { char a:7, b:2; };
struct A6 { char a:7; short b:2; };
struct A7 { short a:8; long b:16; int c;
char d:7; };
struct A8 { short a:8; long b:16; int :0;
char c:7; };
struct A9 { unsigned short a:8; long b:16;
unsigned long c:29; long long d:9;
unsigned long e:2, f:31; };
struct A10 { unsigned short a:8; char b; };
struct A11 { char a; int b:5, c:11, :0, d:8;
struct { int ee:8; } e; };
struct Issue24592a { unsigned long long a:20, b:20, c:24; };
struct Issue24592b { unsigned int x; unsigned long long a:20, b:20, c:24; };
struct Issue24592c { unsigned long long a:20, b:32, c:32, d:32, e:32, f:32; };
struct Issue24592d { unsigned long long a:10, b:16, c:16, d:16, e:16, f:16; };
90 changes: 90 additions & 0 deletions compiler/test/runnable_cxx/testbitfields.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// EXTRA_CPP_SOURCES: testbitfields_cpp.cpp
// EXTRA_SOURCES: extra-files/testbitfields_importc.c
// CXXFLAGS(linux osx freebsd dragonflybsd): -std=c++11

import core.stdc.stdio;
import core.stdc.stdlib;
import core.stdc.string;

static import testbitfields_importc;

extern(C++) size_t getStructSize(T)();
extern(C++) size_t getStructAlign(T)();
extern(C++) void resetBitfield(T)(ref T data, const(char) *member);

bool checkType(S)()
{
bool different;
if (S.sizeof != getStructSize!S)
different = true;
if (S.alignof != getStructAlign!S)
different = true;
static foreach (member; __traits(allMembers, S))
{{
static if (member[0] != '_' && typeof(__traits(getMember, S, member)).stringof[0] != '_')
{
S dummyD;
memset(&dummyD, 0xff, S.sizeof);
__traits(getMember, dummyD, member) = 0;

S* dummyC = cast(S*) malloc(getStructSize!S);
memset(dummyC, 0xff, getStructSize!S);
resetBitfield!S(*dummyC, member.ptr);
if (S.sizeof == getStructSize!S && memcmp(&dummyD, dummyC, S.sizeof) != 0)
different = true;
free(dummyC);
}
}}
if (different)
{
printf("Struct %s has different bitfield layout for C and D:\n", __traits(identifier, S).ptr);
printf(" D: size=%zd align=%zd\n", S.sizeof, S.alignof);
printf(" C: size=%zd align=%zd\n", getStructSize!S, getStructAlign!S);
static foreach (member; __traits(allMembers, S))
{{
static if (member[0] != '_' && typeof(__traits(getMember, S, member)).stringof[0] != '_')
{
printf(" %s %s:\n", typeof(__traits(getMember, S, member)).stringof.ptr, member.ptr);
printf(" D:");
S dummyD;
memset(&dummyD, 0xff, S.sizeof);
__traits(getMember, dummyD, member) = 0;
foreach (i; 0 .. S.sizeof)
{
if (i % 4 == 0)
printf(" ");
printf("%02X", 0xff & ~(cast(ubyte*) &dummyD)[i]);
}

printf("\n C:");
S* dummyC = cast(S*) malloc(getStructSize!S);
memset(dummyC, 0xff, getStructSize!S);
resetBitfield!S(*dummyC, member.ptr);
foreach (i; 0 .. getStructSize!S)
{
if (i % 4 == 0)
printf(" ");
printf("%02X", 0xff & ~(cast(ubyte*) dummyC)[i]);
}
free(dummyC);
printf("\n");
}
}}
}
return different;
}

int main()
{
int ret;
static foreach (name; __traits(allMembers, testbitfields_importc))
{{
alias S = __traits(getMember, testbitfields_importc, name);
static if (is(S == struct) && name[0] != '_')
{
if (checkType!S)
ret = 1;
}
}}
return ret;
}
Loading