[clang] [HLSL] support packoffset in clang codeGen (PR #91999)
Xiang Li via cfe-commits
cfe-commits at lists.llvm.org
Thu May 16 08:18:14 PDT 2024
https://github.com/python3kgae updated https://github.com/llvm/llvm-project/pull/91999
>From de2b6cab831ac07bf6adcfe563fd9d866e295071 Mon Sep 17 00:00:00 2001
From: Xiang Li <python3kgae at outlook.com>
Date: Mon, 13 May 2024 12:59:48 -0400
Subject: [PATCH 1/2] [HLSL] support packoffset in clang codeGen
Implement packoffset as offset in the layouted struct for cbuffer.
cbuffer CB {
float a : packoffset(c2);
float b : packoffset(c4);
float2 c : packoffset(c2.z);
}
will get layout struct like
struct CBLayout {
uint8_t padding0[32]; // c0/c1
float a; // c2.x
uint8_t padding1[4]; // c2.y
float2 c; // c2.zw
uint8_t padding[8]; // c3
float b; // c4.x
}
---
clang/include/clang/AST/Decl.h | 5 ++
clang/lib/AST/Decl.cpp | 48 +++++++++++
clang/lib/CodeGen/CGHLSLRuntime.cpp | 103 +++++++++++++++++++----
clang/lib/CodeGen/CGHLSLRuntime.h | 8 +-
clang/lib/Sema/SemaHLSL.cpp | 38 +--------
clang/test/CodeGenHLSL/cbuf.hlsl | 8 +-
clang/test/CodeGenHLSL/packoffset.hlsl | 109 +++++++++++++++++++++++++
7 files changed, 264 insertions(+), 55 deletions(-)
create mode 100644 clang/test/CodeGenHLSL/packoffset.hlsl
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index de8b923645f8d..dfec2f3834e9d 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -4959,6 +4959,11 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext {
SourceLocation LBrace);
static HLSLBufferDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
+ // Calculate the size of a legacy cbuffer type based on
+ // https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules
+ static unsigned calculateLegacyCbufferSize(const ASTContext &Context,
+ QualType T);
+
SourceRange getSourceRange() const override LLVM_READONLY {
return SourceRange(getLocStart(), RBraceLoc);
}
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index ec851c9371e10..ebfff00001087 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -5671,6 +5671,54 @@ HLSLBufferDecl *HLSLBufferDecl::CreateDeserialized(ASTContext &C,
SourceLocation(), SourceLocation());
}
+static uint64_t calculateLegacyCbufferAlign(const ASTContext &Context,
+ QualType T) {
+ if (T->isAggregateType())
+ return 128;
+ else if (const VectorType *VT = T->getAs<VectorType>())
+ return Context.getTypeSize(VT->getElementType());
+ else
+ return Context.getTypeSize(T);
+}
+
+unsigned HLSLBufferDecl::calculateLegacyCbufferSize(const ASTContext &Context,
+ QualType T) {
+ unsigned Size = 0;
+ constexpr unsigned CBufferAlign = 128;
+ constexpr unsigned CBufferAlignMask = CBufferAlign - 1;
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ const RecordDecl *RD = RT->getDecl();
+ for (const FieldDecl *Field : RD->fields()) {
+ QualType Ty = Field->getType().getCanonicalType();
+ unsigned FieldSize = calculateLegacyCbufferSize(Context, Ty);
+ unsigned FieldAlign = calculateLegacyCbufferAlign(Context, Ty);
+ if (FieldAlign < CBufferAlign) {
+ // Cross 16-byte boundary.
+ unsigned Base = CBufferAlignMask & Size;
+ if ((Base + FieldSize) > CBufferAlign)
+ FieldAlign = CBufferAlign;
+ }
+ Size = llvm::alignTo(Size, FieldAlign);
+ Size += FieldSize;
+ }
+ } else if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) {
+ if (unsigned ElementCount = AT->getSize().getZExtValue()) {
+ unsigned ElementSize =
+ calculateLegacyCbufferSize(Context, AT->getElementType());
+ unsigned AlignedElementSize = llvm::alignTo(ElementSize, CBufferAlign);
+ Size = AlignedElementSize * (ElementCount - 1) + ElementSize;
+ }
+ } else if (const VectorType *VT = T->getAs<VectorType>()) {
+ unsigned ElementCount = VT->getNumElements();
+ unsigned ElementSize =
+ calculateLegacyCbufferSize(Context, VT->getElementType());
+ Size = ElementSize * ElementCount;
+ } else {
+ Size = Context.getTypeSize(T);
+ }
+ return Size;
+}
+
//===----------------------------------------------------------------------===//
// ImportDecl Implementation
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 5e6a3dd4878f4..0014bfbc68095 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -52,6 +52,17 @@ void addDisableOptimizations(llvm::Module &M) {
StringRef Key = "dx.disable_optimizations";
M.addModuleFlag(llvm::Module::ModFlagBehavior::Override, Key, 1);
}
+
+static uint64_t calculateLegacyCbufferAlign(const DataLayout &DL,
+ llvm::Type *T) {
+ if (T->isAggregateType())
+ return 16;
+ else if (const auto *VT = dyn_cast<FixedVectorType>(T))
+ return DL.getTypeAllocSize(VT->getElementType());
+ else
+ return DL.getTypeAllocSize(T);
+}
+
// cbuffer will be translated into global variable in special address space.
// If translate into C,
// cbuffer A {
@@ -76,14 +87,71 @@ void layoutBuffer(CGHLSLRuntime::Buffer &Buf, const DataLayout &DL) {
if (Buf.Constants.empty())
return;
+ // Sort Buffer.Constants based on offset.
+ std::stable_sort(Buf.Constants.begin(), Buf.Constants.end(),
+ [](const CGHLSLRuntime::Buffer::Constant &LHS,
+ const CGHLSLRuntime::Buffer::Constant &RHS) {
+ return LHS.Offset < RHS.Offset;
+ });
+
+ unsigned BufferSize = 0;
+ // Collect offset for allocated constants first.
+ for (auto &Const : Buf.Constants) {
+ unsigned Offset = Const.Offset;
+ if (Offset == UINT_MAX)
+ continue;
+ unsigned Size = Const.Size;
+ // No need to align, the packoffset is already aligned.
+ BufferSize = Offset + Size;
+ }
+
+ constexpr unsigned CBufferAlign = 16;
+ constexpr unsigned CBufferAlignMask = CBufferAlign - 1;
+ // Allocate Offset for constant not allocated yet.
+ for (auto &Const : Buf.Constants) {
+ unsigned Offset = Const.Offset;
+ if (Offset != UINT_MAX)
+ continue;
+
+ GlobalVariable *GV = Const.GV;
+ llvm::Type *Ty = GV->getValueType();
+ unsigned Align = calculateLegacyCbufferAlign(DL, Ty);
+ unsigned Size = Const.Size;
+ if (Align < CBufferAlign) {
+ // Cross 16-byte boundary.
+ unsigned Base = CBufferAlignMask & Size;
+ if ((Base + Size) > CBufferAlign)
+ Align = CBufferAlign;
+ }
+ Offset = llvm::alignTo(BufferSize, Align);
+ BufferSize = Offset + Size;
+ Const.Offset = Offset;
+ }
+
+ // Build struct type for cbuffer.
+ LLVMContext &Ctx = Buf.Constants[0].GV->getContext();
std::vector<llvm::Type *> EltTys;
+ unsigned CurOffset = 0;
+ auto *I8Ty = llvm::Type::getInt8Ty(Ctx);
+
for (auto &Const : Buf.Constants) {
- GlobalVariable *GV = Const.first;
- Const.second = EltTys.size();
+ // Byte offset.
+ unsigned ConstOffset = Const.Offset;
+ // Add padding if needed.
+ if (CurOffset < ConstOffset)
+ EltTys.emplace_back(
+ llvm::ArrayType::get(I8Ty, (ConstOffset - CurOffset)));
+ assert(CurOffset <= ConstOffset && "constant overlap");
+ GlobalVariable *GV = Const.GV;
+ // Change the offset to field index of the layout struct.
+ Const.ElementIndex = EltTys.size();
llvm::Type *Ty = GV->getValueType();
EltTys.emplace_back(Ty);
+ unsigned Size = Const.Size;
+ // No need to align, the ConstOffset is already aligned.
+ CurOffset = ConstOffset + Size;
}
- Buf.LayoutStruct = llvm::StructType::get(EltTys[0]->getContext(), EltTys);
+ Buf.LayoutStruct = llvm::StructType::get(Ctx, EltTys);
}
GlobalVariable *replaceBuffer(CGHLSLRuntime::Buffer &Buf) {
@@ -97,11 +165,13 @@ GlobalVariable *replaceBuffer(CGHLSLRuntime::Buffer &Buf) {
IRBuilder<> B(CBGV->getContext());
Value *ZeroIdx = B.getInt32(0);
// Replace Const use with CB use.
- for (auto &[GV, Offset] : Buf.Constants) {
- Value *GEP =
- B.CreateGEP(Buf.LayoutStruct, CBGV, {ZeroIdx, B.getInt32(Offset)});
+ for (auto &Constant : Buf.Constants) {
+ GlobalVariable *GV = Constant.GV;
+ Value *GEP = B.CreateGEP(Buf.LayoutStruct, CBGV,
+ {ZeroIdx, B.getInt32(Constant.ElementIndex)});
- assert(Buf.LayoutStruct->getElementType(Offset) == GV->getValueType() &&
+ assert(Buf.LayoutStruct->getElementType(Constant.ElementIndex) ==
+ GV->getValueType() &&
"constant type mismatch");
// Replace.
@@ -134,13 +204,18 @@ void CGHLSLRuntime::addConstant(VarDecl *D, Buffer &CB) {
codegenoptions::DebugInfoKind::LimitedDebugInfo)
DI->EmitGlobalVariable(cast<GlobalVariable>(GV), D);
- // FIXME: support packoffset.
- // See https://github.com/llvm/llvm-project/issues/57914.
- uint32_t Offset = 0;
- bool HasUserOffset = false;
-
- unsigned LowerBound = HasUserOffset ? Offset : UINT_MAX;
- CB.Constants.emplace_back(std::make_pair(GV, LowerBound));
+ unsigned LowerBound = UINT_MAX;
+ bool HasUserOffset = D->hasAttr<HLSLPackOffsetAttr>();
+ if (HasUserOffset) {
+ auto *Attr = D->getAttr<HLSLPackOffsetAttr>();
+ // Make the offset in bytes.
+ LowerBound = Attr->getOffset() * 4;
+ }
+ // Byte size.
+ unsigned Size = HLSLBufferDecl::calculateLegacyCbufferSize(CGM.getContext(),
+ D->getType()) >>
+ 3;
+ CB.Constants.emplace_back(Buffer::Constant{GV, LowerBound, Size, 0});
}
void CGHLSLRuntime::addBufferDecls(const DeclContext *DC, Buffer &CB) {
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 0abe39dedcb96..e9f6ccad72ee8 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -95,8 +95,14 @@ class CGHLSLRuntime {
// IsCBuffer - Whether the buffer is a cbuffer (and not a tbuffer).
bool IsCBuffer;
BufferResBinding Binding;
+ struct Constant {
+ llvm::GlobalVariable *GV;
+ unsigned Offset;
+ unsigned Size;
+ unsigned ElementIndex;
+ };
// Global variable and offset for each constant.
- std::vector<std::pair<llvm::GlobalVariable *, unsigned>> Constants;
+ std::vector<Constant> Constants;
llvm::StructType *LayoutStruct = nullptr;
};
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 6a12c417e2f3a..12496e6f01c7d 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -39,41 +39,6 @@ Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer,
return Result;
}
-// Calculate the size of a legacy cbuffer type based on
-// https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules
-static unsigned calculateLegacyCbufferSize(const ASTContext &Context,
- QualType T) {
- unsigned Size = 0;
- constexpr unsigned CBufferAlign = 128;
- if (const RecordType *RT = T->getAs<RecordType>()) {
- const RecordDecl *RD = RT->getDecl();
- for (const FieldDecl *Field : RD->fields()) {
- QualType Ty = Field->getType();
- unsigned FieldSize = calculateLegacyCbufferSize(Context, Ty);
- unsigned FieldAlign = 32;
- if (Ty->isAggregateType())
- FieldAlign = CBufferAlign;
- Size = llvm::alignTo(Size, FieldAlign);
- Size += FieldSize;
- }
- } else if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) {
- if (unsigned ElementCount = AT->getSize().getZExtValue()) {
- unsigned ElementSize =
- calculateLegacyCbufferSize(Context, AT->getElementType());
- unsigned AlignedElementSize = llvm::alignTo(ElementSize, CBufferAlign);
- Size = AlignedElementSize * (ElementCount - 1) + ElementSize;
- }
- } else if (const VectorType *VT = T->getAs<VectorType>()) {
- unsigned ElementCount = VT->getNumElements();
- unsigned ElementSize =
- calculateLegacyCbufferSize(Context, VT->getElementType());
- Size = ElementSize * ElementCount;
- } else {
- Size = Context.getTypeSize(T);
- }
- return Size;
-}
-
void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) {
auto *BufDecl = cast<HLSLBufferDecl>(Dcl);
BufDecl->setRBraceLoc(RBrace);
@@ -110,7 +75,8 @@ void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) {
for (unsigned i = 0; i < PackOffsetVec.size() - 1; i++) {
VarDecl *Var = PackOffsetVec[i].first;
HLSLPackOffsetAttr *Attr = PackOffsetVec[i].second;
- unsigned Size = calculateLegacyCbufferSize(Context, Var->getType());
+ unsigned Size =
+ HLSLBufferDecl::calculateLegacyCbufferSize(Context, Var->getType());
unsigned Begin = Attr->getOffset() * 32;
unsigned End = Begin + Size;
unsigned NextBegin = PackOffsetVec[i + 1].second->getOffset() * 32;
diff --git a/clang/test/CodeGenHLSL/cbuf.hlsl b/clang/test/CodeGenHLSL/cbuf.hlsl
index dc2a6aaa8f433..2500562508274 100644
--- a/clang/test/CodeGenHLSL/cbuf.hlsl
+++ b/clang/test/CodeGenHLSL/cbuf.hlsl
@@ -2,13 +2,13 @@
// RUN: dxil-pc-shadermodel6.3-library %s \
// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-// CHECK: @[[CB:.+]] = external constant { float, double }
+// CHECK: @[[CB:.+]] = external constant { float, [4 x i8], double }
cbuffer A : register(b0, space2) {
float a;
double b;
}
-// CHECK: @[[TB:.+]] = external constant { float, double }
+// CHECK: @[[TB:.+]] = external constant { float, [4 x i8], double }
tbuffer A : register(t2, space1) {
float c;
double d;
@@ -16,9 +16,9 @@ tbuffer A : register(t2, space1) {
float foo() {
// CHECK: load float, ptr @[[CB]], align 4
-// CHECK: load double, ptr getelementptr inbounds ({ float, double }, ptr @[[CB]], i32 0, i32 1), align 8
+// CHECK: load double, ptr getelementptr inbounds ({ float, [4 x i8], double }, ptr @[[CB]], i32 0, i32 2), align 8
// CHECK: load float, ptr @[[TB]], align 4
-// CHECK: load double, ptr getelementptr inbounds ({ float, double }, ptr @[[TB]], i32 0, i32 1), align 8
+// CHECK: load double, ptr getelementptr inbounds ({ float, [4 x i8], double }, ptr @[[TB]], i32 0, i32 2), align 8
return a + b + c*d;
}
diff --git a/clang/test/CodeGenHLSL/packoffset.hlsl b/clang/test/CodeGenHLSL/packoffset.hlsl
new file mode 100644
index 0000000000000..72cfc11c00aee
--- /dev/null
+++ b/clang/test/CodeGenHLSL/packoffset.hlsl
@@ -0,0 +1,109 @@
+// RUN: %clang_cc1 -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: @A.cb. = external constant { [8 x i8], double, [8 x i8], float, float, half, i16, [4 x i8], i64, i32 }
+cbuffer A {
+ float a : packoffset(c1.z);
+ double b : packoffset(c0.z);
+ float c;
+ half d;
+ int16_t e;
+ int64_t f;
+ int g;
+}
+
+// CHECK: @B.cb. = external constant { [24 x i8], float, [4 x i8], double, [8 x i8], <3 x float>, [4 x i8], <3 x double>, half, [6 x i8], <2 x double>, float, <3 x half>, <3 x half> }
+cbuffer B {
+ double B0;
+ float3 B1;
+ float B2 : packoffset(c1.z);
+ double3 B3;
+ half B4;
+ double2 B5;
+ float B6;
+ half3 B7;
+ half3 B8;
+}
+
+// CHECK: @C.cb. = external constant { [2 x double], [8 x i8], [3 x <3 x float>], float, [3 x double], half, [6 x i8], [1 x <2 x double>], float, [12 x i8], [2 x <3 x half>], <3 x half> }
+cbuffer C {
+ double C0[2] : packoffset(c0);
+ float3 C1[3];
+ float C2;
+ double C3[3];
+ half C4;
+ double2 C5[1];
+ float C6;
+ half3 C7[2];
+ half3 C8;
+}
+
+// CHECK: @D.cb. = external constant { [3 x <3 x double>], <3 x half> }
+cbuffer D {
+ double3 D9[3] : packoffset(c);
+ half3 D10;
+}
+
+struct S0
+{
+ double B0;
+ float3 B1;
+ float B2;
+ double3 B3;
+ half B4;
+ double2 B5;
+ float B6;
+ half3 B7;
+ half3 B8;
+};
+
+struct S1
+{
+ float A0;
+ double A1;
+ float A2;
+ half A3;
+ int16_t A4;
+ int64_t A5;
+ int A6;
+};
+
+struct S2
+{
+ double B0;
+ float3 B1;
+ float B2;
+ double3 B3;
+ half B4;
+ double2 B5;
+ float B6;
+ half3 B7;
+ half3 B8;
+};
+
+struct S3
+{
+ S1 C0;
+ float C1[1];
+ S2 C2[2];
+ half C3;
+};
+
+// CHECK: @E.cb. = external constant { [16 x i8], half, [2 x i8], i32, double, %struct.S3, [206 x i8], %struct.S0 }
+cbuffer E {
+ int E0 : packoffset(c1.y);
+ S0 E1 : packoffset(c31);
+ half E2 : packoffset(c1);
+ S3 E3 : packoffset(c2);
+ double E4 : packoffset(c1.z);
+}
+
+float foo() {
+// CHECK: %[[a:.+]] = load float, ptr getelementptr inbounds ({ [8 x i8], double, [8 x i8], float, float, half, i16, [4 x i8], i64, i32 }, ptr @A.cb., i32 0, i32 3), align 4
+// CHECK: %[[B2:.+]] = load float, ptr getelementptr inbounds ({ [24 x i8], float, [4 x i8], double, [8 x i8], <3 x float>, [4 x i8], <3 x double>, half, [6 x i8], <2 x double>, float, <3 x half>, <3 x half> }, ptr @B.cb., i32 0, i32 1), align 4
+// CHECK: %[[C6:.+]] = load float, ptr getelementptr inbounds ({ [2 x double], [8 x i8], [3 x <3 x float>], float, [3 x double], half, [6 x i8], [1 x <2 x double>], float, [12 x i8], [2 x <3 x half>], <3 x half> }, ptr @C.cb., i32 0, i32 8), align 4
+// CHECK: %[[D10:.+]] = load <3 x half>, ptr getelementptr inbounds ({ [3 x <3 x double>], <3 x half> }, ptr @D.cb., i32 0, i32 1), align 8
+// CHECK: %[[E0:.+]] = load i32, ptr getelementptr inbounds ({ [16 x i8], half, [2 x i8], i32, double, %struct.S3, [206 x i8], %struct.S0 }, ptr @E.cb., i32 0, i32 3), align 4
+ return a + B2 + C6*D10.z + E0;
+}
>From 87de4175301caa98387e7447111d6fda914e73d4 Mon Sep 17 00:00:00 2001
From: Xiang Li <python3kgae at outlook.com>
Date: Thu, 16 May 2024 11:17:52 -0400
Subject: [PATCH 2/2] Add unit test.
---
clang/unittests/AST/CMakeLists.txt | 1 +
.../AST/HLSLLegacyCbufferTypeSizeTest.cpp | 576 ++++++++++++++++++
2 files changed, 577 insertions(+)
create mode 100644 clang/unittests/AST/HLSLLegacyCbufferTypeSizeTest.cpp
diff --git a/clang/unittests/AST/CMakeLists.txt b/clang/unittests/AST/CMakeLists.txt
index 54765e36db008..5ce8b7c44554e 100644
--- a/clang/unittests/AST/CMakeLists.txt
+++ b/clang/unittests/AST/CMakeLists.txt
@@ -29,6 +29,7 @@ add_clang_unittest(ASTTests
DeclTest.cpp
EvaluateAsRValueTest.cpp
ExternalASTSourceTest.cpp
+ HLSLLegacyCbufferTypeSizeTest.cpp
NamedDeclPrinterTest.cpp
RandstructTest.cpp
RecursiveASTVisitorTest.cpp
diff --git a/clang/unittests/AST/HLSLLegacyCbufferTypeSizeTest.cpp b/clang/unittests/AST/HLSLLegacyCbufferTypeSizeTest.cpp
new file mode 100644
index 0000000000000..abf494d8b3482
--- /dev/null
+++ b/clang/unittests/AST/HLSLLegacyCbufferTypeSizeTest.cpp
@@ -0,0 +1,576 @@
+//===- unittests/AST/HLSLLegacyCbufferTypeSizeTest.cpp -- cbuf size test --===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains tests for HLSLBufferDecl::calculateLegacyCbufferSize.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/SmallString.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace ast_matchers;
+using namespace tooling;
+
+// FIXME: Let buildASTFromCodeWithArgs find hlsl.h instead of using "nostdinc".
+
+TEST(HLSLLegacyCbufferTypeSize, BasicTypes) {
+ constexpr char Code[] = R"hlsl(
+ namespace hlsl {
+ // built-in scalar data types:
+
+ #ifdef __HLSL_ENABLE_16_BIT
+ // 16-bit integer.
+ typedef short int16_t;
+ #endif
+
+ // 64-bit integer.
+ typedef long int64_t;
+
+ } // namespace hlsl
+
+ struct A {
+ float a;
+ double b;
+ float c;
+ half d;
+ int16_t e;
+ int64_t f;
+ int g;
+ };
+ )hlsl";
+ auto AST =
+ tooling::buildASTFromCodeWithArgs(Code,
+ /*Args=*/
+ {"--driver-mode=dxc", "-T", "lib_6_3",
+ "-enable-16bit-types", "-nostdinc"},
+ /* FileName*/ "input.hlsl");
+ ASTContext &Ctx = AST->getASTContext();
+
+ auto Results = match(decl(cxxRecordDecl(hasName("A")).bind("A")), Ctx);
+
+ // struct A
+ // {
+
+ // float a; ; Offset: 0
+ // double b; ; Offset: 8
+ // float c; ; Offset: 16
+ // half d; ; Offset: 20
+ // int16_t e; ; Offset: 22
+ // int64_t f; ; Offset: 24
+ // int g; ; Offset: 32
+
+ // } A; ; Offset: 0 Size: 36
+ auto const *A = selectFirst<RecordDecl>("A", Results);
+ unsigned SizeA = HLSLBufferDecl::calculateLegacyCbufferSize(
+ Ctx, QualType(A->getTypeForDecl(), 0));
+ ASSERT_EQ(SizeA, 36u * 8u);
+}
+
+TEST(HLSLLegacyCbufferTypeSize, VectorTypes) {
+ constexpr char Code[] = R"hlsl(
+ namespace hlsl {
+ // built-in scalar data types:
+
+ #ifdef __HLSL_ENABLE_16_BIT
+ // 16-bit integer.
+ typedef short int16_t;
+ #endif
+
+ // 64-bit integer.
+ typedef long int64_t;
+
+ // built-in vector data types:
+
+ typedef vector<half, 2> half2;
+ typedef vector<half, 3> half3;
+ typedef vector<half, 4> half4;
+
+ typedef vector<float, 2> float2;
+ typedef vector<float, 3> float3;
+ typedef vector<float, 4> float4;
+ typedef vector<double, 2> double2;
+ typedef vector<double, 3> double3;
+ typedef vector<double, 4> double4;
+
+ } // namespace hlsl
+
+ struct A {
+ double B0;
+ float3 B1;
+ float B2;
+ double3 B3;
+ half B4;
+ double2 B5;
+ float B6;
+ half3 B7;
+ half3 B8;
+ };
+ )hlsl";
+ auto AST =
+ tooling::buildASTFromCodeWithArgs(Code,
+ /*Args=*/
+ {"--driver-mode=dxc", "-T", "lib_6_3",
+ "-enable-16bit-types", "-nostdinc"},
+ /* FileName*/ "input.hlsl");
+ ASTContext &Ctx = AST->getASTContext();
+
+ auto Results = match(decl(cxxRecordDecl(hasName("A")).bind("A")), Ctx);
+ // struct A
+ // {
+
+ // double B0; ; Offset: 0
+ // float3 B1; ; Offset: 16
+ // float B2; ; Offset: 28
+ // double3 B3; ; Offset: 32
+ // half B4; ; Offset: 56
+ // double2 B5; ; Offset: 64
+ // float B6; ; Offset: 80
+ // half3 B7; ; Offset: 84
+ // half3 B8; ; Offset: 90
+
+ // } A; ; Offset: 0 Size: 96
+ auto const *A = selectFirst<RecordDecl>("A", Results);
+ unsigned SizeA = HLSLBufferDecl::calculateLegacyCbufferSize(
+ Ctx, QualType(A->getTypeForDecl(), 0));
+ ASSERT_EQ(SizeA, 96u * 8u);
+}
+
+TEST(HLSLLegacyCbufferTypeSize, ArrayTypes) {
+ constexpr char Code[] = R"hlsl(
+ namespace hlsl {
+ // built-in scalar data types:
+
+ #ifdef __HLSL_ENABLE_16_BIT
+ // 16-bit integer.
+ typedef short int16_t;
+ #endif
+
+ // 64-bit integer.
+ typedef long int64_t;
+
+ // built-in vector data types:
+
+ typedef vector<half, 2> half2;
+ typedef vector<half, 3> half3;
+ typedef vector<half, 4> half4;
+
+ typedef vector<float, 2> float2;
+ typedef vector<float, 3> float3;
+ typedef vector<float, 4> float4;
+ typedef vector<double, 2> double2;
+ typedef vector<double, 3> double3;
+ typedef vector<double, 4> double4;
+
+ } // namespace hlsl
+
+ struct A {
+ double C0[2];
+ float3 C1[3];
+ float C2;
+ double C3[3];
+ half C4;
+ double2 C5[1];
+ float C6;
+ half3 C7[2];
+ half3 C8;
+ };
+ )hlsl";
+ auto AST =
+ tooling::buildASTFromCodeWithArgs(Code,
+ /*Args=*/
+ {"--driver-mode=dxc", "-T", "lib_6_3",
+ "-enable-16bit-types", "-nostdinc"},
+ /* FileName*/ "input.hlsl");
+ ASTContext &Ctx = AST->getASTContext();
+
+ auto Results = match(decl(cxxRecordDecl(hasName("A")).bind("A")), Ctx);
+
+ // struct A
+ // {
+
+ // double C0[2]; ; Offset: 0
+ // float3 C1[3]; ; Offset: 32
+ // float C2; ; Offset: 76
+ // double C3[3]; ; Offset: 80
+ // half C4; ; Offset: 120
+ // double2 C5[1]; ; Offset: 128
+ // float C6; ; Offset: 144
+ // half3 C7[2]; ; Offset: 160
+ // half3 C8; ; Offset: 182
+
+ // } A; ; Offset: 0 Size: 188
+ auto const *A = selectFirst<RecordDecl>("A", Results);
+ unsigned SizeA = HLSLBufferDecl::calculateLegacyCbufferSize(
+ Ctx, QualType(A->getTypeForDecl(), 0));
+ ASSERT_EQ(SizeA, 188u * 8u);
+}
+
+TEST(HLSLLegacyCbufferTypeSize, Vec3) {
+ constexpr char Code[] = R"hlsl(
+ namespace hlsl {
+ // built-in scalar data types:
+
+ #ifdef __HLSL_ENABLE_16_BIT
+ // 16-bit integer.
+ typedef short int16_t;
+ #endif
+
+ // 64-bit integer.
+ typedef long int64_t;
+
+ // built-in vector data types:
+
+ typedef vector<half, 2> half2;
+ typedef vector<half, 3> half3;
+ typedef vector<half, 4> half4;
+
+ typedef vector<float, 2> float2;
+ typedef vector<float, 3> float3;
+ typedef vector<float, 4> float4;
+ typedef vector<double, 2> double2;
+ typedef vector<double, 3> double3;
+ typedef vector<double, 4> double4;
+
+ } // namespace hlsl
+
+ struct A {
+ double3 D9[3];
+ half3 D10;
+ };
+ )hlsl";
+ auto AST =
+ tooling::buildASTFromCodeWithArgs(Code,
+ /*Args=*/
+ {"--driver-mode=dxc", "-T", "lib_6_3",
+ "-enable-16bit-types", "-nostdinc"},
+ /* FileName*/ "input.hlsl");
+ ASTContext &Ctx = AST->getASTContext();
+
+ auto Results = match(decl(cxxRecordDecl(hasName("A")).bind("A")), Ctx);
+
+ // struct A
+ // {
+ //
+ // double3 D9[3]; ; Offset: 0
+ // half3 D10; ; Offset: 88
+ //
+ // } A; ; Offset: 0 Size: 94
+ auto const *A = selectFirst<RecordDecl>("A", Results);
+ unsigned SizeA = HLSLBufferDecl::calculateLegacyCbufferSize(
+ Ctx, QualType(A->getTypeForDecl(), 0));
+ ASSERT_EQ(SizeA, 94u * 8u);
+}
+
+TEST(HLSLLegacyCbufferTypeSize, NestedStruct) {
+ constexpr char Code[] = R"hlsl(
+ namespace hlsl {
+ // built-in scalar data types:
+
+ #ifdef __HLSL_ENABLE_16_BIT
+ // 16-bit integer.
+ typedef short int16_t;
+ #endif
+
+ // 64-bit integer.
+ typedef long int64_t;
+
+ // built-in vector data types:
+
+ typedef vector<half, 2> half2;
+ typedef vector<half, 3> half3;
+ typedef vector<half, 4> half4;
+
+ typedef vector<float, 2> float2;
+ typedef vector<float, 3> float3;
+ typedef vector<float, 4> float4;
+ typedef vector<double, 2> double2;
+ typedef vector<double, 3> double3;
+ typedef vector<double, 4> double4;
+
+ } // namespace hlsl
+
+ struct S0
+ {
+ double B0;
+ float3 B1;
+ float B2;
+ double3 B3;
+ half B4;
+ double2 B5;
+ float B6;
+ half3 B7;
+ half3 B8;
+ };
+
+ struct S1
+ {
+ float A0;
+ double A1;
+ float A2;
+ half A3;
+ int16_t A4;
+ int64_t A5;
+ int A6;
+ };
+
+ struct S2
+ {
+ double B0;
+ float3 B1;
+ float B2;
+ double3 B3;
+ half B4;
+ double2 B5;
+ float B6;
+ half3 B7;
+ half3 B8;
+ };
+
+ struct S3
+ {
+ S1 C0;
+ float C1[1];
+ S2 C2[2];
+ half C3;
+ };
+
+ struct A {
+ int E0;
+ S0 E1;
+ half E2;
+ S3 E3;
+ double E4;
+ };
+ )hlsl";
+
+ auto AST =
+ tooling::buildASTFromCodeWithArgs(Code,
+ /*Args=*/
+ {"--driver-mode=dxc", "-T", "lib_6_3",
+ "-enable-16bit-types", "-nostdinc"},
+ /* FileName*/ "input.hlsl");
+ ASTContext &Ctx = AST->getASTContext();
+
+ auto Results = match(decl(cxxRecordDecl(hasName("A")).bind("A")), Ctx);
+
+ // struct E
+ // {
+ // int E0; ; Offset: 0
+ // struct struct.S0
+ // {
+
+ // double B0; ; Offset: 16
+ // float3 B1; ; Offset: 32
+ // float B2; ; Offset: 44
+ // double3 B3; ; Offset: 48
+ // half B4; ; Offset: 72
+ // double2 B5; ; Offset: 80
+ // float B6; ; Offset: 96
+ // half3 B7; ; Offset: 100
+ // half3 B8; ; Offset: 106
+
+ // } E1; ; Offset: 16
+
+ // half E2; ; Offset: 112
+ // struct struct.S3
+ // {
+
+ // struct struct.S1
+ // {
+
+ // float A0; ; Offset: 128
+ // double A1; ; Offset: 136
+ // float A2; ; Offset: 144
+ // half A3; ; Offset: 148
+ // int16_t A4; ; Offset: 150
+ // int64_t A5; ; Offset: 152
+ // int A6; ; Offset: 160
+
+ // } C0; ; Offset: 128
+
+ // float C1[1]; ; Offset: 176
+ // struct struct.S2
+ // {
+
+ // double B0; ; Offset: 192
+ // float3 B1; ; Offset: 208
+ // float B2; ; Offset: 220
+ // double3 B3; ; Offset: 224
+ // half B4; ; Offset: 248
+ // double2 B5; ; Offset: 256
+ // float B6; ; Offset: 272
+ // half3 B7; ; Offset: 276
+ // half3 B8; ; Offset: 282
+
+ // } C2[2];; ; Offset: 192
+
+ // half C3; ; Offset: 384
+
+ // } E3; ; Offset: 128
+
+ // double E4; ; Offset: 392
+
+ // } E; ; Offset: 0 Size: 400
+
+ auto const *A = selectFirst<RecordDecl>("A", Results);
+ unsigned SizeA = HLSLBufferDecl::calculateLegacyCbufferSize(
+ Ctx, QualType(A->getTypeForDecl(), 0));
+ ASSERT_EQ(SizeA, 400u * 8u);
+}
+
+TEST(HLSLLegacyCbufferTypeSize, NestedStructDisable16bitTypes) {
+ constexpr char Code[] = R"hlsl(
+ namespace hlsl {
+
+ // built-in vector data types:
+
+ typedef vector<half, 2> half2;
+ typedef vector<half, 3> half3;
+ typedef vector<half, 4> half4;
+
+ typedef vector<float, 2> float2;
+ typedef vector<float, 3> float3;
+ typedef vector<float, 4> float4;
+ typedef vector<double, 2> double2;
+ typedef vector<double, 3> double3;
+ typedef vector<double, 4> double4;
+
+ } // namespace hlsl
+
+ struct S0
+ {
+ double B0;
+ float3 B1;
+ float B2;
+ double3 B3;
+ half B4;
+ double2 B5;
+ float B6;
+ half3 B7;
+ half3 B8;
+ };
+
+ struct S1
+ {
+ float A0;
+ double A1;
+ float A2;
+ half A3;
+ half A4;
+ double A5;
+ int A6;
+ };
+
+ struct S2
+ {
+ double B0;
+ float3 B1;
+ float B2;
+ double3 B3;
+ half B4;
+ double2 B5;
+ float B6;
+ half3 B7;
+ half3 B8;
+ };
+
+ struct S3
+ {
+ S1 C0;
+ float C1[1];
+ S2 C2[2];
+ half C3;
+ };
+
+ struct A {
+ int E0;
+ S0 E1;
+ half E2;
+ S3 E3;
+ double E4;
+ };
+ )hlsl";
+
+ auto AST = tooling::buildASTFromCodeWithArgs(
+ Code,
+ /*Args=*/{"--driver-mode=dxc", "-T", "lib_6_3", "-nostdinc"},
+ /* FileName*/ "input.hlsl");
+ ASTContext &Ctx = AST->getASTContext();
+
+ auto Results = match(decl(cxxRecordDecl(hasName("A")).bind("A")), Ctx);
+
+ // struct E
+ // {
+
+ // int E0; ; Offset: 0
+ // struct struct.S0
+ // {
+
+ // double B0; ; Offset: 16
+ // float3 B1; ; Offset: 32
+ // float B2; ; Offset: 44
+ // double3 B3; ; Offset: 48
+ // float B4; ; Offset: 72
+ // double2 B5; ; Offset: 80
+ // float B6; ; Offset: 96
+ // float3 B7; ; Offset: 100
+ // float3 B8; ; Offset: 112
+
+ // } E1; ; Offset: 16
+
+ // float E2; ; Offset: 124
+ // struct struct.S3
+ // {
+
+ // struct struct.S1
+ // {
+
+ // float A0; ; Offset: 128
+ // double A1; ; Offset: 136
+ // float A2; ; Offset: 144
+ // float A3; ; Offset: 148
+ // float A4; ; Offset: 152
+ // double A5; ; Offset: 160
+ // int A6; ; Offset: 168
+
+ // } C0; ; Offset: 128
+
+ // float C1[1]; ; Offset: 176
+ // struct struct.S2
+ // {
+
+ // double B0; ; Offset: 192
+ // float3 B1; ; Offset: 208
+ // float B2; ; Offset: 220
+ // double3 B3; ; Offset: 224
+ // float B4; ; Offset: 248
+ // double2 B5; ; Offset: 256
+ // float B6; ; Offset: 272
+ // float3 B7; ; Offset: 276
+ // float3 B8; ; Offset: 288
+
+ // } C2[2];; ; Offset: 192
+
+ // float C3; ; Offset: 412
+
+ // } E3; ; Offset: 128
+
+ // double E4; ; Offset: 416
+
+ // } E; ; Offset: 0 Size: 424
+
+ auto const *A = selectFirst<RecordDecl>("A", Results);
+ unsigned SizeA = HLSLBufferDecl::calculateLegacyCbufferSize(
+ Ctx, QualType(A->getTypeForDecl(), 0));
+ ASSERT_EQ(SizeA, 424u * 8u);
+}
More information about the cfe-commits
mailing list