diff --git a/compiler/src/dmd/dsymbolsem.d b/compiler/src/dmd/dsymbolsem.d index 4a21b1473423..e32f5fa221c7 100644 --- a/compiler/src/dmd/dsymbolsem.d +++ b/compiler/src/dmd/dsymbolsem.d @@ -7270,7 +7270,7 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor // 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) { if (log) printf("more units of alignment than its type\n"); startNewField(); // the bit field is full @@ -7278,10 +7278,10 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor else { // if alignment boundary is crossed - uint start = fieldState.fieldOffset * 8 + fieldState.bitOffset; + uint start = (fieldState.fieldOffset * 8 + fieldState.bitOffset) % (memalignsize * 8); 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)) { if (log) printf("alignment is crossed\n"); startNewField(); diff --git a/compiler/src/dmd/e2ir.d b/compiler/src/dmd/e2ir.d index e073d6bd82dc..d6af6ccba0ee 100644 --- a/compiler/src/dmd/e2ir.d +++ b/compiler/src/dmd/e2ir.d @@ -3135,12 +3135,13 @@ elem* toElem(Expression e, ref IRState irs) { // 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; assert(bitOffset + bf.fieldWidth <= szbits); } //printf("voffset %u bitOffset %u fieldWidth %u bits %u\n", cast(uint)voffset, bitOffset, bf.fieldWidth, szbits); diff --git a/compiler/test/runnable/bitfieldsposix32.c b/compiler/test/runnable/bitfieldsposix32.c index 543d306656e6..790b594912c2 100644 --- a/compiler/test/runnable/bitfieldsposix32.c +++ b/compiler/test/runnable/bitfieldsposix32.c @@ -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 @@ -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() { @@ -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; diff --git a/compiler/test/runnable/bitfieldsposix64.c b/compiler/test/runnable/bitfieldsposix64.c index baedb2f761ff..8a2b089334b3 100644 --- a/compiler/test/runnable/bitfieldsposix64.c +++ b/compiler/test/runnable/bitfieldsposix64.c @@ -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 @@ -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() { @@ -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; diff --git a/compiler/test/runnable_cxx/extra-files/testbitfields_cpp.cpp b/compiler/test/runnable_cxx/extra-files/testbitfields_cpp.cpp new file mode 100644 index 000000000000..7302ca6df980 --- /dev/null +++ b/compiler/test/runnable_cxx/extra-files/testbitfields_cpp.cpp @@ -0,0 +1,84 @@ +extern "C" +{ +#include "testbitfields_importc.c" +} + +#include +#include + +template +size_t getStructSize(); +template +size_t getStructAlign(); +template +void resetBitfield(T &data, const char *member); + +#define BEGIN_STRUCT(S) \ + template<> \ + size_t getStructSize() \ + { \ + return sizeof(S); \ + } \ + template<> \ + size_t getStructAlign() \ + { \ + return alignof(S); \ + } \ + template<> \ + void resetBitfield(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 diff --git a/compiler/test/runnable_cxx/extra-files/testbitfields_importc.c b/compiler/test/runnable_cxx/extra-files/testbitfields_importc.c new file mode 100644 index 000000000000..2bc7569067dd --- /dev/null +++ b/compiler/test/runnable_cxx/extra-files/testbitfields_importc.c @@ -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; }; diff --git a/compiler/test/runnable_cxx/testbitfields.d b/compiler/test/runnable_cxx/testbitfields.d new file mode 100644 index 000000000000..2dd3a297c31d --- /dev/null +++ b/compiler/test/runnable_cxx/testbitfields.d @@ -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; +}