diff options
| author | Ellie Hermaszewska <ellieh@nvidia.com> | 2025-07-31 15:23:13 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-07-31 07:23:13 +0000 |
| commit | 66301ab9068c5705e5a2bcbf2eaadfb28e8bb084 (patch) | |
| tree | 3682e0224df6706bcf70f58e37873c1d078c785c /tests/language-feature | |
| parent | db59c22cfb774e984a207a074f13870b78ec0071 (diff) | |
msvc style bitfield packing (#7963)
Closes https://github.com/shader-slang/slang/issues/3646
New tests rather than just adding another TEST line to existing tests so
that we get the msvc- prefix in the output of slang-test
Diffstat (limited to 'tests/language-feature')
| -rw-r--r-- | tests/language-feature/bitfield/msvc-mixed.slang | 40 | ||||
| -rw-r--r-- | tests/language-feature/bitfield/msvc-repr-mixed.slang | 38 | ||||
| -rw-r--r-- | tests/language-feature/bitfield/msvc-repr.slang | 36 | ||||
| -rw-r--r-- | tests/language-feature/bitfield/msvc-simple.slang | 31 | ||||
| -rw-r--r-- | tests/language-feature/bitfield/msvc-sizeof.slang | 43 | ||||
| -rw-r--r-- | tests/language-feature/bitfield/msvc-zero-width.slang | 30 | ||||
| -rw-r--r-- | tests/language-feature/bitfield/repr-mixed.slang | 36 | ||||
| -rw-r--r-- | tests/language-feature/bitfield/repr.slang | 36 |
8 files changed, 290 insertions, 0 deletions
diff --git a/tests/language-feature/bitfield/msvc-mixed.slang b/tests/language-feature/bitfield/msvc-mixed.slang new file mode 100644 index 000000000..d21bdad37 --- /dev/null +++ b/tests/language-feature/bitfield/msvc-mixed.slang @@ -0,0 +1,40 @@ +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu -output-using-type -compile-arg -msvc-style-bitfield-packing + +// MSVC packing with mixed type sizes +// CHECK: 15 +// CHECK-NEXT: 255 +// CHECK-NEXT: 4095 +// CHECK-NEXT: 8 + +//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer +RWStructuredBuffer<uint> outputBuffer; + +struct MixedTypes { + uint8_t a : 4; // Uses uint8_t backing, bits 7-4 + uint8_t b : 4; // Same backing, bits 3-0 + uint16_t c : 8; // New uint16_t backing due to type change, bits 15-8 + uint16_t d : 8; // Same backing, bits 7-0 + uint32_t e : 12; // New uint32_t backing due to type change, bits 31-20 + uint32_t f : 12; // Same backing, bits 19-8 + uint32_t g : 8; // Same backing, bits 7-0 +}; + +[numthreads(1, 1, 1)] +void computeMain() +{ + MixedTypes m; + m.a = 15; // 0xF + m.b = 15; // 0xF + m.c = 255; // 0xFF + m.d = 255; // 0xFF + m.e = 4095; // 0xFFF + m.f = 4095; // 0xFFF + m.g = 255; // 0xFF + + outputBuffer[0] = m.a; + outputBuffer[1] = m.c; + outputBuffer[2] = m.e; + // Verify struct size includes all three backing fields + outputBuffer[3] = sizeof(MixedTypes); +} + diff --git a/tests/language-feature/bitfield/msvc-repr-mixed.slang b/tests/language-feature/bitfield/msvc-repr-mixed.slang new file mode 100644 index 000000000..47f03ad1d --- /dev/null +++ b/tests/language-feature/bitfield/msvc-repr-mixed.slang @@ -0,0 +1,38 @@ +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu -compile-arg -msvc-style-bitfield-packing + +// MSVC creates separate backing fields for different type sizes +// struct MixedSizes { uint8_t a:4; uint8_t b:4; uint16_t c:8; uint16_t d:8; } +// First backing (uint8_t): a=0xA (bits 4-7), b=0xB (bits 0-3) => 0xAB +// Second backing (uint16_t): c=0xCD (bits 8-15), d=0xEF (bits 0-7) => 0xCDEF +// Memory layout: [0xAB, padding, 0xCDEF] or [0xAB, padding, 0xEF, 0xCD] depending on endianness + +// CHECK: AB +// CHECK-NEXT: CDEF + +//TEST_INPUT:ubuffer(data=[0 0], stride=4):out,name=outputBuffer +RWStructuredBuffer<uint> outputBuffer; + +struct MixedSizes { + uint8_t a : 4; // First backing field (uint8_t) + uint8_t b : 4; // Same backing field + uint16_t c : 8; // New backing field (uint16_t) due to type change + uint16_t d : 8; // Same backing field +}; + +[numthreads(1, 1, 1)] +void computeMain() +{ + MixedSizes m; + m.a = 0xA; + m.b = 0xB; + m.c = 0xCD; + m.d = 0xEF; + + // Read the two backing fields separately + uint8_t* p8 = (uint8_t*)&m; + uint16_t* p16 = (uint16_t*)((uint8_t*)&m + 2); // Skip uint8_t + padding + + outputBuffer[0] = uint(*p8); + outputBuffer[1] = uint(*p16); +} + diff --git a/tests/language-feature/bitfield/msvc-repr.slang b/tests/language-feature/bitfield/msvc-repr.slang new file mode 100644 index 000000000..4edd47556 --- /dev/null +++ b/tests/language-feature/bitfield/msvc-repr.slang @@ -0,0 +1,36 @@ +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu -compile-arg -msvc-style-bitfield-packing + +// MSVC style packs from MSB to LSB +// struct S { uint a:4; uint b:8; uint c:4; uint d:16; } +// Memory layout (32-bit): +// bits 28-31: a (0x5) +// bits 20-27: b (0xAB) +// bits 16-19: c (0xC) +// bits 0-15: d (0xDEF0) +// Expected: 0x5ABCDEF0 + +// CHECK: 5ABCDEF0 + +//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer +RWStructuredBuffer<uint> outputBuffer; + +struct S { + uint a : 4; // bits 28-31 (MSB side) + uint b : 8; // bits 20-27 + uint c : 4; // bits 16-19 + uint d : 16; // bits 0-15 +}; + +[numthreads(1, 1, 1)] +void computeMain() +{ + S s; + s.a = 0x5; + s.b = 0xAB; + s.c = 0xC; + s.d = 0xDEF0; + + // Write the struct to memory and read it back as uint + outputBuffer[0] = *((uint*)&s); +} + diff --git a/tests/language-feature/bitfield/msvc-simple.slang b/tests/language-feature/bitfield/msvc-simple.slang new file mode 100644 index 000000000..4651626b8 --- /dev/null +++ b/tests/language-feature/bitfield/msvc-simple.slang @@ -0,0 +1,31 @@ +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu -output-using-type -compile-arg -msvc-style-bitfield-packing + +// With MSVC packing, bitfields are packed from MSB to LSB +// and new backing fields start when type sizes change +// CHECK: 123 +// CHECK-NEXT: 4567 +// CHECK-NEXT: 0 +// CHECK-NEXT: 0 + +//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer +RWStructuredBuffer<uint> outputBuffer; + +struct S { + int foo : 8; // Packed in bits 31-24 + uint bar : 24; // Packed in bits 23-0 +}; + +[numthreads(1, 1, 1)] +void computeMain() +{ + S s; + s.foo = 123; + s.bar = 4567; + outputBuffer[0] = s.foo; + outputBuffer[1] = s.bar; + s.foo = 0; + s.bar = 0; + outputBuffer[2] = s.foo; + outputBuffer[3] = s.bar; +} + diff --git a/tests/language-feature/bitfield/msvc-sizeof.slang b/tests/language-feature/bitfield/msvc-sizeof.slang new file mode 100644 index 000000000..9d4ccdcfc --- /dev/null +++ b/tests/language-feature/bitfield/msvc-sizeof.slang @@ -0,0 +1,43 @@ +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu -output-using-type -compile-arg -msvc-style-bitfield-packing + +// MSVC starts new backing fields when type sizes change +// CHECK: 4 +// CHECK-NEXT: 12 +// CHECK-NEXT: 8 +// CHECK-NEXT: 16 + +//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer +RWStructuredBuffer<uint> outputBuffer; + +struct S { + int foo : 8; + int bar : 24; +}; + +// MSVC will use separate backing fields for different sized types +struct T { + int64_t foo : 33; // Uses int64_t backing + int bar : 24; // Uses separate int backing due to type size change +}; + +// This still takes two ints to store all the bits +struct P { + int foo : 24; + int bar : 24; +}; + +// MSVC will use separate backing fields due to type size difference +struct Q { + int8_t foo : 1; // Uses int8_t backing + int64_t bar : 63; // Uses separate int64_t backing +}; + +[numthreads(1, 1, 1)] +void computeMain() +{ + outputBuffer[0] = sizeof(S); + outputBuffer[1] = sizeof(T); + outputBuffer[2] = sizeof(P); + outputBuffer[3] = sizeof(Q); +} + diff --git a/tests/language-feature/bitfield/msvc-zero-width.slang b/tests/language-feature/bitfield/msvc-zero-width.slang new file mode 100644 index 000000000..3363ef066 --- /dev/null +++ b/tests/language-feature/bitfield/msvc-zero-width.slang @@ -0,0 +1,30 @@ +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu -output-using-type -compile-arg -msvc-style-bitfield-packing + +// MSVC packing with zero-width bitfields +// CHECK: 123 +// CHECK-NEXT: 4567 +// CHECK-NEXT: 1 +// CHECK-NEXT: 0 + +//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer +RWStructuredBuffer<uint> outputBuffer; + +struct S { + int foo : 8; // First backing field + int breaker : 0; // Forces new backing field + int bar : 24; // Second backing field +}; + +[numthreads(1, 1, 1)] +void computeMain() +{ + S s; + s.foo = 123; + s.bar = 4567; + s.breaker = 9999; // Zero-width field, assignment has no effect + outputBuffer[0] = s.foo; + outputBuffer[1] = s.bar; + outputBuffer[2] = sizeof(S) == sizeof(int) * 2; // Two backing fields + outputBuffer[3] = s.breaker; // Always returns 0 +} + diff --git a/tests/language-feature/bitfield/repr-mixed.slang b/tests/language-feature/bitfield/repr-mixed.slang new file mode 100644 index 000000000..44a3f69d9 --- /dev/null +++ b/tests/language-feature/bitfield/repr-mixed.slang @@ -0,0 +1,36 @@ +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu + +// Default packing keeps all fields in one backing field when they fit +// struct MixedSizes { uint8_t a:4; uint8_t b:4; uint16_t c:8; uint16_t d:8; } +// All packed in single uint32_t backing: +// bits 0-3: a (0xA) +// bits 4-7: b (0xB) +// bits 8-15: c (0xCD) +// bits 16-23: d (0xEF) +// Expected: 0x00EFCDBA (top 8 bits unused) + +// CHECK: EFCDBA + +//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer +RWStructuredBuffer<uint> outputBuffer; + +struct MixedSizes { + uint8_t a : 4; // bits 0-3 + uint8_t b : 4; // bits 4-7 + uint16_t c : 8; // bits 8-15 + uint16_t d : 8; // bits 16-23 +}; + +[numthreads(1, 1, 1)] +void computeMain() +{ + MixedSizes m; + m.a = 0xA; + m.b = 0xB; + m.c = 0xCD; + m.d = 0xEF; + + // With default packing, all fields are in one backing field + outputBuffer[0] = *((uint*)&m) & 0xFFFFFF; // Mask to 24 bits +} + diff --git a/tests/language-feature/bitfield/repr.slang b/tests/language-feature/bitfield/repr.slang new file mode 100644 index 000000000..a199b23ff --- /dev/null +++ b/tests/language-feature/bitfield/repr.slang @@ -0,0 +1,36 @@ +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-cpu + +// Default GCC/Clang style packs from LSB to MSB +// struct S { uint a:4; uint b:8; uint c:4; uint d:16; } +// Memory layout (32-bit): +// bits 0-3: a (0x5) +// bits 4-11: b (0xAB) +// bits 12-15: c (0xC) +// bits 16-31: d (0xDEF0) +// Expected: 0xDEF0CAB5 + +// CHECK: DEF0CAB5 + +//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer +RWStructuredBuffer<uint> outputBuffer; + +struct S { + uint a : 4; // bits 0-3 + uint b : 8; // bits 4-11 + uint c : 4; // bits 12-15 + uint d : 16; // bits 16-31 +}; + +[numthreads(1, 1, 1)] +void computeMain() +{ + S s; + s.a = 0x5; + s.b = 0xAB; + s.c = 0xC; + s.d = 0xDEF0; + + // Write the struct to memory and read it back as uint + outputBuffer[0] = *((uint*)&s); +} + |
