-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[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
Conversation
@llvm/pr-subscribers-hlsl Author: Ashley Coleman (V-FEXrt) ChangesFixes #119641 Update SemaHLSL to correctly calculate the alignment barrier for scalars that are not 4 bytes wide Full diff: https://github.com/llvm/llvm-project/pull/128086.diff 2 Files Affected:
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index d26d85d5861b1..cccfd4aec7eb2 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -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,
@@ -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;
}
diff --git a/clang/test/CodeGenHLSL/cbuffer_align.hlsl b/clang/test/CodeGenHLSL/cbuffer_align.hlsl
new file mode 100644
index 0000000000000..31db2e0726020
--- /dev/null
+++ b/clang/test/CodeGenHLSL/cbuffer_align.hlsl
@@ -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;
+}
|
@llvm/pr-subscribers-clang Author: Ashley Coleman (V-FEXrt) ChangesFixes #119641 Update SemaHLSL to correctly calculate the alignment barrier for scalars that are not 4 bytes wide Full diff: https://github.com/llvm/llvm-project/pull/128086.diff 2 Files Affected:
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index d26d85d5861b1..cccfd4aec7eb2 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -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,
@@ -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;
}
diff --git a/clang/test/CodeGenHLSL/cbuffer_align.hlsl b/clang/test/CodeGenHLSL/cbuffer_align.hlsl
new file mode 100644
index 0000000000000..31db2e0726020
--- /dev/null
+++ b/clang/test/CodeGenHLSL/cbuffer_align.hlsl
@@ -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;
+}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens for vector fields?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
Fixes #119641
Update SemaHLSL to correctly calculate the alignment barrier for scalars that are not 4 bytes wide