Skip to content

[HLSL][Sema] Fix Struct Size Calculation containing 16/32 bit scalars #128086

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 26, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,27 @@ Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer,
return Result;
}

static unsigned calculateLegacyCbufferFieldAlign(const ASTContext &Context,
QualType T) {
// Aggregate types are always aligned to new buffer rows
if (T->isAggregateType())
return 16;

assert(Context.getTypeSize(T) <= 64 &&
"Scalar bit widths larger than 64 not supported");

// 64 bit types such as double and uint64_t align to 8 bytes
if (Context.getTypeSize(T) == 64)
return 8;

// Half types align to 2 bytes only if native half is available
if (T->isHalfType() && Context.getLangOpts().NativeHalfType)
return 2;

// Everything else aligns to 4 bytes
return 4;
}

// 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,
Expand All @@ -183,11 +204,7 @@ 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())
FieldAlign = CBufferAlign;
unsigned FieldAlign = calculateLegacyCbufferFieldAlign(Context, Ty);
Size = llvm::alignTo(Size, FieldAlign);
Size += FieldSize;
}
Expand Down
60 changes: 60 additions & 0 deletions clang/test/CodeGenHLSL/cbuffer_align.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \
// RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type \
// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s --check-prefix=CHECK-HALF

// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \
// RUN: dxil-pc-shadermodel6.3-library %s \
// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s --check-prefix=CHECK-FLOAT


struct S1 {
half a; // 2 bytes + 2 bytes pad or 4 bytes
float b; // 4 bytes
half c; // 2 bytes + 2 bytes pad or 4 bytes
float d; // 4 bytes
double e; // 8 bytes
};

struct S2 {
half a; // 2 bytes or 4 bytes
half b; // 2 bytes or 4 bytes
float e; // 4 bytes or 4 bytes + 4 padding
double f; // 8 bytes
};

struct S3 {
half a; // 2 bytes + 6 bytes pad or 4 bytes + 4 bytes pad
uint64_t b; // 8 bytes
};

struct S4 {
float a; // 4 bytes
half b; // 2 bytes or 4 bytes
half c; // 2 bytes or 4 bytes + 4 bytes pad
double d; // 8 bytes
};


cbuffer CB0 {
// CHECK-HALF: @CB0.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_CB0, 24, 0))
// CHECK-FLOAT: @CB0.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_CB0, 24, 0))
S1 s1;
}

cbuffer CB1 {
// CHECK-HALF: @CB1.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_CB1, 16, 0))
// CHECK-FLOAT: @CB1.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_CB1, 24, 0))
S2 s2;
}

cbuffer CB2 {
// CHECK-HALF: @CB2.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_CB2, 16, 0))
// CHECK-FLOAT: @CB2.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_CB2, 16, 0))
S3 s3;
}

cbuffer CB3 {
// CHECK-HALF: @CB3.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_CB3, 16, 0))
// CHECK-FLOAT: @CB3.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_CB3, 24, 0))
S4 s4;
}
Loading