Author: Ashley Coleman Date: 2025-02-25T17:23:09-07:00 New Revision: cd4c30bb224e432d8cd37f375c138cbaada14f6c
URL: https://github.com/llvm/llvm-project/commit/cd4c30bb224e432d8cd37f375c138cbaada14f6c DIFF: https://github.com/llvm/llvm-project/commit/cd4c30bb224e432d8cd37f375c138cbaada14f6c.diff LOG: [HLSL][Sema] Fix Struct Size Calculation containing 16/32 bit scalars (#128086) Fixes #119641 Update SemaHLSL to correctly calculate the alignment barrier for scalars that are not 4 bytes wide Added: clang/test/CodeGenHLSL/cbuffer_align.hlsl Modified: clang/lib/Sema/SemaHLSL.cpp Removed: ################################################################################ diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index d26d85d5861b1..e4a446f3fe37e 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -172,6 +172,23 @@ Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer, return Result; } +static unsigned calculateLegacyCbufferFieldAlign(const ASTContext &Context, + QualType T) { + // Arrays and Structs are always aligned to new buffer rows + if (T->isArrayType() || T->isStructureType()) + return 16; + + // Vectors are aligned to the type they contain + if (const VectorType *VT = T->getAs<VectorType>()) + return calculateLegacyCbufferFieldAlign(Context, VT->getElementType()); + + assert(Context.getTypeSize(T) <= 64 && + "Scalar bit widths larger than 64 not supported"); + + // Scalar types are aligned to their byte width + return Context.getTypeSize(T) / 8; +} + // Calculate the size of a legacy cbuffer type in bytes based on // https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules static unsigned calculateLegacyCbufferSize(const ASTContext &Context, @@ -183,11 +200,15 @@ static unsigned calculateLegacyCbufferSize(const ASTContext &Context, for (const FieldDecl *Field : RD->fields()) { QualType Ty = Field->getType(); unsigned FieldSize = calculateLegacyCbufferSize(Context, Ty); - // FIXME: This is not the correct alignment, it does not work for 16-bit - // types. See llvm/llvm-project#119641. - unsigned FieldAlign = 4; - if (Ty->isAggregateType()) + unsigned FieldAlign = calculateLegacyCbufferFieldAlign(Context, Ty); + + // If the field crosses the row boundary after alignment it drops to the + // next row + unsigned AlignSize = llvm::alignTo(Size, FieldAlign); + if ((AlignSize % CBufferAlign) + FieldSize > CBufferAlign) { FieldAlign = CBufferAlign; + } + Size = llvm::alignTo(Size, FieldAlign); Size += FieldSize; } diff --git a/clang/test/CodeGenHLSL/cbuffer_align.hlsl b/clang/test/CodeGenHLSL/cbuffer_align.hlsl new file mode 100644 index 0000000000000..25fe20da7a230 --- /dev/null +++ b/clang/test/CodeGenHLSL/cbuffer_align.hlsl @@ -0,0 +1,121 @@ +// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \ +// RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type \ +// RUN: -fsyntax-only -verify -verify-ignore-unexpected=warning + +struct S0 { + half a; + half b; + half c; + half d; + half e; + half f; + half g; + half h; +}; + +cbuffer CB0Pass { + S0 s0p : packoffset(c0.x); + float f0p : packoffset(c1.x); +} + +cbuffer CB0Fail { + S0 s0f : packoffset(c0.x); + float f0f : packoffset(c0.w); + // expected-error@-1 {{packoffset overlap between 'f0f', 's0f'}} +} + +struct S1 { + float a; + double b; + float c; +}; + +cbuffer CB1Pass { + S1 s1p : packoffset(c0.x); + float f1p : packoffset(c1.y); +} + +cbuffer CB1Fail { + S1 s1f : packoffset(c0.x); + float f1f : packoffset(c1.x); + // expected-error@-1 {{packoffset overlap between 'f1f', 's1f'}} +} + +struct S2 { + float3 a; + float2 b; +}; + +cbuffer CB2Pass { + S2 s2p : packoffset(c0.x); + float f2p : packoffset(c1.z); +} + +cbuffer CB2Fail { + S2 s2f : packoffset(c0.x); + float f2f : packoffset(c1.y); + // expected-error@-1 {{packoffset overlap between 'f2f', 's2f'}} +} + +struct S3 { + float3 a; + float b; +}; + +cbuffer CB3Pass { + S3 s3p : packoffset(c0.x); + float f3p : packoffset(c1.x); +} + +cbuffer CB3Fail { + S3 s3f : packoffset(c0.x); + float f3f : packoffset(c0.w); + // expected-error@-1 {{packoffset overlap between 'f3f', 's3f'}} +} + +struct S4 { + float2 a; + float2 b; +}; + +cbuffer CB4Pass { + S4 s4p : packoffset(c0.x); + float f4p : packoffset(c1.x); +} + +cbuffer CB4Fail { + S4 s4f : packoffset(c0.x); + float f4f : packoffset(c0.w); + // expected-error@-1 {{packoffset overlap between 'f4f', 's4f'}} +} + +struct S5 { + float a[3]; +}; + +cbuffer CB5Pass { + S5 s5p : packoffset(c0.x); + float f5p : packoffset(c2.y); +} + +cbuffer CB5Fail { + S5 s5f : packoffset(c0.x); + float f5f : packoffset(c2.x); + // expected-error@-1 {{packoffset overlap between 'f5f', 's5f'}} +} + +struct S6 { + float a; + float2 b; +}; + +cbuffer CB6Pass { + S6 s6p : packoffset(c0.x); + float f6p : packoffset(c0.w); +} + +cbuffer CB6Fail { + S6 s6f : packoffset(c0.x); + float f6f : packoffset(c0.y); + // expected-error@-1 {{packoffset overlap between 'f6f', 's6f'}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits