[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
This commit is contained in:
Ashley Coleman 2025-02-25 17:23:09 -07:00 committed by GitHub
parent 09832777d8
commit cd4c30bb22
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 146 additions and 4 deletions

View File

@ -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;
}

View File

@ -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'}}
}