diff --git a/tools/clang/lib/SPIRV/AlignmentSizeCalculator.cpp b/tools/clang/lib/SPIRV/AlignmentSizeCalculator.cpp index 9bb2f1b1fa..7f5914acd5 100644 --- a/tools/clang/lib/SPIRV/AlignmentSizeCalculator.cpp +++ b/tools/clang/lib/SPIRV/AlignmentSizeCalculator.cpp @@ -170,6 +170,9 @@ std::pair AlignmentSizeCalculator::getAlignmentAndSize( if (rule == SpirvLayoutRule::Scalar) { // A structure has a scalar alignment equal to the largest scalar // alignment of any of its members in VK_EXT_scalar_block_layout. + // Its size is rounded up to its final alignment for compatibility with + // C structure layout, even if not strictly necessary. + structSize = roundToPow2(structSize, maxAlignment); return {maxAlignment, structSize}; } diff --git a/tools/clang/test/CodeGenSPIRV/array.scalar.layout.hlsl b/tools/clang/test/CodeGenSPIRV/scalar.layout.array.hlsl similarity index 77% rename from tools/clang/test/CodeGenSPIRV/array.scalar.layout.hlsl rename to tools/clang/test/CodeGenSPIRV/scalar.layout.array.hlsl index 44c05bf6c1..251d55c48b 100644 --- a/tools/clang/test/CodeGenSPIRV/array.scalar.layout.hlsl +++ b/tools/clang/test/CodeGenSPIRV/scalar.layout.array.hlsl @@ -1,6 +1,6 @@ // RUN: %dxc -T cs_6_2 -E main %s -fvk-use-scalar-layout -spirv | FileCheck %s -// Check that the array stride and offsets are corrects. The uint64_t has alignment +// Check that the array stride and offsets are correct. The uint64_t has alignment // 8 and the struct has size 12. So the stride should be the smallest multiple of 8 // greater than or equal to 12, which is 16. @@ -9,13 +9,13 @@ // CHECK-DAG: OpDecorate %_runtimearr_Data ArrayStride 16 // CHECK-DAG: OpMemberDecorate %type_RWStructuredBuffer_Data 0 Offset 0 struct Data { - uint64_t y; - uint x; + uint64_t y; + uint x; }; + RWStructuredBuffer buffer; [numthreads(1, 1, 1)] -void main() -{ - buffer[0].x = 5; +void main() { + buffer[0].x = 5; } diff --git a/tools/clang/test/CodeGenSPIRV/scalar.layout.struct.aligned.size.hlsl b/tools/clang/test/CodeGenSPIRV/scalar.layout.struct.aligned.size.hlsl new file mode 100644 index 0000000000..40baa6361f --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/scalar.layout.struct.aligned.size.hlsl @@ -0,0 +1,33 @@ +// RUN: %dxc -T cs_6_2 -E main %s -fvk-use-scalar-layout -spirv | FileCheck %s + +// Check that the size of Foo and Bar gets rounded up to its alignment to follow +// C-style layout rules. See #7894 + +// CHECK-DAG: OpMemberDecorate %Foo 0 Offset 0 +// CHECK-DAG: OpMemberDecorate %Foo 1 Offset 8 +// CHECK-DAG: OpMemberDecorate %Bar 0 Offset 0 +// CHECK-DAG: OpMemberDecorate %Bar 1 Offset 16 +// CHECK-DAG: OpDecorate %_runtimearr_Bar ArrayStride 24 +// CHECK-DAG: OpMemberDecorate %type_RWStructuredBuffer_Bar 0 Offset 0 + +struct Foo { + uint64_t a; + int b; +}; + +struct Bar { + Foo foo; + int c; +}; + +RWStructuredBuffer buffer; + +[numthreads(1, 1, 1)] +void main(in uint3 threadId : SV_DispatchThreadID) { + // CHECK: [[buf_0:%[0-9]+]] = OpAccessChain %_ptr_Uniform_int %buffer %int_0 %uint_0 %int_1 + // CHECK-NEXT: OpStore [[buf_0]] %int_16 + buffer[0].c = sizeof(Foo); + // CHECK: [[buf_1:%[0-9]+]] = OpAccessChain %_ptr_Uniform_int %buffer %int_0 %uint_1 %int_1 + // CHECK-NEXT: OpStore [[buf_1]] %int_24 + buffer[1].c = sizeof(Bar); +} diff --git a/tools/clang/test/CodeGenSPIRV/scalar.layout.struct.array.hlsl b/tools/clang/test/CodeGenSPIRV/scalar.layout.struct.array.hlsl new file mode 100644 index 0000000000..892534f150 --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/scalar.layout.struct.array.hlsl @@ -0,0 +1,29 @@ +// RUN: %dxc -T cs_6_2 -E main %s -fvk-use-scalar-layout -spirv | FileCheck %s + +// Check that arrays of structs respect alignment requirements. Note that this +// test does not distinguish between C-style and "strict" scalar layout. + +// CHECK-DAG: OpMemberDecorate %Foo 0 Offset 0 +// CHECK-DAG: OpMemberDecorate %Foo 1 Offset 8 +// CHECK-DAG: OpDecorate %_arr_Foo_uint_3 ArrayStride 16 +// CHECK-DAG: OpMemberDecorate %Bar 0 Offset 0 +// CHECK-DAG: OpDecorate %_runtimearr_Bar ArrayStride 56 +// CHECK-DAG: OpMemberDecorate %type_RWStructuredBuffer_Bar 0 Offset 0 + +struct Foo { + uint64_t a; + int b; +}; + +struct Bar { + Foo foo[3]; + uint64_t c; +}; + +RWStructuredBuffer buffer; + +[numthreads(1, 1, 1)] void main() { + // CHECK: [[buf_0:%[0-9]+]] = OpAccessChain %_ptr_Uniform_ulong %buffer %int_0 %uint_0 %int_1 + // CHECK-NEXT: OpStore [[buf_0]] %ulong_56 + buffer[0].c = sizeof(Bar); +} diff --git a/tools/clang/test/CodeGenSPIRV/vk.layout.cbuffer.scalar.hlsl b/tools/clang/test/CodeGenSPIRV/vk.layout.cbuffer.scalar.hlsl index 0de791fbd4..82a15569c3 100644 --- a/tools/clang/test/CodeGenSPIRV/vk.layout.cbuffer.scalar.hlsl +++ b/tools/clang/test/CodeGenSPIRV/vk.layout.cbuffer.scalar.hlsl @@ -9,16 +9,16 @@ struct S { // Alignment Offset Size float sf2; // 4 -> 8 + 4 = 12 float3 sf3; // 4 -> 12 + 4 * 3 = 24 float sf4; // 4 -> 24 + 4 = 28 -}; // 8(max) 28 +}; // 8(max) 32 (size rounded up to alignment) struct T { // Alignment Offset Size = Next int tf1; // 4 -> 0 + 4 = 4 R tf2[3]; // 8 -> 8 (4 round up to R alignment) + 3 * stride(8) = 32 float3x2 tf3; // 4 -> 32 + 4 * 3 * 2 = 56 - S tf4; // 8 -> 56 + 28 = 84 - float16_t tf5; // 2 -> 84 + 2 = 86 - float tf6; // 4 -> 88 (86 round up to float align) + 4 = 92 -}; // 8(max) 92 + S tf4; // 8 -> 56 + 32 = 88 + float16_t tf5; // 2 -> 88 + 2 = 90 + float tf6; // 4 -> 92 (90 round up to float align) + 4 = 96 +}; // 8(max) 96 cbuffer MyCBuffer { // Alignment Offset Size Next bool a; // 4 -> 0 + 4 = 4 @@ -29,8 +29,8 @@ cbuffer MyCBuffer { // Alignment Offset float2x1 f; // 4 -> 68 + 4 * 2 = 76 row_major float2x3 g[3]; // 4 -> 76 + 4 * 2 * 3 * 3 = 148 column_major float2x2 h[4]; // 4 -> 148 + 4 * 2 * 2 * 4 = 212 - T t; // 8 -> 216 (212 round up to T alignment) + 92 = 308 - float z; // 4 -> 308 + T t; // 8 -> 216 (212 round up to T alignment) + 96 = 312 + float z; // 4 -> 312 }; // CHECK: OpDecorate %_arr_mat2v3float_uint_3 ArrayStride 24 @@ -51,8 +51,8 @@ cbuffer MyCBuffer { // Alignment Offset // CHECK-NEXT: OpMemberDecorate %T 2 MatrixStride 12 // CHECK-NEXT: OpMemberDecorate %T 2 RowMajor // CHECK-NEXT: OpMemberDecorate %T 3 Offset 56 -// CHECK-NEXT: OpMemberDecorate %T 4 Offset 84 -// CHECK-NEXT: OpMemberDecorate %T 5 Offset 88 +// CHECK-NEXT: OpMemberDecorate %T 4 Offset 88 +// CHECK-NEXT: OpMemberDecorate %T 5 Offset 92 // CHECK: OpMemberDecorate %type_MyCBuffer 0 Offset 0 // CHECK-NEXT: OpMemberDecorate %type_MyCBuffer 1 Offset 4 @@ -71,7 +71,7 @@ cbuffer MyCBuffer { // Alignment Offset // CHECK-NEXT: OpMemberDecorate %type_MyCBuffer 7 MatrixStride 8 // CHECK-NEXT: OpMemberDecorate %type_MyCBuffer 7 RowMajor // CHECK-NEXT: OpMemberDecorate %type_MyCBuffer 8 Offset 216 -// CHECK-NEXT: OpMemberDecorate %type_MyCBuffer 9 Offset 308 +// CHECK-NEXT: OpMemberDecorate %type_MyCBuffer 9 Offset 312 // CHECK-NEXT: OpDecorate %type_MyCBuffer Block float main() : A {