From c11e145434d4d82ffe470a8ee92098446f6a1a9e Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Mon, 23 Aug 2021 14:47:57 -0700 Subject: [PATCH 1/3] ImportC: add support for Posix bit fields --- src/dmd/declaration.d | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/src/dmd/declaration.d b/src/dmd/declaration.d index 0f40c1142c73..4c47a434508c 100644 --- a/src/dmd/declaration.d +++ b/src/dmd/declaration.d @@ -1192,14 +1192,7 @@ extern (C++) class VarDeclaration : Declaration /* If coming after a bit field in progress, * advance past the field */ - if (fieldState.inFlight) - { - fieldState.inFlight = false; - if (0 && target.os & Target.OS.Posix) - fieldState.offset += (fieldState.bitOffset + 7) / 8; - else if (0 &&target.os == Target.OS.Windows) - fieldState.offset += fieldState.fieldSize; - } + fieldState.inFlight = false; const sz = t.size(loc); assert(sz != SIZE_INVALID && sz < uint.max); @@ -1783,15 +1776,19 @@ extern (C++) class BitFieldDeclaration : VarDeclaration { startNewField(); } - - if (0 && target.os & Target.OS.Posix) + else if (target.os & Target.OS.Posix) { - if ((fieldState.offset%4 * 8) + fieldState.bitOffset + fieldWidth > int.sizeof * 8) + if (fieldState.fieldSize == 8 && + fieldState.bitOffset + fieldWidth > 64) + { + startNewField(); + } + else if (fieldState.bitOffset + fieldWidth > int.sizeof * 8) { startNewField(); } } - else if (1 || target.os == Target.OS.Windows) + else if (target.os == Target.OS.Windows) { if (memsize != fieldState.fieldSize || fieldState.bitOffset + fieldWidth > fieldState.fieldSize * 8) @@ -1799,22 +1796,23 @@ extern (C++) class BitFieldDeclaration : VarDeclaration startNewField(); } } + else + assert(0); offset = fieldState.fieldOffset; bitOffset = fieldState.bitOffset; - if (0 && target.os & Target.OS.Posix) - { - while (bitOffset > memsize * 8) - { - bitOffset -= 8; - offset += 1; - } - } + + const pastField = bitOffset + fieldWidth; + if (target.os & Target.OS.Posix) + { + fieldState.fieldSize = (pastField + 7) / 8; + ad.structsize = offset + fieldState.fieldSize; + } //fieldState.fieldSize = memsize; if (!isunion) { - fieldState.bitOffset += fieldWidth; + fieldState.bitOffset = pastField; } //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize); From 669ae8a2650a09ba96e16905600a638a9423957f Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Tue, 24 Aug 2021 01:15:41 -0700 Subject: [PATCH 2/3] ImportC add Posix bitfield support --- src/dmd/cparse.d | 23 ++++++++++------------- src/dmd/declaration.d | 20 ++++++++++---------- test/compilable/zerosize.d | 2 -- test/fail_compilation/bitfields1.c | 7 ++++++- test/fail_compilation/failcstuff1.c | 1 - 5 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/dmd/cparse.d b/src/dmd/cparse.d index 34ff1ac596fb..4f430f8cf38f 100644 --- a/src/dmd/cparse.d +++ b/src/dmd/cparse.d @@ -3037,14 +3037,9 @@ final class CParser(AST) : Parser!AST check(TOK.rightCurly); if ((*members).length == 0) // C11 6.7.2.1-8 - /* TODO: not strict enough, should really be contains "no named members", - * not just "no members". - * I.e. an unnamed bit field, _Static_assert, etc, are not named members, - * but will pass this check. - * Be careful to detect named members that come anonymous structs. - * Correctly doing this will likely mean moving it to typesem.d. - */ - error("empty struct-declaration-list for `%s %s`", Token.toChars(structOrUnion), tag ? tag.toChars() : "Anonymous".ptr); + { + // allow empty structs as an extension + } } else if (!tag) error("missing tag `identifier` after `%s`", Token.toChars(structOrUnion)); @@ -3139,12 +3134,14 @@ final class CParser(AST) : Parser!AST dt = tspec; } else - dt = cparseDeclarator(DTR.xdirect, tspec, id); - if (!dt) { - panic(); - nextToken(); - break; // error recovery + dt = cparseDeclarator(DTR.xdirect, tspec, id); + if (!dt) + { + panic(); + nextToken(); + break; // error recovery + } } AST.Expression width; diff --git a/src/dmd/declaration.d b/src/dmd/declaration.d index 4c47a434508c..3377c07a738d 100644 --- a/src/dmd/declaration.d +++ b/src/dmd/declaration.d @@ -1192,7 +1192,7 @@ extern (C++) class VarDeclaration : Declaration /* If coming after a bit field in progress, * advance past the field */ - fieldState.inFlight = false; + fieldState.inFlight = false; const sz = t.size(loc); assert(sz != SIZE_INVALID && sz < uint.max); @@ -1778,7 +1778,7 @@ extern (C++) class BitFieldDeclaration : VarDeclaration } else if (target.os & Target.OS.Posix) { - if (fieldState.fieldSize == 8 && + if (fieldState.fieldSize == 8 && fieldState.bitOffset + fieldWidth > 64) { startNewField(); @@ -1796,18 +1796,18 @@ extern (C++) class BitFieldDeclaration : VarDeclaration startNewField(); } } - else - assert(0); + else + assert(0); offset = fieldState.fieldOffset; bitOffset = fieldState.bitOffset; - const pastField = bitOffset + fieldWidth; - if (target.os & Target.OS.Posix) - { - fieldState.fieldSize = (pastField + 7) / 8; - ad.structsize = offset + fieldState.fieldSize; - } + const pastField = bitOffset + fieldWidth; + if (target.os & Target.OS.Posix) + { + fieldState.fieldSize = (pastField + 7) / 8; + ad.structsize = offset + fieldState.fieldSize; + } //fieldState.fieldSize = memsize; if (!isunion) diff --git a/test/compilable/zerosize.d b/test/compilable/zerosize.d index 3c0062ead303..3a3251ed85bf 100644 --- a/test/compilable/zerosize.d +++ b/test/compilable/zerosize.d @@ -8,5 +8,3 @@ extern (C++) struct T { } static assert(T.sizeof == 1); static assert(T.alignof == 1); - - diff --git a/test/fail_compilation/bitfields1.c b/test/fail_compilation/bitfields1.c index b732c93b6428..f350566b93c1 100644 --- a/test/fail_compilation/bitfields1.c +++ b/test/fail_compilation/bitfields1.c @@ -1,7 +1,9 @@ /* TEST_OUTPUT: --- fail_compilation/bitfields1.c(103): Error: no alignment-specifier for bit field declaration -fail_compilation/bitfields1.c(109): Error: empty struct-declaration-list for `struct T` +fail_compilation/bitfields1.c(108): Error: specifier-qualifier-list required +fail_compilation/bitfields1.c(111): Error: specifier-qualifier-list required +fail_compilation/bitfields1.c(112): Error: specifier-qualifier-list required --- */ @@ -17,3 +19,6 @@ struct T :3; }; +struct E1 { :0; int x; }; +struct E2 { int x; :0; }; + diff --git a/test/fail_compilation/failcstuff1.c b/test/fail_compilation/failcstuff1.c index 417cf7370e4f..cff063d2e7e2 100644 --- a/test/fail_compilation/failcstuff1.c +++ b/test/fail_compilation/failcstuff1.c @@ -8,7 +8,6 @@ fail_compilation/failcstuff1.c(152): Error: `;` or `,` expected fail_compilation/failcstuff1.c(153): Error: `void` has no value fail_compilation/failcstuff1.c(153): Error: missing comma fail_compilation/failcstuff1.c(153): Error: `;` or `,` expected -fail_compilation/failcstuff1.c(154): Error: empty struct-declaration-list for `struct Anonymous` fail_compilation/failcstuff1.c(157): Error: identifier not allowed in abstract-declarator fail_compilation/failcstuff1.c(203): Error: storage class not allowed in specifier-qualified-list fail_compilation/failcstuff1.c(204): Error: storage class not allowed in specifier-qualified-list From 6ec9f4cf086e20dd6c84a50749f5eb5e9f302f9d Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Fri, 27 Aug 2021 01:16:21 -0700 Subject: [PATCH 3/3] ImportC: posix bit field layout --- src/dmd/cparse.d | 5 +- src/dmd/declaration.d | 99 ++++++++++++++++---- src/dmd/dsymbol.d | 8 +- src/dmd/dsymbol.h | 4 +- src/dmd/frontend.h | 11 ++- src/dmd/todt.d | 8 +- test/runnable/bitfieldsposix32.c | 155 +++++++++++++++++++++++++++++++ test/runnable/bitfieldsposix64.c | 155 +++++++++++++++++++++++++++++++ 8 files changed, 419 insertions(+), 26 deletions(-) create mode 100644 test/runnable/bitfieldsposix32.c create mode 100644 test/runnable/bitfieldsposix64.c diff --git a/src/dmd/cparse.d b/src/dmd/cparse.d index 4f430f8cf38f..f6249d738912 100644 --- a/src/dmd/cparse.d +++ b/src/dmd/cparse.d @@ -3038,7 +3038,10 @@ final class CParser(AST) : Parser!AST if ((*members).length == 0) // C11 6.7.2.1-8 { - // allow empty structs as an extension + /* allow empty structs as an extension + * struct-declarator-list: + * struct-declarator (opt) + */ } } else if (!tag) diff --git a/src/dmd/declaration.d b/src/dmd/declaration.d index 3377c07a738d..9200bb829112 100644 --- a/src/dmd/declaration.d +++ b/src/dmd/declaration.d @@ -1736,13 +1736,23 @@ 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(); + const bool anon = isAnonymous(); // List in ad.fields. Even if the type is error, it's necessary to avoid // pointless error diagnostic "more initializers than fields" on struct literal. - if (!isAnonymous()) + if (!anon) ad.fields.push(this); if (t.ty == Terror) @@ -1753,17 +1763,34 @@ extern (C++) class BitFieldDeclaration : VarDeclaration uint memsize = cast(uint)sz; // size of member uint memalignsize = target.fieldalign(t); // size of member for alignment purposes - if (fieldWidth == 0 && !isAnonymous()) + if (fieldWidth == 0 && !anon) error(loc, "named bit fields cannot have 0 width"); if (fieldWidth > memsize * 8) error(loc, "bit field width %d is larger than type", fieldWidth); void startNewField() { + uint alignsize; + if (target.c.bitFieldStyle == TargetC.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; + + uint dummy; offset = AggregateDeclaration.placeField( &fieldState.offset, - memsize, memalignsize, alignment, - &ad.structsize, &ad.alignsize, + memsize, alignsize, alignment, + &ad.structsize, + anon ? &dummy : &ad.alignsize, isunion); fieldState.inFlight = true; @@ -1772,23 +1799,58 @@ extern (C++) class BitFieldDeclaration : VarDeclaration fieldState.fieldSize = memsize; } - if (!fieldState.inFlight || fieldWidth == 0) + if (target.c.bitFieldStyle == TargetC.BitFieldStyle.Gcc_Clang) + { + if (fieldWidth == 0) + { + if (!isunion) + { + // Use type of zero width field to align to next field + fieldState.offset = (fieldState.offset + memalignsize - 1) & ~(memalignsize - 1); + ad.structsize = fieldState.offset; + } + + fieldState.inFlight = false; + return; + } + + if (ad.alignsize == 0) + ad.alignsize = 1; + if (!anon && + ad.alignsize < memalignsize) + ad.alignsize = memalignsize; + } + + if (fieldWidth == 0) + { + fieldState.inFlight = false; + return; + } + else if (!fieldState.inFlight) { startNewField(); } - else if (target.os & Target.OS.Posix) + else if (target.c.bitFieldStyle == TargetC.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 == TargetC.BitFieldStyle.Dm_Ms) { if (memsize != fieldState.fieldSize || fieldState.bitOffset + fieldWidth > fieldState.fieldSize * 8) @@ -1803,13 +1865,18 @@ extern (C++) class BitFieldDeclaration : VarDeclaration bitOffset = fieldState.bitOffset; const pastField = bitOffset + fieldWidth; - if (target.os & Target.OS.Posix) + if (target.c.bitFieldStyle == TargetC.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; diff --git a/src/dmd/dsymbol.d b/src/dmd/dsymbol.d index 3a6dff2d44fb..50eaf32901f2 100644 --- a/src/dmd/dsymbol.d +++ b/src/dmd/dsymbol.d @@ -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 } diff --git a/src/dmd/dsymbol.h b/src/dmd/dsymbol.h index f43bc8379926..8c3440a2550c 100644 --- a/src/dmd/dsymbol.h +++ b/src/dmd/dsymbol.h @@ -145,8 +145,10 @@ struct FieldState unsigned offset; unsigned fieldOffset; + unsigned fieldSize; + unsigned fieldAlign; unsigned bitOffset; - unsigned fieldSice; + bool inFlight; }; diff --git a/src/dmd/frontend.h b/src/dmd/frontend.h index c518918678a1..ca8412d8a676 100644 --- a/src/dmd/frontend.h +++ b/src/dmd/frontend.h @@ -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) {} }; diff --git a/src/dmd/todt.d b/src/dmd/todt.d index 61ca6000b20b..5b722bb76e06 100644 --- a/src/dmd/todt.d +++ b/src/dmd/todt.d @@ -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 == TargetC.BitFieldStyle.Gcc_Clang) + bitFieldSize = (bitOffset + bf.fieldWidth + 7) / 8; + else + bitFieldSize = cast(uint)vd.type.size(); + } assert(offset <= vd.offset); if (offset < vd.offset) diff --git a/test/runnable/bitfieldsposix32.c b/test/runnable/bitfieldsposix32.c new file mode 100644 index 000000000000..8a794975c18d --- /dev/null +++ b/test/runnable/bitfieldsposix32.c @@ -0,0 +1,155 @@ +/* test bitfields + * DISABLED: win32 win64 linux64 freebsd64 osx64 + * RUN_OUTPUT: +--- +T0 = 1 1 | 1 1 +T1 = 2 2 | 2 2 +T2 = 4 4 | 4 4 +T3 = 8 4 | 8 8 +T4 = 12 4 | 16 8 +T5 = 8 4 | 8 8 +S1 = 4 4 | 8 8 +S2 = 4 4 | 4 4 +S3 = 4 4 | 4 4 +S4 = 4 4 | 4 4 +S5 = 4 4 | 4 4 +S6 = 2 2 | 2 2 +S7 = 4 4 | 8 8 +S8 = 2 2 | 2 2 +S8A = 2 2 | 2 2 +S8B = 2 2 | 2 2 +S8C = 4 4 | 4 4 +S9 = 4 2 | 4 2 +S10 = 0 1 | 0 1 +S11 = 0 1 | 0 1 +S12 = 4 4 | 4 4 +S13 = 8 4 | 8 4 +S14 = 8 4 | 8 4 +S15 = 4 4 | 4 4 +S16 = 4 1 | 4 1 +S17 = 4 4 | 4 4 +S18 = 5 1 | 9 1 +A0 = 12 4 | 16 8 +S9 = x30200 +S14 = x300000201 +S15 = xe01 +S18 = 4 should be 4 +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); + } +} + +int is64bit() { return sizeof(long) == 8; } // otherwise assume 32 bit + +/*************************************************************/ + +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 S16 { int :32; }; // 4 1 +struct S17 { int a:32; }; // 4 4 +struct S18 { char a; long long :0; char b; }; // 5 1 (32 bit) 9 1 (64 bit) +struct A0 { int a; long long b:34, c:4; }; // 12 4 (32 bit) 16 8 (64 bit) + +int main() +{ + printf("T0 = %d %d | 1 1\n", (int)sizeof(struct T0), (int)_Alignof(struct T0)); + printf("T1 = %d %d | 2 2\n", (int)sizeof(struct T1), (int)_Alignof(struct T1)); + printf("T2 = %d %d | 4 4\n", (int)sizeof(struct T2), (int)_Alignof(struct T2)); + printf("T3 = %d %d | 8 8\n", (int)sizeof(struct T3), (int)_Alignof(struct T3)); + printf("T4 = %d %d | 16 8\n", (int)sizeof(struct T4), (int)_Alignof(struct T4)); + printf("T5 = %d %d | 8 8\n", (int)sizeof(struct T5), (int)_Alignof(struct T5)); + printf("S1 = %d %d | 8 8\n", (int)sizeof(struct S1), (int)_Alignof(struct S1)); + printf("S2 = %d %d | 4 4\n", (int)sizeof(struct S2), (int)_Alignof(struct S2)); + printf("S3 = %d %d | 4 4\n", (int)sizeof(struct S3), (int)_Alignof(struct S3)); + printf("S4 = %d %d | 4 4\n", (int)sizeof(struct S4), (int)_Alignof(struct S4)); + printf("S5 = %d %d | 4 4\n", (int)sizeof(struct S5), (int)_Alignof(struct S5)); + printf("S6 = %d %d | 2 2\n", (int)sizeof(struct S6), (int)_Alignof(struct S6)); + printf("S7 = %d %d | 8 8\n", (int)sizeof(struct S7), (int)_Alignof(struct S7)); + printf("S8 = %d %d | 2 2\n", (int)sizeof(struct S8), (int)_Alignof(struct S8)); + printf("S8A = %d %d | 2 2\n", (int)sizeof(struct S8A), (int)_Alignof(struct S8A)); + printf("S8B = %d %d | 2 2\n", (int)sizeof(struct S8B), (int)_Alignof(struct S8B)); + printf("S8C = %d %d | 4 4\n", (int)sizeof(struct S8C), (int)_Alignof(struct S8C)); + printf("S9 = %d %d | 4 2\n", (int)sizeof(struct S9), (int)_Alignof(struct S9)); + printf("S10 = %d %d | 0 1\n", (int)sizeof(struct S10), (int)_Alignof(struct S10)); + printf("S11 = %d %d | 0 1\n", (int)sizeof(struct S11), (int)_Alignof(struct S11)); + printf("S12 = %d %d | 4 4\n", (int)sizeof(struct S12), (int)_Alignof(struct S12)); + printf("S13 = %d %d | 8 4\n", (int)sizeof(struct S13), (int)_Alignof(struct S13)); + printf("S14 = %d %d | 8 4\n", (int)sizeof(struct S14), (int)_Alignof(struct S14)); + printf("S15 = %d %d | 4 4\n", (int)sizeof(struct S15), (int)_Alignof(struct S15)); + printf("S16 = %d %d | 4 1\n", (int)sizeof(struct S16), (int)_Alignof(struct S16)); + printf("S17 = %d %d | 4 4\n", (int)sizeof(struct S17), (int)_Alignof(struct S17)); + printf("S18 = %d %d | 9 1\n", (int)sizeof(struct S18), (int)_Alignof(struct S18)); + printf("A0 = %d %d | 16 8\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 S18 s; + printf("S18 = %d should be %d\n", (int)(&s.b - &s.a), is64bit() ? 8 : 4); + } + { + 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; +} + + diff --git a/test/runnable/bitfieldsposix64.c b/test/runnable/bitfieldsposix64.c new file mode 100644 index 000000000000..a145cc124fef --- /dev/null +++ b/test/runnable/bitfieldsposix64.c @@ -0,0 +1,155 @@ +/* test bitfields + * DISABLED: win32 win64 linux32 freebsd32 osx32 + * RUN_OUTPUT: +--- +T0 = 1 1 | 1 1 +T1 = 2 2 | 2 2 +T2 = 4 4 | 4 4 +T3 = 8 8 | 8 8 +T4 = 16 8 | 16 8 +T5 = 8 8 | 8 8 +S1 = 8 8 | 8 8 +S2 = 4 4 | 4 4 +S3 = 4 4 | 4 4 +S4 = 4 4 | 4 4 +S5 = 4 4 | 4 4 +S6 = 2 2 | 2 2 +S7 = 8 8 | 8 8 +S8 = 2 2 | 2 2 +S8A = 2 2 | 2 2 +S8B = 2 2 | 2 2 +S8C = 4 4 | 4 4 +S9 = 4 2 | 4 2 +S10 = 0 1 | 0 1 +S11 = 0 1 | 0 1 +S12 = 4 4 | 4 4 +S13 = 8 4 | 8 4 +S14 = 8 4 | 8 4 +S15 = 4 4 | 4 4 +S16 = 4 1 | 4 1 +S17 = 4 4 | 4 4 +S18 = 9 1 | 9 1 +A0 = 16 8 | 16 8 +S9 = x30200 +S14 = x300000201 +S15 = xe01 +S18 = 8 should be 8 +A0 = x1 +--- + */ + +int printf(const char *fmt, ...); +void exit(int); + +void assert(int n, int b) +{ + if (!b) + { + printf("assert fail %d\n", n); + exit(1); + } +} + +int is64bit() { return sizeof(long) == 8; } // otherwise assume 32 bit + +/*************************************************************/ + +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 S16 { int :32; }; // 4 1 +struct S17 { int a:32; }; // 4 4 +struct S18 { char a; long long :0; char b; }; // 5 1 (32 bit) 9 1 (64 bit) +struct A0 { int a; long long b:34, c:4; }; // 12 4 (32 bit) 16 8 (64 bit) + +int main() +{ + printf("T0 = %d %d | 1 1\n", (int)sizeof(struct T0), (int)_Alignof(struct T0)); + printf("T1 = %d %d | 2 2\n", (int)sizeof(struct T1), (int)_Alignof(struct T1)); + printf("T2 = %d %d | 4 4\n", (int)sizeof(struct T2), (int)_Alignof(struct T2)); + printf("T3 = %d %d | 8 8\n", (int)sizeof(struct T3), (int)_Alignof(struct T3)); + printf("T4 = %d %d | 16 8\n", (int)sizeof(struct T4), (int)_Alignof(struct T4)); + printf("T5 = %d %d | 8 8\n", (int)sizeof(struct T5), (int)_Alignof(struct T5)); + printf("S1 = %d %d | 8 8\n", (int)sizeof(struct S1), (int)_Alignof(struct S1)); + printf("S2 = %d %d | 4 4\n", (int)sizeof(struct S2), (int)_Alignof(struct S2)); + printf("S3 = %d %d | 4 4\n", (int)sizeof(struct S3), (int)_Alignof(struct S3)); + printf("S4 = %d %d | 4 4\n", (int)sizeof(struct S4), (int)_Alignof(struct S4)); + printf("S5 = %d %d | 4 4\n", (int)sizeof(struct S5), (int)_Alignof(struct S5)); + printf("S6 = %d %d | 2 2\n", (int)sizeof(struct S6), (int)_Alignof(struct S6)); + printf("S7 = %d %d | 8 8\n", (int)sizeof(struct S7), (int)_Alignof(struct S7)); + printf("S8 = %d %d | 2 2\n", (int)sizeof(struct S8), (int)_Alignof(struct S8)); + printf("S8A = %d %d | 2 2\n", (int)sizeof(struct S8A), (int)_Alignof(struct S8A)); + printf("S8B = %d %d | 2 2\n", (int)sizeof(struct S8B), (int)_Alignof(struct S8B)); + printf("S8C = %d %d | 4 4\n", (int)sizeof(struct S8C), (int)_Alignof(struct S8C)); + printf("S9 = %d %d | 4 2\n", (int)sizeof(struct S9), (int)_Alignof(struct S9)); + printf("S10 = %d %d | 0 1\n", (int)sizeof(struct S10), (int)_Alignof(struct S10)); + printf("S11 = %d %d | 0 1\n", (int)sizeof(struct S11), (int)_Alignof(struct S11)); + printf("S12 = %d %d | 4 4\n", (int)sizeof(struct S12), (int)_Alignof(struct S12)); + printf("S13 = %d %d | 8 4\n", (int)sizeof(struct S13), (int)_Alignof(struct S13)); + printf("S14 = %d %d | 8 4\n", (int)sizeof(struct S14), (int)_Alignof(struct S14)); + printf("S15 = %d %d | 4 4\n", (int)sizeof(struct S15), (int)_Alignof(struct S15)); + printf("S16 = %d %d | 4 1\n", (int)sizeof(struct S16), (int)_Alignof(struct S16)); + printf("S17 = %d %d | 4 4\n", (int)sizeof(struct S17), (int)_Alignof(struct S17)); + printf("S18 = %d %d | 9 1\n", (int)sizeof(struct S18), (int)_Alignof(struct S18)); + printf("A0 = %d %d | 16 8\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 S18 s; + printf("S18 = %d should be %d\n", (int)(&s.b - &s.a), is64bit() ? 8 : 4); + } + { + 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; +} + +