[clang] [HLSL] Constant buffers codegen (PR #124886)
Helena Kotas via cfe-commits
cfe-commits at lists.llvm.org
Wed Feb 19 14:20:44 PST 2025
https://github.com/hekota updated https://github.com/llvm/llvm-project/pull/124886
>From 63c465b40512ad4c5fff84c0b2b022b49d46eaa7 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 28 Jan 2025 13:20:30 -0800
Subject: [PATCH 01/13] [HLSL] Constant buffer layout struct update
- create structs with public fields instead of classes with private fields
- add Packed attribute to prevent struct padding
- use __cblayout_ prefix in name
- filter out arrays of resources (bug fix)
- don't create implicit initializer for constant buffer decls
- update tests
---
clang/lib/Sema/SemaDecl.cpp | 7 +
clang/lib/Sema/SemaHLSL.cpp | 29 ++--
.../AST/HLSL/ast-dump-comment-cbuffer.hlsl | 3 -
clang/test/AST/HLSL/cbuffer.hlsl | 144 ++++++++++--------
.../test/AST/HLSL/cbuffer_and_namespaces.hlsl | 30 ++--
clang/test/AST/HLSL/pch_hlsl_buffer.hlsl | 4 +-
6 files changed, 121 insertions(+), 96 deletions(-)
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index fe68eadc951b5..ba424567b23e0 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14183,6 +14183,13 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
if (getLangOpts().OpenCL &&
Var->getType().getAddressSpace() == LangAS::opencl_local)
return;
+
+ // In HLSL, objects in the hlsl_constat address space are initialized
+ // externaly, so don't synthesize an implicit initializer.
+ if (getLangOpts().HLSL &&
+ Var->getType().getAddressSpace() == LangAS::hlsl_constant)
+ return;
+
// C++03 [dcl.init]p9:
// If no initializer is specified for an object, and the
// object is of (possibly cv-qualified) non-POD class type (or
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index aa99b44958eaf..97df01a5dd307 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -269,8 +269,11 @@ static bool isZeroSizedArray(const ConstantArrayType *CAT) {
return CAT != nullptr;
}
-// Returns true if the record type is an HLSL resource class
-static bool isResourceRecordType(const Type *Ty) {
+// Returns true if the record type is an HLSL resource class or an array of
+// HLSL resource classes
+static bool isResourceRecordTypeOrArrayOf(const Type *Ty) {
+ while (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
+ Ty = CAT->getArrayElementTypeNoTypeQual();
return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr;
}
@@ -279,11 +282,10 @@ static bool isResourceRecordType(const Type *Ty) {
// array, or a builtin intangible type. Returns false it is a valid leaf element
// type or if it is a record type that needs to be inspected further.
static bool isInvalidConstantBufferLeafElementType(const Type *Ty) {
- if (Ty->isRecordType()) {
- if (isResourceRecordType(Ty) || Ty->getAsCXXRecordDecl()->isEmpty())
- return true;
- return false;
- }
+ if (isResourceRecordTypeOrArrayOf(Ty))
+ return true;
+ if (Ty->isRecordType())
+ return Ty->getAsCXXRecordDecl()->isEmpty();
if (Ty->isConstantArrayType() &&
isZeroSizedArray(cast<ConstantArrayType>(Ty)))
return true;
@@ -339,7 +341,7 @@ static IdentifierInfo *getHostLayoutStructName(Sema &S, NamedDecl *BaseDecl,
ASTContext &AST = S.getASTContext();
IdentifierInfo *NameBaseII = BaseDecl->getIdentifier();
- llvm::SmallString<64> Name("__layout_");
+ llvm::SmallString<64> Name("__cblayout_");
if (NameBaseII) {
Name.append(NameBaseII->getName());
} else {
@@ -393,7 +395,7 @@ static FieldDecl *createFieldForHostLayoutStruct(Sema &S, const Type *Ty,
auto *Field = FieldDecl::Create(AST, LayoutStruct, SourceLocation(),
SourceLocation(), II, QT, TSI, nullptr, false,
InClassInitStyle::ICIS_NoInit);
- Field->setAccess(AccessSpecifier::AS_private);
+ Field->setAccess(AccessSpecifier::AS_public);
return Field;
}
@@ -417,9 +419,11 @@ static CXXRecordDecl *createHostLayoutStruct(Sema &S,
if (CXXRecordDecl *RD = findRecordDeclInContext(II, DC))
return RD;
- CXXRecordDecl *LS = CXXRecordDecl::Create(
- AST, TagDecl::TagKind::Class, DC, SourceLocation(), SourceLocation(), II);
+ CXXRecordDecl *LS =
+ CXXRecordDecl::Create(AST, TagDecl::TagKind::Struct, DC, SourceLocation(),
+ SourceLocation(), II);
LS->setImplicit(true);
+ LS->addAttr(PackedAttr::CreateImplicit(AST));
LS->startDefinition();
// copy base struct, create HLSL Buffer compatible version if needed
@@ -472,8 +476,9 @@ void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) {
IdentifierInfo *II = getHostLayoutStructName(S, BufDecl, true);
CXXRecordDecl *LS =
- CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, BufDecl,
+ CXXRecordDecl::Create(AST, TagDecl::TagKind::Struct, BufDecl,
SourceLocation(), SourceLocation(), II);
+ LS->addAttr(PackedAttr::CreateImplicit(AST));
LS->setImplicit(true);
LS->startDefinition();
diff --git a/clang/test/AST/HLSL/ast-dump-comment-cbuffer.hlsl b/clang/test/AST/HLSL/ast-dump-comment-cbuffer.hlsl
index b2b3e13308da3..eca2ed0211d1b 100644
--- a/clang/test/AST/HLSL/ast-dump-comment-cbuffer.hlsl
+++ b/clang/test/AST/HLSL/ast-dump-comment-cbuffer.hlsl
@@ -27,6 +27,3 @@ cbuffer A {
// AST-NEXT: TextComment {{.*}} Text=" CBuffer decl."
// AST-NEXT: VarDecl {{.*}} a 'hlsl_constant float'
// AST-NEXT: VarDecl {{.*}} b 'hlsl_constant int'
-// AST-NEXT: CXXRecordDecl {{.*}} implicit class __layout_A definition
-// AST: FieldDecl {{.*}} a 'float'
-// AST-NEXT: FieldDecl {{.*}} b 'int'
diff --git a/clang/test/AST/HLSL/cbuffer.hlsl b/clang/test/AST/HLSL/cbuffer.hlsl
index f516cf5099e82..8254f0ee00b14 100644
--- a/clang/test/AST/HLSL/cbuffer.hlsl
+++ b/clang/test/AST/HLSL/cbuffer.hlsl
@@ -48,75 +48,83 @@ struct TwoFloats {
// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
cbuffer CB {
- // CHECK: VarDecl {{.*}} col:9 used a1 'hlsl_constant float'
+ // CHECK: VarDecl {{.*}} used a1 'hlsl_constant float'
float a1;
- // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB definition
- // CHECK: FieldDecl {{.*}} a1 'float'
+ // CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB definition
+ // CHECK: PackedAttr
+ // CHECK-NEXT: FieldDecl {{.*}} a1 'float'
}
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __layout_CB), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __cblayout_CB), "");
// Check that buffer layout struct does not include resources or empty types
-// CHECK: HLSLBufferDecl {{.*}} line:62:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 3]]:9 cbuffer CB
// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
cbuffer CB {
- // CHECK: VarDecl {{.*}} col:9 used a2 'hlsl_constant float'
+ // CHECK: VarDecl {{.*}} used a2 'hlsl_constant float'
float a2;
- // CHECK: VarDecl {{.*}} col:19 b2 'RWBuffer<float>':'hlsl::RWBuffer<float>'
+ // CHECK: VarDecl {{.*}} b2 'RWBuffer<float>':'hlsl::RWBuffer<float>'
RWBuffer<float> b2;
- // CHECK: VarDecl {{.*}} col:15 c2 'EmptyStruct'
+ // CHECK: VarDecl {{.*}} c2 'EmptyStruct'
EmptyStruct c2;
- // CHECK: VarDecl {{.*}} col:9 d2 'float[0]'
+ // CHECK: VarDecl {{.*}} d2 'float[0]'
float d2[0];
- // CHECK: VarDecl {{.*}} col:9 e2 'hlsl_constant float'
+ // CHECK: VarDecl {{.*}} f2 'RWBuffer<float>[2]'
+ RWBuffer<float> f2[2];
+ // CHECK: VarDecl {{.*}} e2 'hlsl_constant float'
float e2;
- // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_1 definition
- // CHECK: FieldDecl {{.*}} a2 'float'
+ // CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB_1 definition
+ // CHECK: PackedAttr
+ // CHECK-NEXT: FieldDecl {{.*}} a2 'float'
// CHECK-NEXT: FieldDecl {{.*}} e2 'float'
}
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __layout_CB_1), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __cblayout_CB_1), "");
// Check that layout struct is created for B and the empty struct C is removed
-// CHECK: HLSLBufferDecl {{.*}} line:83:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 3]]:9 cbuffer CB
// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
cbuffer CB {
- // CHECK: VarDecl {{.*}} col:5 used s1 'hlsl_constant A'
+ // CHECK: VarDecl {{.*}} used s1 'hlsl_constant A'
A s1;
- // CHECK: VarDecl {{.*}} col:5 s2 'hlsl_constant B'
+ // CHECK: VarDecl {{.*}} s2 'hlsl_constant B'
B s2;
- // CHECK: VarDecl {{.*}} col:12 s3 'CTypedef':'C'
+ // CHECK: VarDecl {{.*}} s3 'CTypedef':'C'
CTypedef s3;
- // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_2 definition
- // CHECK: FieldDecl {{.*}} s1 'A'
- // CHECK: FieldDecl {{.*}} s2 '__layout_B'
+ // CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB_2 definition
+ // CHECK: PackedAttr
+ // CHECK-NEXT: FieldDecl {{.*}} s1 'A'
+ // CHECK-NEXT: FieldDecl {{.*}} s2 '__cblayout_B'
}
-// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_B definition
-// CHECK: FieldDecl {{.*}} a 'float'
+// CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_B definition
+// CHECK: PackedAttr
+// CHECK-NEXT: FieldDecl {{.*}} a 'float'
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __layout_B), "");
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __layout_CB_2), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __cblayout_B), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __cblayout_CB_2), "");
// check that layout struct is created for D because of its base struct
-// CHECK: HLSLBufferDecl {{.*}} line:104:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 3]]:9 cbuffer CB
// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
cbuffer CB {
// CHECK: VarDecl {{.*}} s4 'hlsl_constant D'
D s4;
- // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_3 definition
- // CHECK: FieldDecl {{.*}} s4 '__layout_D'
+ // CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB_3 definition
+ // CHECK: PackedAttr
+ // CHECK-NEXT: FieldDecl {{.*}} s4 '__cblayout_D'
}
- // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_D definition
- // CHECK: public '__layout_B'
- // CHECK: FieldDecl {{.*}} b 'float'
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __layout_D), "");
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __layout_CB_3), "");
+ // CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_D definition
+ // CHECK: public '__cblayout_B'
+ // CHECK: PackedAttr
+ // CHECK-NEXT: FieldDecl {{.*}} b 'float'
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __cblayout_D), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __cblayout_CB_3), "");
// check that layout struct is created for E because because its base struct
// is empty and should be eliminated, and BTypedef should reuse the previously
-// defined '__layout_B'
-// CHECK: HLSLBufferDecl {{.*}} line:122:9 cbuffer CB
+// defined '__cblayout_B'
+// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 3]]:9 cbuffer CB
// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
cbuffer CB {
@@ -124,18 +132,20 @@ cbuffer CB {
E s5;
// CHECK: VarDecl {{.*}} s6 'hlsl_constant BTypedef':'hlsl_constant B'
BTypedef s6;
- // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_4 definition
- // CHECK: FieldDecl {{.*}} s5 '__layout_E'
- // CHECK: FieldDecl {{.*}} s6 '__layout_B'
+ // CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB_4 definition
+ // CHECK: PackedAttr
+ // CHECK-NEXT: FieldDecl {{.*}} s5 '__cblayout_E'
+ // CHECK-NEXT: FieldDecl {{.*}} s6 '__cblayout_B'
}
- // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_E definition
- // CHECK: FieldDecl {{.*}} c 'float'
- // CHECK-NOT: CXXRecordDecl {{.*}} class __layout_B definition
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __layout_E), "");
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __layout_CB_4), "");
+// CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_E definition
+// CHECK: PackedAttr
+// CHECK-NEXT: FieldDecl {{.*}} c 'float'
+// CHECK-NOT: CXXRecordDecl {{.*}} struct __cblayout_B definition
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __cblayout_E), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __cblayout_CB_4), "");
// check that this produces empty layout struct
-// CHECK: HLSLBufferDecl {{.*}} line:141:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 3]]:9 cbuffer CB
// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
cbuffer CB {
@@ -149,27 +159,30 @@ cbuffer CB {
RWBuffer<float> Buf;
// CHECK: VarDecl {{.*}} ea 'EmptyArrayTypedef':'float[10][0]'
EmptyArrayTypedef ea;
- // CHECK: CXXRecordDecl {{.*}} implicit class __layout_CB_5 definition
+ // CHECK: CXXRecordDecl {{.*}} implicit struct __cblayout_CB_5 definition
+ // CHECK: PackedAttr
// CHECK-NOT: FieldDecl
}
// check host layout struct with compatible base struct
-// CHECK: HLSLBufferDecl {{.*}} line:160:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 3]]:9 cbuffer CB
// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
cbuffer CB {
// CHECK: VarDecl {{.*}} s8 'hlsl_constant F'
F s8;
- // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_6 definition
- // CHECK: FieldDecl {{.*}} s8 '__layout_F'
+ // CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB_6 definition
+ // CHECK: PackedAttr
+ // CHECK-NEXT: FieldDecl {{.*}} s8 '__cblayout_F'
}
- // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_F definition
- // CHECK: public 'A'
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __layout_F), "");
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __layout_CB_6), "");
+// CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_F definition
+// CHECK: public 'A'
+// CHECK: PackedAttr
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __cblayout_F), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __cblayout_CB_6), "");
// anonymous structs
-// CHECK: HLSLBufferDecl {{.*}} line:175:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 3]]:9 cbuffer CB
// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
cbuffer CB {
@@ -182,7 +195,7 @@ cbuffer CB {
// CHECK: FieldDecl {{.*}} f 'RWBuffer<float>':'hlsl::RWBuffer<float>'
RWBuffer<float> f;
} s9;
- // CHECK: VarDecl {{.*}} s9 'hlsl_constant struct (unnamed struct at {{.*}}cbuffer.hlsl:177:3
+ // CHECK: VarDecl {{.*}} s9 'hlsl_constant struct (unnamed struct at {{.*}}cbuffer.hlsl:[[# @LINE - 8]]:3
// CHECK: CXXRecordDecl {{.*}} struct definition
struct {
// CHECK: FieldDecl {{.*}} g 'float'
@@ -190,18 +203,21 @@ cbuffer CB {
// CHECK: FieldDecl {{.*}} f 'RWBuffer<float>':'hlsl::RWBuffer<float>'
RWBuffer<float> f;
} s10;
- // CHECK: VarDecl {{.*}} s10 'hlsl_constant struct (unnamed struct at {{.*}}cbuffer.hlsl:187:3
- // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_anon definition
- // CHECK: FieldDecl {{.*}} e 'float'
- // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_anon_1 definition
- // CHECK: FieldDecl {{.*}} g 'float'
- // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_7 definition
- // CHECK: FieldDecl {{.*}} s9 '__layout_anon'
- // CHECK: FieldDecl {{.*}} s10 '__layout_anon_1'
+ // CHECK: VarDecl {{.*}} s10 'hlsl_constant struct (unnamed struct at {{.*}}cbuffer.hlsl:[[# @LINE - 6]]:3
+ // CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_anon definition
+ // CHECK: PackedAttr
+ // CHECK-NEXT: FieldDecl {{.*}} e 'float'
+ // CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_anon_1 definition
+ // CHECK: PackedAttr
+ // CHECK-NEXT: FieldDecl {{.*}} g 'float'
+ // CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB_7 definition
+ // CHECK: PackedAttr
+ // CHECK-NEXT: FieldDecl {{.*}} s9 '__cblayout_anon'
+ // CHECK-NEXT: FieldDecl {{.*}} s10 '__cblayout_anon_1'
}
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __layout_anon), "");
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __layout_anon_1), "");
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __layout_CB_7), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __cblayout_anon), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, __cblayout_anon_1), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __cblayout_CB_7), "");
// Add uses for the constant buffer declarations so they are not optimized away
export float foo() {
diff --git a/clang/test/AST/HLSL/cbuffer_and_namespaces.hlsl b/clang/test/AST/HLSL/cbuffer_and_namespaces.hlsl
index 12ce327d8be02..09596eda90b6a 100644
--- a/clang/test/AST/HLSL/cbuffer_and_namespaces.hlsl
+++ b/clang/test/AST/HLSL/cbuffer_and_namespaces.hlsl
@@ -19,10 +19,10 @@ namespace NS1 {
int b;
EmptyStruct es;
};
- // CHECK: CXXRecordDecl {{.*}} implicit class __layout_Foo definition
+ // CHECK: CXXRecordDecl {{.*}} implicit struct __cblayout_Foo definition
// CHECK: FieldDecl {{.*}} b 'int'
};
- // CHECK: CXXRecordDecl {{.*}} implicit class __layout_Foo definition
+ // CHECK: CXXRecordDecl {{.*}} implicit struct __cblayout_Foo definition
// CHECK: FieldDecl {{.*}} a 'float'
}
@@ -41,12 +41,12 @@ cbuffer CB1 {
NS1::Foo foo2;
// CHECK: VarDecl {{.*}} foo3 'hlsl_constant NS1::Bar::Foo'
NS1::Bar::Foo foo3;
- // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB1 definition
- // CHECK: FieldDecl {{.*}} foo1 '__layout_Foo'
- // CHECK: FieldDecl {{.*}} foo2 'NS1::__layout_Foo'
- // CHECK: FieldDecl {{.*}} foo3 'NS1::Bar::__layout_Foo'
+ // CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB1 definition
+ // CHECK: FieldDecl {{.*}} foo1 '__cblayout_Foo'
+ // CHECK: FieldDecl {{.*}} foo2 'NS1::__cblayout_Foo'
+ // CHECK: FieldDecl {{.*}} foo3 'NS1::Bar::__cblayout_Foo'
}
-// CHECK: CXXRecordDecl {{.*}} implicit class __layout_Foo definition
+// CHECK: CXXRecordDecl {{.*}} implicit struct __cblayout_Foo definition
// CHECK: FieldDecl {{.*}} c 'double'
struct CB1ExpectedShape {
@@ -54,7 +54,7 @@ struct CB1ExpectedShape {
float a2;
int a;
};
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(CB1ExpectedShape, __layout_CB1), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(CB1ExpectedShape, __cblayout_CB1), "");
namespace NS2 {
struct Foo {
@@ -73,13 +73,13 @@ namespace NS2 {
NS1::Foo foo2;
// CHECK: VarDecl {{.*}} foo3 'hlsl_constant NS1::Bar::Foo'
NS1::Bar::Foo foo3;
- // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB2 definition
- // CHECK: FieldDecl {{.*}} foo0 '__layout_Foo'
- // CHECK: FieldDecl {{.*}} foo1 'NS2::__layout_Foo'
- // CHECK: FieldDecl {{.*}} foo2 'NS1::__layout_Foo'
- // CHECK: FieldDecl {{.*}} foo3 'NS1::Bar::__layout_Foo'
+ // CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB2 definition
+ // CHECK: FieldDecl {{.*}} foo0 '__cblayout_Foo'
+ // CHECK: FieldDecl {{.*}} foo1 'NS2::__cblayout_Foo'
+ // CHECK: FieldDecl {{.*}} foo2 'NS1::__cblayout_Foo'
+ // CHECK: FieldDecl {{.*}} foo3 'NS1::Bar::__cblayout_Foo'
}
- // CHECK: CXXRecordDecl {{.*}} implicit class __layout_Foo definition
+ // CHECK: CXXRecordDecl {{.*}} implicit struct __cblayout_Foo definition
// CHECK: FieldDecl {{.*}} d 'float[4]'
}
@@ -89,7 +89,7 @@ struct CB2ExpectedShape {
float a2;
int a;
};
-_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(CB2ExpectedShape, NS2::__layout_CB2), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(CB2ExpectedShape, NS2::__cblayout_CB2), "");
// Add uses for the constant buffer declarations so they are not optimized away
// CHECK: ExportDecl
diff --git a/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl b/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
index 98d7aba397852..754948931ee53 100644
--- a/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
+++ b/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
@@ -21,14 +21,14 @@ float foo() {
// CHECK-NEXT: HLSLResourceClassAttr {{.*}} Implicit CBuffer
// CHECK-NEXT: HLSLResourceAttr {{.*}} Implicit CBuffer
// CHECK-NEXT: VarDecl 0x[[A:[0-9a-f]+]] {{.*}} imported used a 'hlsl_constant float'
-// CHECK-NEXT: CXXRecordDecl {{.*}} imported implicit <undeserialized declarations> class __layout_A definition
+// CHECK-NEXT: CXXRecordDecl {{.*}} imported implicit <undeserialized declarations> struct __cblayout_A definition
// CHECK: FieldDecl {{.*}} imported a 'float'
// CHECK: HLSLBufferDecl {{.*}} line:11:9 imported <undeserialized declarations> tbuffer B
// CHECK-NEXT: HLSLResourceClassAttr {{.*}} Implicit SRV
// CHECK-NEXT: HLSLResourceAttr {{.*}} Implicit TBuffer
// CHECK-NEXT: VarDecl 0x[[B:[0-9a-f]+]] {{.*}} imported used b 'hlsl_constant float'
-// CHECK-NEXT: CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} imported implicit <undeserialized declarations> class __layout_B definition
+// CHECK-NEXT: CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} imported implicit <undeserialized declarations> struct __cblayout_B definition
// CHECK: FieldDecl 0x{{[0-9a-f]+}} {{.*}} imported b 'float'
// CHECK-NEXT: FunctionDecl {{.*}} line:15:7 imported foo 'float ()'
>From c80415a22bf9b1e06928e84d8d0efa646fbaa5f9 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 28 Jan 2025 16:52:45 -0800
Subject: [PATCH 02/13] filter groupshared var decls
---
clang/lib/Sema/SemaHLSL.cpp | 3 ++-
clang/test/AST/HLSL/cbuffer.hlsl | 2 ++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 97df01a5dd307..b71dd2b273a1c 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -484,7 +484,8 @@ void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) {
for (Decl *D : BufDecl->decls()) {
VarDecl *VD = dyn_cast<VarDecl>(D);
- if (!VD || VD->getStorageClass() == SC_Static)
+ if (!VD || VD->getStorageClass() == SC_Static ||
+ VD->getType().getAddressSpace() == LangAS::hlsl_groupshared)
continue;
const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
if (FieldDecl *FD =
diff --git a/clang/test/AST/HLSL/cbuffer.hlsl b/clang/test/AST/HLSL/cbuffer.hlsl
index 8254f0ee00b14..865db1201baa5 100644
--- a/clang/test/AST/HLSL/cbuffer.hlsl
+++ b/clang/test/AST/HLSL/cbuffer.hlsl
@@ -71,6 +71,8 @@ cbuffer CB {
float d2[0];
// CHECK: VarDecl {{.*}} f2 'RWBuffer<float>[2]'
RWBuffer<float> f2[2];
+ // CHECK: VarDecl {{.*}} g2 'groupshared float'
+ groupshared float g2;
// CHECK: VarDecl {{.*}} e2 'hlsl_constant float'
float e2;
// CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB_1 definition
>From cf08adb6b9e181613e81d2cfbadbbb68e645fe33 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 28 Jan 2025 14:46:26 -0800
Subject: [PATCH 03/13] [HLSL] Translate cbuffer declarations to target type
dx.CBuffer - initial commit
---
clang/include/clang/AST/Decl.h | 6 +
clang/include/clang/AST/Type.h | 4 +-
clang/lib/AST/Decl.cpp | 17 +-
clang/lib/CodeGen/CGHLSLRuntime.cpp | 409 ++++++++++++------
clang/lib/CodeGen/CGHLSLRuntime.h | 31 +-
clang/lib/CodeGen/Targets/DirectX.cpp | 11 +-
clang/lib/Sema/SemaHLSL.cpp | 3 +
clang/test/CodeGenHLSL/cbuf.hlsl | 33 --
clang/test/CodeGenHLSL/cbuf_in_namespace.hlsl | 29 --
clang/test/CodeGenHLSL/cbuffer.hlsl | 200 +++++++++
.../CodeGenHLSL/cbuffer_and_namespaces.hlsl | 63 +++
.../CodeGenHLSL/cbuffer_with_packoffset.hlsl | 40 ++
...uffer_with_static_global_and_function.hlsl | 32 ++
clang/test/CodeGenHLSL/resource-bindings.hlsl | 4 +
.../static_global_and_function_in_cb.hlsl | 22 -
15 files changed, 679 insertions(+), 225 deletions(-)
delete mode 100644 clang/test/CodeGenHLSL/cbuf.hlsl
delete mode 100644 clang/test/CodeGenHLSL/cbuf_in_namespace.hlsl
create mode 100644 clang/test/CodeGenHLSL/cbuffer.hlsl
create mode 100644 clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl
create mode 100644 clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
create mode 100644 clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl
delete mode 100644 clang/test/CodeGenHLSL/static_global_and_function_in_cb.hlsl
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 16403774e72b3..e1c7e3817699c 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -5032,6 +5032,9 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext {
SourceLocation KwLoc;
/// IsCBuffer - Whether the buffer is a cbuffer (and not a tbuffer).
bool IsCBuffer;
+ /// HasValidPackoffset - Whether the buffer has valid packoffset annotations
+ // on all declarations
+ bool HasPackoffset;
HLSLBufferDecl(DeclContext *DC, bool CBuffer, SourceLocation KwLoc,
IdentifierInfo *ID, SourceLocation IDLoc,
@@ -5052,6 +5055,9 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext {
SourceLocation getRBraceLoc() const { return RBraceLoc; }
void setRBraceLoc(SourceLocation L) { RBraceLoc = L; }
bool isCBuffer() const { return IsCBuffer; }
+ void setHasPackoffset(bool PO) { HasPackoffset = PO; }
+ bool hasPackoffset() const { return HasPackoffset; }
+ const CXXRecordDecl *getLayoutStruct() const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 1d9743520654e..c3ff7ebd88516 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -6266,8 +6266,8 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
LLVM_PREFERRED_TYPE(bool)
uint8_t RawBuffer : 1;
- Attributes(llvm::dxil::ResourceClass ResourceClass, bool IsROV,
- bool RawBuffer)
+ Attributes(llvm::dxil::ResourceClass ResourceClass, bool IsROV = false,
+ bool RawBuffer = false)
: ResourceClass(ResourceClass), IsROV(IsROV), RawBuffer(RawBuffer) {}
Attributes() : Attributes(llvm::dxil::ResourceClass::UAV, false, false) {}
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index beb5fcaefac53..fa7d03354a993 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -1747,6 +1747,10 @@ void NamedDecl::printNestedNameSpecifier(raw_ostream &OS,
}
}
+ // Suppress transparent contexts like export or HLSLBufferDecl context
+ if (Ctx->isTransparentContext())
+ continue;
+
// Skip non-named contexts such as linkage specifications and ExportDecls.
const NamedDecl *ND = dyn_cast<NamedDecl>(Ctx);
if (!ND)
@@ -5713,7 +5717,7 @@ HLSLBufferDecl::HLSLBufferDecl(DeclContext *DC, bool CBuffer,
SourceLocation IDLoc, SourceLocation LBrace)
: NamedDecl(Decl::Kind::HLSLBuffer, DC, IDLoc, DeclarationName(ID)),
DeclContext(Decl::Kind::HLSLBuffer), LBraceLoc(LBrace), KwLoc(KwLoc),
- IsCBuffer(CBuffer) {}
+ IsCBuffer(CBuffer), HasPackoffset(false) {}
HLSLBufferDecl *HLSLBufferDecl::Create(ASTContext &C,
DeclContext *LexicalParent, bool CBuffer,
@@ -5743,6 +5747,17 @@ HLSLBufferDecl *HLSLBufferDecl::CreateDeserialized(ASTContext &C,
SourceLocation(), SourceLocation());
}
+const CXXRecordDecl *HLSLBufferDecl::getLayoutStruct() const {
+ // Layout struct is the last decl in the HLSLBufferDecl.
+ if (CXXRecordDecl *RD = llvm::dyn_cast_or_null<CXXRecordDecl>(LastDecl)) {
+ assert(RD->getName().starts_with(
+ ("__cblayout_" + getIdentifier()->getName()).str()) &&
+ "expected buffer layout struct");
+ return RD;
+ }
+ llvm_unreachable("HLSL buffer is missing a layout struct");
+}
+
//===----------------------------------------------------------------------===//
// ImportDecl Implementation
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 2ce54cc3c52ef..d3d9d42664359 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -16,15 +16,20 @@
#include "CGDebugInfo.h"
#include "CodeGenModule.h"
#include "TargetInfo.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/Type.h"
#include "clang/Basic/TargetOptions.h"
+#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
+#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/Alignment.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormatVariadic.h"
using namespace clang;
@@ -32,6 +37,9 @@ using namespace CodeGen;
using namespace clang::hlsl;
using namespace llvm;
+static void createResourceInitFn(CodeGenModule &CGM, llvm::GlobalVariable *GV,
+ unsigned Slot, unsigned Space);
+
namespace {
void addDxilValVersion(StringRef ValVersionStr, llvm::Module &M) {
@@ -54,54 +62,11 @@ void addDxilValVersion(StringRef ValVersionStr, llvm::Module &M) {
auto *DXILValMD = M.getOrInsertNamedMetadata(DXILValKey);
DXILValMD->addOperand(Val);
}
+
void addDisableOptimizations(llvm::Module &M) {
StringRef Key = "dx.disable_optimizations";
M.addModuleFlag(llvm::Module::ModFlagBehavior::Override, Key, 1);
}
-// cbuffer will be translated into global variable in special address space.
-// If translate into C,
-// cbuffer A {
-// float a;
-// float b;
-// }
-// float foo() { return a + b; }
-//
-// will be translated into
-//
-// struct A {
-// float a;
-// float b;
-// } cbuffer_A __attribute__((address_space(4)));
-// float foo() { return cbuffer_A.a + cbuffer_A.b; }
-//
-// layoutBuffer will create the struct A type.
-// replaceBuffer will replace use of global variable a and b with cbuffer_A.a
-// and cbuffer_A.b.
-//
-void layoutBuffer(CGHLSLRuntime::Buffer &Buf, const DataLayout &DL) {
- if (Buf.Constants.empty())
- return;
-
- std::vector<llvm::Type *> EltTys;
- for (auto &Const : Buf.Constants) {
- GlobalVariable *GV = Const.first;
- Const.second = EltTys.size();
- llvm::Type *Ty = GV->getValueType();
- EltTys.emplace_back(Ty);
- }
- Buf.LayoutStruct = llvm::StructType::get(EltTys[0]->getContext(), EltTys);
-}
-
-GlobalVariable *replaceBuffer(CGHLSLRuntime::Buffer &Buf) {
- // Create global variable for CB.
- GlobalVariable *CBGV = new GlobalVariable(
- Buf.LayoutStruct, /*isConstant*/ true,
- GlobalValue::LinkageTypes::ExternalLinkage, nullptr,
- llvm::formatv("{0}{1}", Buf.Name, Buf.IsCBuffer ? ".cb." : ".tb."),
- GlobalValue::NotThreadLocal);
-
- return CBGV;
-}
} // namespace
@@ -119,48 +84,280 @@ llvm::Triple::ArchType CGHLSLRuntime::getArch() {
return CGM.getTarget().getTriple().getArch();
}
-void CGHLSLRuntime::addConstant(VarDecl *D, Buffer &CB) {
- if (D->getStorageClass() == SC_Static) {
- // For static inside cbuffer, take as global static.
- // Don't add to cbuffer.
- CGM.EmitGlobal(D);
- return;
+// Returns true if the type is an HLSL resource class
+static bool isResourceRecordType(const clang::Type *Ty) {
+ return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr;
+}
+
+// Returns true if the type is an HLSL resource class or an array of
+// HLSL resource classes
+static bool isResourceRecordTypeOrArrayOf(const clang::Type *Ty) {
+ while (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
+ Ty = CAT->getArrayElementTypeNoTypeQual();
+ return isResourceRecordType(Ty);
+}
+
+static ConstantAsMetadata *getConstIntMetadata(LLVMContext &Ctx, uint32_t value,
+ bool isSigned = false) {
+ return ConstantAsMetadata::get(
+ ConstantInt::get(Ctx, llvm::APInt(32, value, isSigned)));
+}
+
+static unsigned getScalarOrVectorSize(llvm::Type *Ty) {
+ assert(Ty->isVectorTy() || Ty->isIntegerTy() || Ty->isFloatingPointTy());
+ if (Ty->isVectorTy()) {
+ llvm::FixedVectorType *FVT = cast<llvm::FixedVectorType>(Ty);
+ return FVT->getNumElements() *
+ (FVT->getElementType()->getScalarSizeInBits() / 8);
+ }
+ return Ty->getScalarSizeInBits() / 8;
+}
+
+size_t
+CGHLSLRuntime::getOrCalculateStructSizeForBuffer(llvm::StructType *StructTy) {
+ assert(StructTy->isStructTy());
+
+ // check if we already have a side for this struct
+ auto SizeIt = StructSizesForBuffer.find(StructTy);
+ if (SizeIt != StructSizesForBuffer.end())
+ return SizeIt->getSecond();
+
+ // if not, calculate the struct layout and add it to metadata
+ LLVMContext &Ctx = CGM.getLLVMContext();
+ SmallVector<llvm::Metadata *> LayoutItems;
+ LayoutItems.push_back(MDString::get(Ctx, StructTy->getName()));
+
+ size_t StructSize = 0;
+ LayoutItems.push_back(nullptr); // reserve one slot for the buffer size
+
+ for (llvm::Type *ElTy : StructTy->elements())
+ addLayoutInfoForBufferElement(StructSize, LayoutItems, ElTy);
+
+ // set the size of the buffer
+ LayoutItems[1] = getConstIntMetadata(Ctx, StructSize);
+
+ // add the struct layout info to metadata
+ MDNode *LayoutMDNode = MDNode::get(CGM.getLLVMContext(), LayoutItems);
+ CGM.getModule()
+ .getOrInsertNamedMetadata("hlsl.cblayouts")
+ ->addOperand(LayoutMDNode);
+
+ // add struct size to list and return it
+ StructSizesForBuffer[StructTy] = StructSize;
+ return StructSize;
+}
+
+void CGHLSLRuntime::addLayoutInfoForBufferElement(
+ size_t &EndOffset, SmallVector<llvm::Metadata *> &LayoutItems,
+ llvm::Type *LayoutTy, HLSLPackOffsetAttr *PackoffsetAttr) {
+
+ // calculate element offset and size; for arrays also calculate array
+ // element count and stride
+ size_t ElemOffset = 0;
+ size_t ElemSize = 0;
+ size_t ArrayCount = 1;
+ size_t ArrayStride = 0;
+ size_t NextRowOffset = llvm::alignTo(EndOffset, 16U);
+
+ if (LayoutTy->isArrayTy()) {
+ llvm::Type *Ty = LayoutTy;
+ while (Ty->isArrayTy()) {
+ ArrayCount *= Ty->getArrayNumElements();
+ Ty = Ty->getArrayElementType();
+ }
+ ElemSize =
+ Ty->isStructTy()
+ ? getOrCalculateStructSizeForBuffer(cast<llvm::StructType>(Ty))
+ : getScalarOrVectorSize(Ty);
+ ArrayStride = llvm::alignTo(ElemSize, 16U);
+ ElemOffset =
+ PackoffsetAttr ? PackoffsetAttr->getOffsetInBytes() : NextRowOffset;
+
+ } else if (LayoutTy->isStructTy()) {
+ ElemOffset =
+ PackoffsetAttr ? PackoffsetAttr->getOffsetInBytes() : NextRowOffset;
+ ElemSize =
+ getOrCalculateStructSizeForBuffer(cast<llvm::StructType>(LayoutTy));
+
+ } else {
+ size_t Align = 0;
+ if (LayoutTy->isVectorTy()) {
+ llvm::FixedVectorType *FVT = cast<llvm::FixedVectorType>(LayoutTy);
+ size_t SubElemSize = FVT->getElementType()->getScalarSizeInBits() / 8;
+ ElemSize = FVT->getNumElements() * SubElemSize;
+ Align = SubElemSize;
+ } else {
+ assert(LayoutTy->isIntegerTy() || LayoutTy->isFloatingPointTy());
+ ElemSize = LayoutTy->getScalarSizeInBits() / 8;
+ Align = ElemSize;
+ }
+ if (PackoffsetAttr) {
+ ElemOffset = PackoffsetAttr->getOffsetInBytes();
+ } else {
+ ElemOffset = llvm::alignTo(EndOffset, Align);
+ if (ElemOffset + ElemSize > NextRowOffset)
+ ElemOffset = NextRowOffset;
+ }
}
- auto *GV = cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(D));
- GV->setExternallyInitialized(true);
- // Add debug info for constVal.
- if (CGDebugInfo *DI = CGM.getModuleDebugInfo())
- if (CGM.getCodeGenOpts().getDebugInfo() >=
- 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));
+ // Update end offset of the buffer/struct layout; do not update it if
+ // the provided EndOffset is already bigger than the new one (which may happen
+ // with packoffset annotations)
+ unsigned NewEndOffset =
+ ElemOffset + (ArrayCount - 1) * ArrayStride + ElemSize;
+ EndOffset = std::max<size_t>(EndOffset, NewEndOffset);
+
+ // create metadata constan with the offset and stride and add to list
+ LayoutItems.push_back(getConstIntMetadata(CGM.getLLVMContext(), ElemOffset));
+ if (ArrayStride)
+ LayoutItems.push_back(
+ getConstIntMetadata(CGM.getLLVMContext(), ArrayStride));
}
-void CGHLSLRuntime::addBufferDecls(const DeclContext *DC, Buffer &CB) {
- for (Decl *it : DC->decls()) {
- if (auto *ConstDecl = dyn_cast<VarDecl>(it)) {
- addConstant(ConstDecl, CB);
- } else if (isa<CXXRecordDecl, EmptyDecl>(it)) {
+void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
+ llvm::GlobalVariable *BufGV) {
+ llvm::StructType *LayoutStruct = cast<llvm::StructType>(
+ cast<llvm::TargetExtType>(BufGV->getValueType())->getTypeParameter(0));
+
+ LLVMContext &Ctx = CGM.getLLVMContext();
+
+ SmallVector<llvm::Metadata *> BufGlobals;
+ BufGlobals.push_back(ValueAsMetadata::get(BufGV));
+
+ SmallVector<llvm::Metadata *> LayoutItems;
+ LayoutItems.push_back(MDString::get(Ctx, LayoutStruct->getName()));
+
+ size_t BufferSize = 0;
+ size_t BufferSizeIndex = LayoutItems.size();
+ LayoutItems.push_back(nullptr); // reserve one slot for the buffer size
+
+ bool UsePackoffset = BufDecl->hasPackoffset();
+
+ const auto *ElemIt = LayoutStruct->element_begin();
+ for (Decl *D : BufDecl->decls()) {
+ if (isa<CXXRecordDecl, EmptyDecl>(D))
// Nothing to do for this declaration.
- } else if (isa<FunctionDecl>(it)) {
+ continue;
+ if (isa<FunctionDecl>(D)) {
// A function within an cbuffer is effectively a top-level function,
// as it only refers to globally scoped declarations.
- CGM.EmitTopLevelDecl(it);
+ CGM.EmitTopLevelDecl(D);
+ continue;
+ }
+ if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ QualType VDTy = VD->getType();
+ if (VDTy.getAddressSpace() != LangAS::hlsl_constant) {
+ if (VD->getStorageClass() == SC_Static ||
+ isResourceRecordTypeOrArrayOf(VDTy.getTypePtr())) {
+ // Emit static variables and resource classes inside cbuffer as
+ // regular globals
+ CGM.EmitGlobal(VD);
+ }
+ // Anything else that is not in the hlsl_constant address space must be
+ // an empty struct or a zero-sized array and can be ignored
+ continue;
+ }
+
+ assert(ElemIt != LayoutStruct->element_end() &&
+ "number of elements in layout struct does not match");
+ llvm::Type *LayoutType = *ElemIt++;
+
+ assert((CGM.getTypes().ConvertTypeForMem(VDTy) == LayoutType ||
+ (LayoutType->isStructTy() &&
+ cast<llvm::StructType>(LayoutType)
+ ->getName()
+ .starts_with(("struct.__cblayout_" +
+ VDTy->getAsCXXRecordDecl()->getName())
+ .str()))) &&
+ "layout type does not match the converted element type");
+
+ // handle any resources declarations inside the struct
+ if (VDTy->isStructureType() && VDTy->isHLSLIntangibleType())
+ // FIXME: handle resources in cbuffer structs
+ llvm_unreachable("resources in cbuffer are not supported yet");
+
+ GlobalVariable *ElemGV =
+ cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(VD, LayoutType));
+ BufGlobals.push_back(ValueAsMetadata::get(ElemGV));
+
+ assert(((UsePackoffset && VD->hasAttr<HLSLPackOffsetAttr>()) ||
+ !UsePackoffset) &&
+ "expected packoffset attribute on every declaration");
+
+ addLayoutInfoForBufferElement(
+ BufferSize, LayoutItems, LayoutType,
+ UsePackoffset ? VD->getAttr<HLSLPackOffsetAttr>() : nullptr);
}
}
+ assert(ElemIt == LayoutStruct->element_end() &&
+ "number of elements in layout struct does not match");
+
+ // add buffer global and a list of its constants to metadata
+ MDNode *BufMDNode = MDNode::get(CGM.getLLVMContext(), BufGlobals);
+ CGM.getModule().getOrInsertNamedMetadata("hlsl.cbs")->addOperand(BufMDNode);
+
+ // set the size of the buffer
+ LayoutItems[BufferSizeIndex] = getConstIntMetadata(Ctx, BufferSize);
+
+ // add buffer layout to metadata
+ MDNode *LayoutMDNode = MDNode::get(CGM.getLLVMContext(), LayoutItems);
+ CGM.getModule()
+ .getOrInsertNamedMetadata("hlsl.cblayouts")
+ ->addOperand(LayoutMDNode);
}
-void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *D) {
- Buffers.emplace_back(Buffer(D));
- addBufferDecls(D, Buffers.back());
+// Creates resource handle type for the HLSL buffer
+static const clang::HLSLAttributedResourceType *
+createBufferHandleType(const HLSLBufferDecl *BufDecl) {
+ ASTContext &AST = BufDecl->getASTContext();
+ QualType QT = AST.getHLSLAttributedResourceType(
+ AST.HLSLResourceTy,
+ QualType(BufDecl->getLayoutStruct()->getTypeForDecl(), 0),
+ HLSLAttributedResourceType::Attributes(ResourceClass::CBuffer));
+ return cast<HLSLAttributedResourceType>(QT.getTypePtr());
+}
+
+// Creates temporary global variables for all declarations within the constant
+// buffer context, creates a global variable for the constant buffer and adds
+// it to the module.
+// All uses of the temporary constant globals will be replaced with buffer
+// access intrinsic resource.getpointer in CGHLSLRuntime::finishCodeGen.
+// Later on in DXILResourceAccess pass these will be transtaled
+// to dx.op.cbufferLoadLegacy instructions.
+void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
+
+ assert(BufDecl->isCBuffer() && "tbuffer codegen is not supported yet");
+
+ // Create resource handle type for the buffer
+ const clang::HLSLAttributedResourceType *ResHandleTy =
+ createBufferHandleType(BufDecl);
+
+ // ignore empty constant buffer
+ if (ResHandleTy->getContainedType()->getAsCXXRecordDecl()->isEmpty())
+ return;
+
+ // Create global variable for the buffer
+ llvm::Module &M = CGM.getModule();
+ llvm::TargetExtType *TargetTy =
+ cast<llvm::TargetExtType>(convertHLSLSpecificType(ResHandleTy));
+ llvm::GlobalVariable *BufGV =
+ new GlobalVariable(TargetTy, /*isConstant*/ true,
+ GlobalValue::LinkageTypes::ExternalLinkage, nullptr,
+ llvm::formatv("{0}{1}", BufDecl->getName(),
+ BufDecl->isCBuffer() ? ".cb" : ".tb"),
+ GlobalValue::NotThreadLocal);
+ M.insertGlobalVariable(BufGV);
+
+ // Add globals for buffer elements and create metadata node for the buffer
+ emitBufferGlobalsAndMetadata(BufDecl, BufGV);
+
+ // Add cbuffer resource initialization
+ const HLSLResourceBindingAttr *RBA =
+ BufDecl->getAttr<HLSLResourceBindingAttr>();
+ // FIXME: handle implicit binding if no binding attribute is found
+ if (RBA)
+ createResourceInitFn(CGM, BufGV, RBA->getSlotNumber(),
+ RBA->getSpaceNumber());
}
void CGHLSLRuntime::finishCodeGen() {
@@ -173,28 +370,8 @@ void CGHLSLRuntime::finishCodeGen() {
generateGlobalCtorDtorCalls();
if (CGM.getCodeGenOpts().OptimizationLevel == 0)
addDisableOptimizations(M);
-
- const DataLayout &DL = M.getDataLayout();
-
- for (auto &Buf : Buffers) {
- layoutBuffer(Buf, DL);
- GlobalVariable *GV = replaceBuffer(Buf);
- M.insertGlobalVariable(GV);
- llvm::hlsl::ResourceClass RC = Buf.IsCBuffer
- ? llvm::hlsl::ResourceClass::CBuffer
- : llvm::hlsl::ResourceClass::SRV;
- llvm::hlsl::ResourceKind RK = Buf.IsCBuffer
- ? llvm::hlsl::ResourceKind::CBuffer
- : llvm::hlsl::ResourceKind::TBuffer;
- addBufferResourceAnnotation(GV, RC, RK, /*IsROV=*/false,
- llvm::hlsl::ElementType::Invalid, Buf.Binding);
- }
}
-CGHLSLRuntime::Buffer::Buffer(const HLSLBufferDecl *D)
- : Name(D->getName()), IsCBuffer(D->isCBuffer()),
- Binding(D->getAttr<HLSLResourceBindingAttr>()) {}
-
void CGHLSLRuntime::addBufferResourceAnnotation(llvm::GlobalVariable *GV,
llvm::hlsl::ResourceClass RC,
llvm::hlsl::ResourceKind RK,
@@ -521,21 +698,15 @@ void CGHLSLRuntime::generateGlobalCtorDtorCalls() {
}
}
-// Returns true if the type is an HLSL resource class
-static bool isResourceRecordType(const clang::Type *Ty) {
- return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr;
-}
-
-static void createResourceInitFn(CodeGenModule &CGM, const VarDecl *VD,
- llvm::GlobalVariable *GV, unsigned Slot,
- unsigned Space) {
+static void createResourceInitFn(CodeGenModule &CGM, llvm::GlobalVariable *GV,
+ unsigned Slot, unsigned Space) {
LLVMContext &Ctx = CGM.getLLVMContext();
llvm::Type *Int1Ty = llvm::Type::getInt1Ty(Ctx);
llvm::Function *InitResFunc = llvm::Function::Create(
llvm::FunctionType::get(CGM.VoidTy, false),
llvm::GlobalValue::InternalLinkage,
- ("_init_resource_" + VD->getName()).str(), CGM.getModule());
+ ("_init_resource_" + GV->getName()).str(), CGM.getModule());
InitResFunc->addFnAttr(llvm::Attribute::AlwaysInline);
llvm::BasicBlock *EntryBB =
@@ -544,20 +715,15 @@ static void createResourceInitFn(CodeGenModule &CGM, const VarDecl *VD,
const DataLayout &DL = CGM.getModule().getDataLayout();
Builder.SetInsertPoint(EntryBB);
- const HLSLAttributedResourceType *AttrResType =
- HLSLAttributedResourceType::findHandleTypeOnResource(
- VD->getType().getTypePtr());
-
- // FIXME: Only simple declarations of resources are supported for now.
- // Arrays of resources or resources in user defined classes are
- // not implemented yet.
- assert(AttrResType != nullptr &&
- "Resource class must have a handle of HLSLAttributedResourceType");
-
- llvm::Type *TargetTy =
- CGM.getTargetCodeGenInfo().getHLSLType(CGM, AttrResType);
- assert(TargetTy != nullptr &&
- "Failed to convert resource handle to target type");
+ // Make sure the global variable is resource handle (cbuffer) or
+ // resource class (=class where the first element is a resource handle).
+ llvm::Type *HandleTy = GV->getValueType();
+ assert((HandleTy->isTargetExtTy() ||
+ (HandleTy->isStructTy() &&
+ HandleTy->getStructElementType(0)->isTargetExtTy())) &&
+ "unexpected type of the global");
+ if (!HandleTy->isTargetExtTy())
+ HandleTy = HandleTy->getStructElementType(0);
llvm::Value *Args[] = {
llvm::ConstantInt::get(CGM.IntTy, Space), /* reg_space */
@@ -569,9 +735,9 @@ static void createResourceInitFn(CodeGenModule &CGM, const VarDecl *VD,
llvm::ConstantInt::get(Int1Ty, false) /* non-uniform */
};
llvm::Value *CreateHandle = Builder.CreateIntrinsic(
- /*ReturnType=*/TargetTy,
+ /*ReturnType=*/HandleTy,
CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic(), Args, nullptr,
- Twine(VD->getName()).concat("_h"));
+ Twine(GV->getName()).concat("_h"));
llvm::Value *HandleRef = Builder.CreateStructGEP(GV->getValueType(), GV, 0);
Builder.CreateAlignedStore(CreateHandle, HandleRef,
@@ -598,8 +764,7 @@ void CGHLSLRuntime::handleGlobalVarDefinition(const VarDecl *VD,
// not implemented yet.
return;
- createResourceInitFn(CGM, VD, GV, RBA->getSlotNumber(),
- RBA->getSpaceNumber());
+ createResourceInitFn(CGM, GV, RBA->getSlotNumber(), RBA->getSpaceNumber());
}
llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) {
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 032b2dee82f21..a6e3c78f52285 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -15,6 +15,7 @@
#ifndef LLVM_CLANG_LIB_CODEGEN_CGHLSLRUNTIME_H
#define LLVM_CLANG_LIB_CODEGEN_CGHLSLRUNTIME_H
+#include "llvm/ADT/DenseMap.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/IntrinsicsDirectX.h"
@@ -46,25 +47,31 @@
} \
}
+using ResourceClass = llvm::dxil::ResourceClass;
+
namespace llvm {
class GlobalVariable;
class Function;
class StructType;
+class Metadata;
} // namespace llvm
namespace clang {
+class NamedDecl;
class VarDecl;
class ParmVarDecl;
class HLSLBufferDecl;
class HLSLResourceBindingAttr;
class Type;
class DeclContext;
+class HLSLPackOffsetAttr;
class FunctionDecl;
namespace CodeGen {
class CodeGenModule;
+class CGBuilderTy;
class CGHLSLRuntime {
public:
@@ -124,16 +131,6 @@ class CGHLSLRuntime {
unsigned Space;
BufferResBinding(HLSLResourceBindingAttr *Attr);
};
- struct Buffer {
- Buffer(const HLSLBufferDecl *D);
- llvm::StringRef Name;
- // IsCBuffer - Whether the buffer is a cbuffer (and not a tbuffer).
- bool IsCBuffer;
- BufferResBinding Binding;
- // Global variable and offset for each constant.
- std::vector<std::pair<llvm::GlobalVariable *, unsigned>> Constants;
- llvm::StructType *LayoutStruct = nullptr;
- };
protected:
CodeGenModule &CGM;
@@ -167,10 +164,18 @@ class CGHLSLRuntime {
llvm::hlsl::ResourceKind RK, bool IsROV,
llvm::hlsl::ElementType ET,
BufferResBinding &Binding);
- void addConstant(VarDecl *D, Buffer &CB);
- void addBufferDecls(const DeclContext *DC, Buffer &CB);
+ void emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
+ llvm::GlobalVariable *BufGV);
+ void addLayoutInfoForBufferElement(
+ size_t &EndOffset, SmallVector<llvm::Metadata *> &LayoutItems,
+ llvm::Type *LayoutTy, HLSLPackOffsetAttr *PackoffsetAttr = nullptr);
+
+ size_t getOrCalculateStructSizeForBuffer(llvm::StructType *StructTy);
+
llvm::Triple::ArchType getArch();
- llvm::SmallVector<Buffer> Buffers;
+
+ // sizes of structs that in constant buffer layout
+ llvm::DenseMap<llvm::StructType *, size_t> StructSizesForBuffer;
};
} // namespace CodeGen
diff --git a/clang/lib/CodeGen/Targets/DirectX.cpp b/clang/lib/CodeGen/Targets/DirectX.cpp
index 7935f7ae37004..33bddc56d83f2 100644
--- a/clang/lib/CodeGen/Targets/DirectX.cpp
+++ b/clang/lib/CodeGen/Targets/DirectX.cpp
@@ -44,6 +44,7 @@ llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM,
return nullptr;
// convert element type
+ // llvm::Type *ElemType = CGM.getTypes().ConvertTypeForMem(ContainedTy);
llvm::Type *ElemType = CGM.getTypes().ConvertType(ContainedTy);
llvm::StringRef TypeName =
@@ -56,9 +57,13 @@ llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM,
return llvm::TargetExtType::get(Ctx, TypeName, {ElemType}, Ints);
}
- case llvm::dxil::ResourceClass::CBuffer:
- llvm_unreachable("dx.CBuffer handles are not implemented yet");
- break;
+ case llvm::dxil::ResourceClass::CBuffer: {
+ QualType StructTy = ResType->getContainedType();
+ if (StructTy.isNull())
+ return nullptr;
+ llvm::Type *Ty = CGM.getTypes().ConvertType(StructTy);
+ return llvm::TargetExtType::get(Ctx, "dx.CBuffer", {Ty});
+ }
case llvm::dxil::ResourceClass::Sampler:
llvm_unreachable("dx.Sampler handles are not implemented yet");
break;
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index b71dd2b273a1c..2807cc773320b 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -239,6 +239,7 @@ static void validatePackoffset(Sema &S, HLSLBufferDecl *BufDecl) {
// Make sure there is no overlap in packoffset - sort PackOffsetVec by offset
// and compare adjacent values.
+ bool IsValid = true;
ASTContext &Context = S.getASTContext();
std::sort(PackOffsetVec.begin(), PackOffsetVec.end(),
[](const std::pair<VarDecl *, HLSLPackOffsetAttr *> &LHS,
@@ -257,8 +258,10 @@ static void validatePackoffset(Sema &S, HLSLBufferDecl *BufDecl) {
VarDecl *NextVar = PackOffsetVec[i + 1].first;
S.Diag(NextVar->getLocation(), diag::err_hlsl_packoffset_overlap)
<< NextVar << Var;
+ IsValid = false;
}
}
+ BufDecl->setHasPackoffset(IsValid);
}
// Returns true if the array has a zero size = if any of the dimensions is 0
diff --git a/clang/test/CodeGenHLSL/cbuf.hlsl b/clang/test/CodeGenHLSL/cbuf.hlsl
deleted file mode 100644
index 825e7b8161a60..0000000000000
--- a/clang/test/CodeGenHLSL/cbuf.hlsl
+++ /dev/null
@@ -1,33 +0,0 @@
-// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library %s \
-// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-
-// RUN: %clang_cc1 -finclude-default-header -triple spirv-pc-vulkan-library %s \
-// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-
-// CHECK: @a = external addrspace(2) externally_initialized global float, align 4
-// CHECK: @b = external addrspace(2) externally_initialized global double, align 8
-// CHECK: @c = external addrspace(2) externally_initialized global float, align 4
-// CHECK: @d = external addrspace(2) externally_initialized global double, align 8
-
-// CHECK: @[[CB:.+]] = external constant { float, double }
-cbuffer A : register(b0, space2) {
- float a;
- double b;
-}
-
-// CHECK: @[[TB:.+]] = external constant { float, double }
-tbuffer A : register(t2, space1) {
- float c;
- double d;
-}
-
-float foo() {
-// CHECK: load float, ptr addrspace(2) @a, align 4
-// CHECK: load double, ptr addrspace(2) @b, align 8
-// CHECK: load float, ptr addrspace(2) @c, align 4
-// CHECK: load double, ptr addrspace(2) @d, align 8
- return a + b + c*d;
-}
-
-// CHECK: !hlsl.cbufs = !{![[CBMD:[0-9]+]]}
-// CHECK: ![[CBMD]] = !{ptr @[[CB]], i32 13, i32 0, i1 false, i32 0, i32 2}
diff --git a/clang/test/CodeGenHLSL/cbuf_in_namespace.hlsl b/clang/test/CodeGenHLSL/cbuf_in_namespace.hlsl
deleted file mode 100644
index 13c401d428331..0000000000000
--- a/clang/test/CodeGenHLSL/cbuf_in_namespace.hlsl
+++ /dev/null
@@ -1,29 +0,0 @@
-// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library %s \
-// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-
-// RUN: %clang_cc1 -finclude-default-header -triple spirv-pc-vulkan-library %s \
-// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-
-// Make sure cbuffer inside namespace works.
-
-// CHECK: @_ZN2n02n11aE = external addrspace(2) externally_initialized global float, align 4
-// CHECK: @_ZN2n01bE = external addrspace(2) externally_initialized global float, align 4
-
-// CHECK: @[[CB:.+]] = external constant { float }
-// CHECK: @[[TB:.+]] = external constant { float }
-namespace n0 {
-namespace n1 {
- cbuffer A {
- float a;
- }
-}
- tbuffer B {
- float b;
- }
-}
-
-float foo() {
-// CHECK: load float, ptr addrspace(2) @_ZN2n02n11aE, align 4
-// CHECK: load float, ptr addrspace(2) @_ZN2n01bE, align 4
- return n0::n1::a + n0::b;
-}
diff --git a/clang/test/CodeGenHLSL/cbuffer.hlsl b/clang/test/CodeGenHLSL/cbuffer.hlsl
new file mode 100644
index 0000000000000..99f16ea62cdcb
--- /dev/null
+++ b/clang/test/CodeGenHLSL/cbuffer.hlsl
@@ -0,0 +1,200 @@
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-compute \
+// RUN: -fnative-half-type -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
+
+// CHECK: %struct.__cblayout_CBScalars = type <{ float, double, half, i64, i32, i16, i32, i64 }>
+// CHECK: %struct.__cblayout_CBVectors = type <{ <3 x float>, <3 x double>, <2 x half>, <3 x i64>, <4 x i32>, <3 x i16>, <3 x i64> }>
+// CHECK: %struct.__cblayout_CBArrays = type <{ [3 x float], [2 x <3 x double>], [2 x [2 x half]], [3 x i64], [2 x [3 x [4 x <4 x i32>]]], [1 x i16], [2 x i64], [4 x i32] }>
+// CHECK: %struct.__cblayout_CBStructs = type { %struct.A, %struct.B, %struct.C, [5 x %struct.A], %struct.__cblayout_D, half, %struct.B, <3 x i16> }
+// CHECK: %struct.A = type { <2 x float> }
+// CHECK: %struct.C = type { i32, %struct.A }
+// CHECK: %struct.__cblayout_D = type { [2 x [3 x %struct.B]] }
+// CHECK: %struct.B = type { %struct.A, <3 x i16> }
+
+cbuffer CBScalars : register(b1, space5) {
+ float a1;
+ double a2;
+ float16_t a3;
+ uint64_t a4;
+ int a5;
+ uint16_t a6;
+ bool a7;
+ int64_t a8;
+}
+
+// CHECK: @CBScalars.cb = external constant target("dx.CBuffer", %struct.__cblayout_CBScalars)
+// CHECK: @a1 = external addrspace(2) global float, align 4
+// CHECK: @a2 = external addrspace(2) global double, align 8
+// CHECK: @a3 = external addrspace(2) global half, align 2
+// CHECK: @a4 = external addrspace(2) global i64, align 8
+// CHECK: @a5 = external addrspace(2) global i32, align 4
+// CHECK: @a6 = external addrspace(2) global i16, align 2
+// CHECK: @a7 = external addrspace(2) global i32, align 4
+// CHECK: @a8 = external addrspace(2) global i64, align 8
+
+cbuffer CBVectors {
+ float3 b1;
+ double3 b2;
+ float16_t2 b3;
+ uint64_t3 b4;
+ int4 b5;
+ uint16_t3 b6;
+ int64_t3 b7;
+ // FIXME: add s bool vectors after llvm-project/llvm#91639 is added
+}
+
+// CHECK: @CBVectors.cb = external constant target("dx.CBuffer", %struct.__cblayout_CBVectors)
+// CHECK: @b1 = external addrspace(2) global <3 x float>, align 16
+// CHECK: @b2 = external addrspace(2) global <3 x double>, align 32
+// CHECK: @b3 = external addrspace(2) global <2 x half>, align 4
+// CHECK: @b4 = external addrspace(2) global <3 x i64>, align 32
+// CHECK: @b5 = external addrspace(2) global <4 x i32>, align 16
+// CHECK: @b6 = external addrspace(2) global <3 x i16>, align 8
+// CHECK: @b7 = external addrspace(2) global <3 x i64>, align 32
+
+cbuffer CBArrays : register(b2) {
+ float c1[3];
+ double3 c2[2];
+ float16_t c3[2][2];
+ uint64_t c4[3];
+ int4 c5[2][3][4];
+ uint16_t c6[1];
+ int64_t c7[2];
+ bool c8[4];
+}
+
+// CHECK: @CBArrays.cb = external constant target("dx.CBuffer", %struct.__cblayout_CBArrays)
+// CHECK: @c1 = external addrspace(2) global [3 x float], align 4
+// CHECK: @c2 = external addrspace(2) global [2 x <3 x double>], align 32
+// CHECK: @c3 = external addrspace(2) global [2 x [2 x half]], align 2
+// CHECK: @c4 = external addrspace(2) global [3 x i64], align 8
+// CHECK: @c5 = external addrspace(2) global [2 x [3 x [4 x <4 x i32>]]], align 16
+// CHECK: @c6 = external addrspace(2) global [1 x i16], align 2
+// CHECK: @c7 = external addrspace(2) global [2 x i64], align 8
+// CHECK: @c8 = external addrspace(2) global [4 x i32], align 4
+
+struct Empty {};
+
+struct A {
+ float2 f1;
+};
+
+struct B : A {
+ uint16_t3 f2;
+};
+
+struct C {
+ int i;
+ A f3;
+};
+
+struct D {
+ B array_of_B[2][3];
+ Empty es;
+};
+
+// CHECK: @CBStructs.cb = external constant target("dx.CBuffer", %struct.__cblayout_CBStructs)
+// CHECK: @a = external addrspace(2) global %struct.A, align 8
+// CHECK: @b = external addrspace(2) global %struct.B, align 8
+// CHECK: @c = external addrspace(2) global %struct.C, align 8
+// CHECK: @array_of_A = external addrspace(2) global [5 x %struct.A], align 8
+// CHECK: @d = external addrspace(2) global %struct.__cblayout_D, align 8
+// CHECK: @e = external addrspace(2) global half, align 2
+
+cbuffer CBStructs {
+ A a;
+ B b;
+ C c;
+ A array_of_A[5];
+ D d;
+ half e;
+ B f;
+ uint16_t3 g;
+};
+
+struct Test {
+ float a, b;
+};
+
+// CHECK: @CBMix.cb = external constant target("dx.CBuffer", %struct.__cblayout_CBMix)
+// CHECK: @test = external addrspace(2) global [2 x %struct.Test], align 4
+// CHECK: @f1 = external addrspace(2) global float, align 4
+// CHECK: @f2 = external addrspace(2) global [3 x [2 x <2 x float>]], align 8
+// CHECK: @f3 = external addrspace(2) global float, align 4
+// CHECK: @s = external addrspace(2) global %struct.anon, align 4
+// CHECK: @dd = external addrspace(2) global double, align 8
+// CHECK: @f4 = external addrspace(2) global float, align 4
+// CHECK: @dv = external addrspace(2) global <1 x double>, align 8
+// CHECK: @uv = external addrspace(2) global i16, align 2
+
+cbuffer CBMix {
+ Test test[2];
+ float f1;
+ float2 f2[3][2];
+ float f3;
+ struct { float c; } s;
+ double dd;
+ float f4;
+ vector<double,1> dv;
+ uint16_t uv;
+};
+
+// CHECK: efine internal void @_init_resource_CBScalars.cb()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %[[HANDLE1:.*]] = call target("dx.CBuffer", %struct.__cblayout_CBScalars)
+// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_s_struct.__cblayout_CBScalarsst(i32 5, i32 1, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", %struct.__cblayout_CBScalars) %[[HANDLE1]], ptr @CBScalars.cb, align 4
+
+// CHECK: define internal void @_init_resource_CBArrays.cb()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %[[HANDLE2:.*]] = call target("dx.CBuffer", %struct.__cblayout_CBArrays)
+// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_s_struct.__cblayout_CBArraysst(i32 0, i32 2, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", %struct.__cblayout_CBArrays) %[[HANDLE2]], ptr @CBArrays.cb, align 4
+
+RWBuffer<float> Buf;
+
+[numthreads(4,1,1)]
+void main() {
+ //Buf[0] = a1 + b1.z + c1[2] + a.f1.y;
+ Buf[0] = a.f1.y;
+}
+
+// CHECK: define internal void @_GLOBAL__sub_I_cbuffer.hlsl()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @_init_resource_CBScalars.cb()
+// CHECK-NEXT: call void @_init_resource_CBArrays.cb()
+
+// CHECK: !hlsl.cbs = !{![[CBSCALARS:[0-9]+]], ![[CBVECTORS:[0-9]+]], ![[CBARRAYS:[0-9]+]], ![[CBSTRUCTS:[0-9]+]], ![[CBMIX:[0-9]+]]}
+// CHECK: !hlsl.cblayouts = !{![[CBSCALARS_LAYOUT:[0-9]+]], ![[CBVECTORS_LAYOUT:[0-9]+]], ![[CBARRAYS_LAYOUT:[0-9]+]], ![[A_LAYOUT:[0-9]+]],
+// CHECK-SAME: ![[B_LAYOUT:[0-9]+]], ![[C_LAYOUT:[0-9]+]], ![[D_LAYOUT:[0-9]+]], ![[CBSTRUCTS_LAYOUT:[0-9]+]], ![[TEST_LAYOUT:[0-9]+]],
+// CHECK-SAME: ![[ANON_LAYOUT:[0-9]+]], ![[CBMIX_LAYOUT:[0-9]+]]}
+
+// CHECK: ![[CBSCALARS]] = !{ptr @CBScalars.cb, ptr addrspace(2) @a1, ptr addrspace(2) @a2, ptr addrspace(2) @a3, ptr addrspace(2) @a4,
+// CHECK-SAME: ptr addrspace(2) @a5, ptr addrspace(2) @a6, ptr addrspace(2) @a7, ptr addrspace(2) @a8}
+
+// CHECK: ![[CBVECTORS]] = !{ptr @CBVectors.cb, ptr addrspace(2) @b1, ptr addrspace(2) @b2, ptr addrspace(2) @b3, ptr addrspace(2) @b4,
+// CHECK-SAME: ptr addrspace(2) @b5, ptr addrspace(2) @b6, ptr addrspace(2) @b7}
+
+// CHECK: ![[CBARRAYS]] = !{ptr @CBArrays.cb, ptr addrspace(2) @c1, ptr addrspace(2) @c2, ptr addrspace(2) @c3, ptr addrspace(2) @c4,
+// CHECK-SAME: ptr addrspace(2) @c5, ptr addrspace(2) @c6, ptr addrspace(2) @c7, ptr addrspace(2) @c8}
+
+// CHECK: ![[CBSTRUCTS]] = !{ptr @CBStructs.cb, ptr addrspace(2) @a, ptr addrspace(2) @b, ptr addrspace(2) @c, ptr addrspace(2) @array_of_A,
+// CHECK-SAME: ptr addrspace(2) @d, ptr addrspace(2) @e, ptr addrspace(2) @f, ptr addrspace(2) @g}
+
+// CHECK: ![[CBMIX]] = !{ptr @CBMix.cb, ptr addrspace(2) @test, ptr addrspace(2) @f1, ptr addrspace(2) @f2, ptr addrspace(2) @f3,
+// CHECK-SAME: ptr addrspace(2) @s, ptr addrspace(2) @dd, ptr addrspace(2) @f4, ptr addrspace(2) @dv, ptr addrspace(2) @uv}
+
+// CHECK: ![[CBSCALARS_LAYOUT]] = !{!"struct.__cblayout_CBScalars", i32 56, i32 0, i32 8, i32 16, i32 24, i32 32, i32 36, i32 40, i32 48}
+// CHECK: ![[CBVECTORS_LAYOUT]] = !{!"struct.__cblayout_CBVectors", i32 136, i32 0, i32 16, i32 40, i32 48, i32 80, i32 96, i32 112}
+
+// CHECK: ![[CBARRAYS_LAYOUT]] = !{!"struct.__cblayout_CBArrays", i32 708, i32 0, i32 16, i32 48, i32 32, i32 112, i32 16, i32 176, i32 16,
+// CHECK-SAME: i32 224, i32 16, i32 608, i32 16, i32 624, i32 16, i32 656, i32 16}
+
+// CHECK: ![[A_LAYOUT]] = !{!"struct.A", i32 8, i32 0}
+// CHECK: ![[B_LAYOUT]] = !{!"struct.B", i32 14, i32 0, i32 8}
+// CHECK: ![[C_LAYOUT]] = !{!"struct.C", i32 24, i32 0, i32 16}
+// CHECK: ![[D_LAYOUT]] = !{!"struct.__cblayout_D", i32 94, i32 0, i32 16}
+// CHECK: ![[CBSTRUCTS_LAYOUT]] = !{!"struct.__cblayout_CBStructs", i32 262, i32 0, i32 16, i32 32, i32 64, i32 16, i32 144, i32 238, i32 240, i32 256}
+
+// CHECK: ![[TEST_LAYOUT]] = !{!"struct.Test", i32 8, i32 0, i32 4}
+// CHECK: ![[ANON_LAYOUT]] = !{!"struct.anon", i32 4, i32 0}
+// CHECK: ![[CBMIX_LAYOUT]] = !{!"struct.__cblayout_CBMix", i32 162, i32 0, i32 16, i32 24, i32 32, i32 16, i32 120, i32 128, i32 136, i32 144, i32 152, i32 160}
diff --git a/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl b/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl
new file mode 100644
index 0000000000000..aa5659af414ef
--- /dev/null
+++ b/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl
@@ -0,0 +1,63 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN: dxil-pc-shadermodel6.3-library %s \
+// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
+
+// Make sure cbuffer inside namespace works.
+
+// CHECK: %"struct.n0::n1::__cblayout_A" = type { float }
+// CHECK: %"struct.n0::__cblayout_B" = type { float }
+// CHECK: %"struct.n0::n2::__cblayout_C" = type { float, %"struct.n0::Foo" }
+// CHECK: %"struct.n0::Foo" = type { float }
+
+// CHECK: @A.cb = external constant target("dx.CBuffer", %"struct.n0::n1::__cblayout_A")
+// CHECK: @_ZN2n02n11aE = external addrspace(2) global float, align 4
+
+// CHECK: @B.cb = external constant target("dx.CBuffer", %"struct.n0::__cblayout_B")
+// CHECK: @_ZN2n01aE = external addrspace(2) global float, align 4
+
+// CHECK: @C.cb = external constant target("dx.CBuffer", %"struct.n0::n2::__cblayout_C")
+// CHECK: @_ZN2n02n21aE = external addrspace(2) global float, align 4
+// CHECK: @_ZN2n02n21bE = external addrspace(2) global %"struct.n0::Foo", align 4
+
+namespace n0 {
+ struct Foo {
+ float f;
+ };
+
+ namespace n1 {
+ cbuffer A {
+ float a;
+ }
+ }
+ cbuffer B {
+ float a;
+ }
+ namespace n2 {
+ cbuffer C {
+ float a;
+ Foo b;
+ }
+ }
+}
+
+float foo() {
+ // CHECK: load float, ptr addrspace(2) @_ZN2n02n11aE, align 4
+ // CHECK: load float, ptr addrspace(2) @_ZN2n01aE, align 4
+ // CHECK: load float, ptr addrspace(2) @_ZN2n02n21aE, align 4
+ return n0::n1::a + n0::a + n0::n2::a;
+}
+
+[numthreads(4,1,1)]
+void main() {}
+
+// CHECK: !hlsl.cbs = !{![[A:[0-9]+]], ![[B:[0-9]+]], ![[C:[0-9]+]]}
+// CHECK: !hlsl.cblayouts = !{![[A_LAYOUT:[0-9]+]], ![[B_LAYOUT:[0-9]+]], ![[FOO_LAYOUT:[0-9]+]], ![[C_LAYOUT:[0-9]+]]}
+
+// CHECK: [[A]] = !{ptr @A.cb, ptr addrspace(2) @_ZN2n02n11aE}
+// CHECK: [[B]] = !{ptr @B.cb, ptr addrspace(2) @_ZN2n01aE}
+// CHECK: [[C]] = !{ptr @C.cb, ptr addrspace(2) @_ZN2n02n21aE, ptr addrspace(2) @_ZN2n02n21bE}
+
+// CHECK: ![[A_LAYOUT]] = !{!"struct.n0::n1::__cblayout_A", i32 4, i32 0}
+// CHECK: ![[B_LAYOUT]] = !{!"struct.n0::__cblayout_B", i32 4, i32 0}
+// CHECK: ![[FOO_LAYOUT]] = !{!"struct.n0::Foo", i32 4, i32 0}
+// CHECK: ![[C_LAYOUT]] = !{!"struct.n0::n2::__cblayout_C", i32 20, i32 0, i32 16}
diff --git a/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl b/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
new file mode 100644
index 0000000000000..f5b5cba6197b3
--- /dev/null
+++ b/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN: dxil-pc-shadermodel6.3-compute %s \
+// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
+
+// CHECK: %struct.__cblayout_CB = type <{ float, double, <2 x i32> }>
+
+// CHECK: @CB.cb = external constant target("dx.CBuffer", %struct.__cblayout_CB)
+// CHECK: @a = external addrspace(2) global float, align 4
+// CHECK: @b = external addrspace(2) global double, align 8
+// CHECK: @c = external addrspace(2) global <2 x i32>, align 8
+
+cbuffer CB : register(b1, space3) {
+ float a : packoffset(c1.x);
+ double b : packoffset(c10.z);
+ int2 c : packoffset(c5.z);
+}
+
+// CHECK: define internal void @_init_resource_CB.cb()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %CB.cb_h = call target("dx.CBuffer", %struct.__cblayout_CB) @llvm.dx.resource.handlefrombinding.tdx.CBuffer_s_struct.__cblayout_CBst(i32 3, i32 1, i32 1, i32 0, i1 false)
+
+float foo() {
+ // CHECK: load float, ptr addrspace(2) @a, align 4
+ // CHECK: load double, ptr addrspace(2) @b, align 8
+ return a + b;
+}
+// CHECK: define internal void @_GLOBAL__sub_I_cbuffer_with_packoffset.hlsl()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @_init_resource_CB.cb()
+
+[numthreads(4,1,1)]
+void main() {
+ foo();
+}
+
+// CHECK: !hlsl.cbs = !{![[CB:[0-9]+]]}
+// CHECK: !hlsl.cblayouts = !{![[CB_LAYOUT:[0-9]+]]}
+
+// CHECK: ![[CB]] = !{ptr @CB.cb, ptr addrspace(2) @a, ptr addrspace(2) @b, ptr addrspace(2) @c}
+// CHECK: ![[CB_LAYOUT]] = !{!"struct.__cblayout_CB", i32 176, i32 16, i32 168, i32 88}
diff --git a/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl b/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl
new file mode 100644
index 0000000000000..8994640d5b311
--- /dev/null
+++ b/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library %s \
+// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
+
+// CHECK: %struct.__cblayout_A = type { float }
+
+// CHECK: @A.cb = external constant target("dx.CBuffer", %struct.__cblayout_A)
+// CHECK: @a = external addrspace(2) global float, align 4
+// CHECK-DAG: @_ZL1b = internal global float 3.000000e+00, align 4
+// CHECK-NOT: @B.cb
+
+cbuffer A {
+ float a;
+ static float b = 3;
+ float foo() { return a + b; }
+}
+
+cbuffer B {
+ // intentionally empty
+}
+
+// CHECK: define {{.*}} float @_Z3foov() #0 {
+// CHECK: load float, ptr addrspace(2) @a, align 4
+
+extern float bar() {
+ return foo();
+}
+
+// CHECK: !hlsl.cbs = !{![[CB:[0-9]+]]}
+// CHECK: !hlsl.cblayouts = !{![[CB_LAYOUT:[0-9]+]]}
+
+// CHECK: ![[CB]] = !{ptr @A.cb, ptr addrspace(2) @a}
+// CHECK: ![[CB_LAYOUT]] = !{!"struct.__cblayout_A", i32 4, i32 0}
diff --git a/clang/test/CodeGenHLSL/resource-bindings.hlsl b/clang/test/CodeGenHLSL/resource-bindings.hlsl
index bfa7896bd9811..57e8cc29572b1 100644
--- a/clang/test/CodeGenHLSL/resource-bindings.hlsl
+++ b/clang/test/CodeGenHLSL/resource-bindings.hlsl
@@ -2,14 +2,17 @@
// CHECK: define internal void @_init_resource_U0S0()
// CHECK: %U0S0_h = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_v4f32_1_0_0t(i32 0, i32 0, i32 1, i32 0, i1 false)
+// CHECK: store target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %U0S0_h, ptr @U0S0, align 4
RWBuffer<float4> U0S0 : register(u0);
// CHECK: define internal void @_init_resource_U5S3()
// CHECK: %U5S3_h = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t(i32 3, i32 5, i32 1, i32 0, i1 false)
+// CHECK: store target("dx.TypedBuffer", float, 1, 0, 0) %U5S3_h, ptr @U5S3, align 4
RWBuffer<float> U5S3 : register(u5, space3);
// CHECK: define internal void @_init_resource_T2S2()
// CHECK: %T2S2_h = call target("dx.RawBuffer", i32, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i32_0_0t(i32 2, i32 2, i32 1, i32 0, i1 false)
+// CHECK: store target("dx.RawBuffer", i32, 0, 0) %T2S2_h, ptr @T2S2, align 4
StructuredBuffer<int> T2S2 : register(t2, space2);
struct S {
float4 f;
@@ -18,6 +21,7 @@ struct S {
// CHECK: define internal void @_init_resource_T3S0()
// CHECK: %T3S0_h = call target("dx.RawBuffer", %struct.S, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_s_struct.Ss_0_0t(i32 0, i32 3, i32 1, i32 0, i1 false)
+// CHECK: store target("dx.RawBuffer", %struct.S, 0, 0) %T3S0_h, ptr @T3S0, align 4
StructuredBuffer<S> T3S0 : register(t3);
// CHECK: define void @main()
diff --git a/clang/test/CodeGenHLSL/static_global_and_function_in_cb.hlsl b/clang/test/CodeGenHLSL/static_global_and_function_in_cb.hlsl
deleted file mode 100644
index 25f51cce2017d..0000000000000
--- a/clang/test/CodeGenHLSL/static_global_and_function_in_cb.hlsl
+++ /dev/null
@@ -1,22 +0,0 @@
-// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library %s \
-// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-
-// RUN: %clang_cc1 -finclude-default-header -triple spirv-pc-vulkan-library %s \
-// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-
-cbuffer A {
- // CHECK: @a = external addrspace(2) externally_initialized global float, align 4
- float a;
- // CHECK: @_ZL1b = internal global float 3.000000e+00, align 4
- static float b = 3;
- float foo() { return a + b; }
-}
-// CHECK: @[[CB:.+]] = external constant { float }
-
-// CHECK:define {{.*}} float @_Z3foov()
-// CHECK:load float, ptr addrspace(2) @a, align 4
-// CHECK:load float, ptr @_ZL1b, align 4
-
-float bar() {
- return foo();
-}
>From 56beb45a133be18b7e6649cc0a4af852bbed3db7 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 28 Jan 2025 16:06:03 -0800
Subject: [PATCH 04/13] remove stride
---
clang/lib/CodeGen/CGHLSLRuntime.cpp | 32 +++++++++++++++--------------
clang/lib/CodeGen/CGHLSLRuntime.h | 7 ++++---
clang/test/CodeGenHLSL/cbuffer.hlsl | 9 ++++----
3 files changed, 25 insertions(+), 23 deletions(-)
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index d3d9d42664359..128ca86f66b5a 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -130,8 +130,11 @@ CGHLSLRuntime::getOrCalculateStructSizeForBuffer(llvm::StructType *StructTy) {
size_t StructSize = 0;
LayoutItems.push_back(nullptr); // reserve one slot for the buffer size
- for (llvm::Type *ElTy : StructTy->elements())
- addLayoutInfoForBufferElement(StructSize, LayoutItems, ElTy);
+ for (llvm::Type *ElTy : StructTy->elements()) {
+ size_t Offset = calculateBufferElementOffset(ElTy, &StructSize);
+ // create metadata constant with the element start offset
+ LayoutItems.push_back(getConstIntMetadata(CGM.getLLVMContext(), Offset));
+ }
// set the size of the buffer
LayoutItems[1] = getConstIntMetadata(Ctx, StructSize);
@@ -147,16 +150,16 @@ CGHLSLRuntime::getOrCalculateStructSizeForBuffer(llvm::StructType *StructTy) {
return StructSize;
}
-void CGHLSLRuntime::addLayoutInfoForBufferElement(
- size_t &EndOffset, SmallVector<llvm::Metadata *> &LayoutItems,
- llvm::Type *LayoutTy, HLSLPackOffsetAttr *PackoffsetAttr) {
+size_t CGHLSLRuntime::calculateBufferElementOffset(
+ llvm::Type *LayoutTy, size_t *LayoutEndOffset,
+ HLSLPackOffsetAttr *PackoffsetAttr) {
- // calculate element offset and size; for arrays also calculate array
- // element count and stride
+ // calculate element offset and size
size_t ElemOffset = 0;
size_t ElemSize = 0;
size_t ArrayCount = 1;
size_t ArrayStride = 0;
+ size_t EndOffset = *LayoutEndOffset;
size_t NextRowOffset = llvm::alignTo(EndOffset, 16U);
if (LayoutTy->isArrayTy()) {
@@ -205,13 +208,9 @@ void CGHLSLRuntime::addLayoutInfoForBufferElement(
// with packoffset annotations)
unsigned NewEndOffset =
ElemOffset + (ArrayCount - 1) * ArrayStride + ElemSize;
- EndOffset = std::max<size_t>(EndOffset, NewEndOffset);
+ *LayoutEndOffset = std::max<size_t>(EndOffset, NewEndOffset);
- // create metadata constan with the offset and stride and add to list
- LayoutItems.push_back(getConstIntMetadata(CGM.getLLVMContext(), ElemOffset));
- if (ArrayStride)
- LayoutItems.push_back(
- getConstIntMetadata(CGM.getLLVMContext(), ArrayStride));
+ return ElemOffset;
}
void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
@@ -284,9 +283,12 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
!UsePackoffset) &&
"expected packoffset attribute on every declaration");
- addLayoutInfoForBufferElement(
- BufferSize, LayoutItems, LayoutType,
+ size_t Offset = calculateBufferElementOffset(
+ LayoutType, &BufferSize,
UsePackoffset ? VD->getAttr<HLSLPackOffsetAttr>() : nullptr);
+
+ // create metadata constant with the element start offset
+ LayoutItems.push_back(getConstIntMetadata(CGM.getLLVMContext(), Offset));
}
}
assert(ElemIt == LayoutStruct->element_end() &&
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index a6e3c78f52285..d1f678863d4fb 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -166,9 +166,10 @@ class CGHLSLRuntime {
BufferResBinding &Binding);
void emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
llvm::GlobalVariable *BufGV);
- void addLayoutInfoForBufferElement(
- size_t &EndOffset, SmallVector<llvm::Metadata *> &LayoutItems,
- llvm::Type *LayoutTy, HLSLPackOffsetAttr *PackoffsetAttr = nullptr);
+
+ size_t
+ calculateBufferElementOffset(llvm::Type *LayoutTy, size_t *LayoutEndOffset,
+ HLSLPackOffsetAttr *PackoffsetAttr = nullptr);
size_t getOrCalculateStructSizeForBuffer(llvm::StructType *StructTy);
diff --git a/clang/test/CodeGenHLSL/cbuffer.hlsl b/clang/test/CodeGenHLSL/cbuffer.hlsl
index 99f16ea62cdcb..e600d25c4e19c 100644
--- a/clang/test/CodeGenHLSL/cbuffer.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer.hlsl
@@ -186,15 +186,14 @@ void main() {
// CHECK: ![[CBSCALARS_LAYOUT]] = !{!"struct.__cblayout_CBScalars", i32 56, i32 0, i32 8, i32 16, i32 24, i32 32, i32 36, i32 40, i32 48}
// CHECK: ![[CBVECTORS_LAYOUT]] = !{!"struct.__cblayout_CBVectors", i32 136, i32 0, i32 16, i32 40, i32 48, i32 80, i32 96, i32 112}
-// CHECK: ![[CBARRAYS_LAYOUT]] = !{!"struct.__cblayout_CBArrays", i32 708, i32 0, i32 16, i32 48, i32 32, i32 112, i32 16, i32 176, i32 16,
-// CHECK-SAME: i32 224, i32 16, i32 608, i32 16, i32 624, i32 16, i32 656, i32 16}
+// CHECK: ![[CBARRAYS_LAYOUT]] = !{!"struct.__cblayout_CBArrays", i32 708, i32 0, i32 48, i32 112, i32 176, i32 224, i32 608, i32 624, i32 656}
// CHECK: ![[A_LAYOUT]] = !{!"struct.A", i32 8, i32 0}
// CHECK: ![[B_LAYOUT]] = !{!"struct.B", i32 14, i32 0, i32 8}
// CHECK: ![[C_LAYOUT]] = !{!"struct.C", i32 24, i32 0, i32 16}
-// CHECK: ![[D_LAYOUT]] = !{!"struct.__cblayout_D", i32 94, i32 0, i32 16}
-// CHECK: ![[CBSTRUCTS_LAYOUT]] = !{!"struct.__cblayout_CBStructs", i32 262, i32 0, i32 16, i32 32, i32 64, i32 16, i32 144, i32 238, i32 240, i32 256}
+// CHECK: ![[D_LAYOUT]] = !{!"struct.__cblayout_D", i32 94, i32 0}
+// CHECK: ![[CBSTRUCTS_LAYOUT]] = !{!"struct.__cblayout_CBStructs", i32 262, i32 0, i32 16, i32 32, i32 64, i32 144, i32 238, i32 240, i32 256}
// CHECK: ![[TEST_LAYOUT]] = !{!"struct.Test", i32 8, i32 0, i32 4}
// CHECK: ![[ANON_LAYOUT]] = !{!"struct.anon", i32 4, i32 0}
-// CHECK: ![[CBMIX_LAYOUT]] = !{!"struct.__cblayout_CBMix", i32 162, i32 0, i32 16, i32 24, i32 32, i32 16, i32 120, i32 128, i32 136, i32 144, i32 152, i32 160}
+// CHECK: ![[CBMIX_LAYOUT]] = !{!"struct.__cblayout_CBMix", i32 162, i32 0, i32 24, i32 32, i32 120, i32 128, i32 136, i32 144, i32 152, i32 160}
>From 749e88e87f36b8b4f2a8b5a4ddf02230a4be9600 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 28 Jan 2025 22:02:24 -0800
Subject: [PATCH 05/13] cleanup, update comments
---
clang/lib/CodeGen/CGHLSLRuntime.cpp | 188 +++++++++++++-------------
clang/lib/CodeGen/CGHLSLRuntime.h | 4 +-
clang/lib/CodeGen/Targets/DirectX.cpp | 1 -
clang/test/CodeGenHLSL/cbuffer.hlsl | 2 +-
4 files changed, 100 insertions(+), 95 deletions(-)
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 128ca86f66b5a..52247173b6990 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -89,8 +89,7 @@ static bool isResourceRecordType(const clang::Type *Ty) {
return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr;
}
-// Returns true if the type is an HLSL resource class or an array of
-// HLSL resource classes
+// Returns true if the type is an HLSL resource class or an array of them
static bool isResourceRecordTypeOrArrayOf(const clang::Type *Ty) {
while (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
Ty = CAT->getArrayElementTypeNoTypeQual();
@@ -113,48 +112,56 @@ static unsigned getScalarOrVectorSize(llvm::Type *Ty) {
return Ty->getScalarSizeInBits() / 8;
}
+// Returns size of a struct in constant buffer layout. The sizes are cached
+// in StructSizesForBuffer map. The map is also an indicator if a layout
+// metadata for this struct has been added to the module.
+// If the struct type is not in the map, this method will calculate the struct
+// layout, add a metadata node describing it to the module, and add the struct
+// size to the map.
size_t
CGHLSLRuntime::getOrCalculateStructSizeForBuffer(llvm::StructType *StructTy) {
- assert(StructTy->isStructTy());
-
// check if we already have a side for this struct
auto SizeIt = StructSizesForBuffer.find(StructTy);
if (SizeIt != StructSizesForBuffer.end())
return SizeIt->getSecond();
- // if not, calculate the struct layout and add it to metadata
+ // if not, calculate the struct layout and create a metadata node
LLVMContext &Ctx = CGM.getLLVMContext();
SmallVector<llvm::Metadata *> LayoutItems;
+
+ // start metadata list with a struct name and reserve one slot for its size
LayoutItems.push_back(MDString::get(Ctx, StructTy->getName()));
+ LayoutItems.push_back(nullptr);
+ // add element offsets
size_t StructSize = 0;
- LayoutItems.push_back(nullptr); // reserve one slot for the buffer size
-
for (llvm::Type *ElTy : StructTy->elements()) {
size_t Offset = calculateBufferElementOffset(ElTy, &StructSize);
- // create metadata constant with the element start offset
LayoutItems.push_back(getConstIntMetadata(CGM.getLLVMContext(), Offset));
}
-
- // set the size of the buffer
+ // set the size of the buffer to the reserved slot
LayoutItems[1] = getConstIntMetadata(Ctx, StructSize);
- // add the struct layout info to metadata
- MDNode *LayoutMDNode = MDNode::get(CGM.getLLVMContext(), LayoutItems);
+ // add the struct layout to metadata
CGM.getModule()
.getOrInsertNamedMetadata("hlsl.cblayouts")
- ->addOperand(LayoutMDNode);
+ ->addOperand(MDNode::get(CGM.getLLVMContext(), LayoutItems));
// add struct size to list and return it
StructSizesForBuffer[StructTy] = StructSize;
return StructSize;
}
+// Calculates offset of a single element in constant buffer layout.
+// The provided LayoutEndOffset marks the end of the layout so far (end offset
+// of the buffer or struct). After the element offset calculations are done it
+// will be updated the new end of layout value.
+// If the PackoffsetAttrs is not nullptr the offset will be based on the
+// packoffset annotation.
size_t CGHLSLRuntime::calculateBufferElementOffset(
llvm::Type *LayoutTy, size_t *LayoutEndOffset,
HLSLPackOffsetAttr *PackoffsetAttr) {
- // calculate element offset and size
size_t ElemOffset = 0;
size_t ElemSize = 0;
size_t ArrayCount = 1;
@@ -198,14 +205,15 @@ size_t CGHLSLRuntime::calculateBufferElementOffset(
ElemOffset = PackoffsetAttr->getOffsetInBytes();
} else {
ElemOffset = llvm::alignTo(EndOffset, Align);
+ // if the element does not fit, move it to the next row
if (ElemOffset + ElemSize > NextRowOffset)
ElemOffset = NextRowOffset;
}
}
// Update end offset of the buffer/struct layout; do not update it if
- // the provided EndOffset is already bigger than the new one (which may happen
- // with packoffset annotations)
+ // the provided EndOffset is already bigger than the new one value
+ // (which may happen with packoffset annotations)
unsigned NewEndOffset =
ElemOffset + (ArrayCount - 1) * ArrayStride + ElemSize;
*LayoutEndOffset = std::max<size_t>(EndOffset, NewEndOffset);
@@ -213,102 +221,106 @@ size_t CGHLSLRuntime::calculateBufferElementOffset(
return ElemOffset;
}
+// Emits constant global variables for buffer declarations, creates metadata
+// linking the constant globals with the buffer. Also calculates the buffer
+// layout and creates metadata node describing it.
void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
llvm::GlobalVariable *BufGV) {
+ LLVMContext &Ctx = CGM.getLLVMContext();
llvm::StructType *LayoutStruct = cast<llvm::StructType>(
cast<llvm::TargetExtType>(BufGV->getValueType())->getTypeParameter(0));
- LLVMContext &Ctx = CGM.getLLVMContext();
-
+ // Start metadata list associating the buffer global variable with its
+ // constatns
SmallVector<llvm::Metadata *> BufGlobals;
BufGlobals.push_back(ValueAsMetadata::get(BufGV));
+ // Start layout metadata list with a struct name and reserve one slot for
+ // the buffer size
SmallVector<llvm::Metadata *> LayoutItems;
LayoutItems.push_back(MDString::get(Ctx, LayoutStruct->getName()));
+ LayoutItems.push_back(nullptr);
size_t BufferSize = 0;
- size_t BufferSizeIndex = LayoutItems.size();
- LayoutItems.push_back(nullptr); // reserve one slot for the buffer size
-
bool UsePackoffset = BufDecl->hasPackoffset();
-
const auto *ElemIt = LayoutStruct->element_begin();
for (Decl *D : BufDecl->decls()) {
if (isa<CXXRecordDecl, EmptyDecl>(D))
// Nothing to do for this declaration.
continue;
if (isa<FunctionDecl>(D)) {
- // A function within an cbuffer is effectively a top-level function,
- // as it only refers to globally scoped declarations.
+ // A function within an cbuffer is effectively a top-level function.
CGM.EmitTopLevelDecl(D);
continue;
}
- if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
- QualType VDTy = VD->getType();
- if (VDTy.getAddressSpace() != LangAS::hlsl_constant) {
- if (VD->getStorageClass() == SC_Static ||
- isResourceRecordTypeOrArrayOf(VDTy.getTypePtr())) {
- // Emit static variables and resource classes inside cbuffer as
- // regular globals
- CGM.EmitGlobal(VD);
- }
- // Anything else that is not in the hlsl_constant address space must be
- // an empty struct or a zero-sized array and can be ignored
- continue;
- }
+ VarDecl *VD = dyn_cast<VarDecl>(D);
+ if (!VD)
+ continue;
- assert(ElemIt != LayoutStruct->element_end() &&
- "number of elements in layout struct does not match");
- llvm::Type *LayoutType = *ElemIt++;
-
- assert((CGM.getTypes().ConvertTypeForMem(VDTy) == LayoutType ||
- (LayoutType->isStructTy() &&
- cast<llvm::StructType>(LayoutType)
- ->getName()
- .starts_with(("struct.__cblayout_" +
- VDTy->getAsCXXRecordDecl()->getName())
- .str()))) &&
- "layout type does not match the converted element type");
-
- // handle any resources declarations inside the struct
- if (VDTy->isStructureType() && VDTy->isHLSLIntangibleType())
- // FIXME: handle resources in cbuffer structs
- llvm_unreachable("resources in cbuffer are not supported yet");
-
- GlobalVariable *ElemGV =
- cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(VD, LayoutType));
- BufGlobals.push_back(ValueAsMetadata::get(ElemGV));
-
- assert(((UsePackoffset && VD->hasAttr<HLSLPackOffsetAttr>()) ||
- !UsePackoffset) &&
- "expected packoffset attribute on every declaration");
-
- size_t Offset = calculateBufferElementOffset(
- LayoutType, &BufferSize,
- UsePackoffset ? VD->getAttr<HLSLPackOffsetAttr>() : nullptr);
-
- // create metadata constant with the element start offset
- LayoutItems.push_back(getConstIntMetadata(CGM.getLLVMContext(), Offset));
+ QualType VDTy = VD->getType();
+ if (VDTy.getAddressSpace() != LangAS::hlsl_constant) {
+ if (VD->getStorageClass() == SC_Static ||
+ VDTy.getAddressSpace() == LangAS::hlsl_groupshared ||
+ isResourceRecordTypeOrArrayOf(VDTy.getTypePtr())) {
+ // Emit static and groupshared variables and resource classes inside
+ // cbuffer as regular globals
+ CGM.EmitGlobal(VD);
+ }
+ // Anything else that is not in the hlsl_constant address space must be
+ // an empty struct or a zero-sized array and can be ignored
+ continue;
}
+
+ assert(ElemIt != LayoutStruct->element_end() &&
+ "number of elements in layout struct does not match");
+ llvm::Type *LayoutType = *ElemIt++;
+
+ // Make sure the type of the VarDecl type matches the type of the layout
+ // struct element, or that it is a layout struct with the same name
+ assert((CGM.getTypes().ConvertTypeForMem(VDTy) == LayoutType ||
+ (LayoutType->isStructTy() &&
+ cast<llvm::StructType>(LayoutType)
+ ->getName()
+ .starts_with(("struct.__cblayout_" +
+ VDTy->getAsCXXRecordDecl()->getName())
+ .str()))) &&
+ "layout type does not match the converted element type");
+
+ // there might be resources inside the used defined structs
+ if (VDTy->isStructureType() && VDTy->isHLSLIntangibleType())
+ // FIXME: handle resources in cbuffer structs
+ llvm_unreachable("resources in cbuffer are not supported yet");
+
+ // create global variable for the constant and to metadata list
+ GlobalVariable *ElemGV =
+ cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(VD, LayoutType));
+ BufGlobals.push_back(ValueAsMetadata::get(ElemGV));
+
+ // get offset of the global and and to metadata list
+ assert(((UsePackoffset && VD->hasAttr<HLSLPackOffsetAttr>()) ||
+ !UsePackoffset) &&
+ "expected packoffset attribute on every declaration");
+ size_t Offset = calculateBufferElementOffset(
+ LayoutType, &BufferSize,
+ UsePackoffset ? VD->getAttr<HLSLPackOffsetAttr>() : nullptr);
+ LayoutItems.push_back(getConstIntMetadata(Ctx, Offset));
}
assert(ElemIt == LayoutStruct->element_end() &&
"number of elements in layout struct does not match");
-
- // add buffer global and a list of its constants to metadata
- MDNode *BufMDNode = MDNode::get(CGM.getLLVMContext(), BufGlobals);
- CGM.getModule().getOrInsertNamedMetadata("hlsl.cbs")->addOperand(BufMDNode);
-
// set the size of the buffer
- LayoutItems[BufferSizeIndex] = getConstIntMetadata(Ctx, BufferSize);
+ LayoutItems[1] = getConstIntMetadata(Ctx, BufferSize);
+
+ // add buffer metadata to the module
+ CGM.getModule()
+ .getOrInsertNamedMetadata("hlsl.cbs")
+ ->addOperand(MDNode::get(Ctx, BufGlobals));
- // add buffer layout to metadata
- MDNode *LayoutMDNode = MDNode::get(CGM.getLLVMContext(), LayoutItems);
CGM.getModule()
.getOrInsertNamedMetadata("hlsl.cblayouts")
- ->addOperand(LayoutMDNode);
+ ->addOperand(MDNode::get(Ctx, LayoutItems));
}
-// Creates resource handle type for the HLSL buffer
+// Creates resource handle type for the HLSL buffer declaration
static const clang::HLSLAttributedResourceType *
createBufferHandleType(const HLSLBufferDecl *BufDecl) {
ASTContext &AST = BufDecl->getASTContext();
@@ -319,26 +331,20 @@ createBufferHandleType(const HLSLBufferDecl *BufDecl) {
return cast<HLSLAttributedResourceType>(QT.getTypePtr());
}
-// Creates temporary global variables for all declarations within the constant
-// buffer context, creates a global variable for the constant buffer and adds
-// it to the module.
-// All uses of the temporary constant globals will be replaced with buffer
-// access intrinsic resource.getpointer in CGHLSLRuntime::finishCodeGen.
-// Later on in DXILResourceAccess pass these will be transtaled
-// to dx.op.cbufferLoadLegacy instructions.
+// Codegen for HLSLBufferDecl
void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
assert(BufDecl->isCBuffer() && "tbuffer codegen is not supported yet");
- // Create resource handle type for the buffer
+ // create resource handle type for the buffer
const clang::HLSLAttributedResourceType *ResHandleTy =
createBufferHandleType(BufDecl);
- // ignore empty constant buffer
+ // empty constant buffer is ignored
if (ResHandleTy->getContainedType()->getAsCXXRecordDecl()->isEmpty())
return;
- // Create global variable for the buffer
+ // create global variable for the constant buffer
llvm::Module &M = CGM.getModule();
llvm::TargetExtType *TargetTy =
cast<llvm::TargetExtType>(convertHLSLSpecificType(ResHandleTy));
@@ -350,10 +356,10 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
GlobalValue::NotThreadLocal);
M.insertGlobalVariable(BufGV);
- // Add globals for buffer elements and create metadata node for the buffer
+ // Add globals for constant buffer elements and create metadata nodes
emitBufferGlobalsAndMetadata(BufDecl, BufGV);
- // Add cbuffer resource initialization
+ // Resource initialization
const HLSLResourceBindingAttr *RBA =
BufDecl->getAttr<HLSLResourceBindingAttr>();
// FIXME: handle implicit binding if no binding attribute is found
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index d1f678863d4fb..8658cb8653fb4 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -71,7 +71,6 @@ class FunctionDecl;
namespace CodeGen {
class CodeGenModule;
-class CGBuilderTy;
class CGHLSLRuntime {
public:
@@ -175,7 +174,8 @@ class CGHLSLRuntime {
llvm::Triple::ArchType getArch();
- // sizes of structs that in constant buffer layout
+ // Sizes of structs in constant buffer layout. Structs in the map
+ // had their layout calculated and added to the module as metadata.
llvm::DenseMap<llvm::StructType *, size_t> StructSizesForBuffer;
};
diff --git a/clang/lib/CodeGen/Targets/DirectX.cpp b/clang/lib/CodeGen/Targets/DirectX.cpp
index 33bddc56d83f2..ec7fa342d5846 100644
--- a/clang/lib/CodeGen/Targets/DirectX.cpp
+++ b/clang/lib/CodeGen/Targets/DirectX.cpp
@@ -44,7 +44,6 @@ llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM,
return nullptr;
// convert element type
- // llvm::Type *ElemType = CGM.getTypes().ConvertTypeForMem(ContainedTy);
llvm::Type *ElemType = CGM.getTypes().ConvertType(ContainedTy);
llvm::StringRef TypeName =
diff --git a/clang/test/CodeGenHLSL/cbuffer.hlsl b/clang/test/CodeGenHLSL/cbuffer.hlsl
index e600d25c4e19c..9a3f632e859c7 100644
--- a/clang/test/CodeGenHLSL/cbuffer.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer.hlsl
@@ -164,6 +164,7 @@ void main() {
// CHECK-NEXT: call void @_init_resource_CBArrays.cb()
// CHECK: !hlsl.cbs = !{![[CBSCALARS:[0-9]+]], ![[CBVECTORS:[0-9]+]], ![[CBARRAYS:[0-9]+]], ![[CBSTRUCTS:[0-9]+]], ![[CBMIX:[0-9]+]]}
+
// CHECK: !hlsl.cblayouts = !{![[CBSCALARS_LAYOUT:[0-9]+]], ![[CBVECTORS_LAYOUT:[0-9]+]], ![[CBARRAYS_LAYOUT:[0-9]+]], ![[A_LAYOUT:[0-9]+]],
// CHECK-SAME: ![[B_LAYOUT:[0-9]+]], ![[C_LAYOUT:[0-9]+]], ![[D_LAYOUT:[0-9]+]], ![[CBSTRUCTS_LAYOUT:[0-9]+]], ![[TEST_LAYOUT:[0-9]+]],
// CHECK-SAME: ![[ANON_LAYOUT:[0-9]+]], ![[CBMIX_LAYOUT:[0-9]+]]}
@@ -193,7 +194,6 @@ void main() {
// CHECK: ![[C_LAYOUT]] = !{!"struct.C", i32 24, i32 0, i32 16}
// CHECK: ![[D_LAYOUT]] = !{!"struct.__cblayout_D", i32 94, i32 0}
// CHECK: ![[CBSTRUCTS_LAYOUT]] = !{!"struct.__cblayout_CBStructs", i32 262, i32 0, i32 16, i32 32, i32 64, i32 144, i32 238, i32 240, i32 256}
-
// CHECK: ![[TEST_LAYOUT]] = !{!"struct.Test", i32 8, i32 0, i32 4}
// CHECK: ![[ANON_LAYOUT]] = !{!"struct.anon", i32 4, i32 0}
// CHECK: ![[CBMIX_LAYOUT]] = !{!"struct.__cblayout_CBMix", i32 162, i32 0, i32 24, i32 32, i32 120, i32 128, i32 136, i32 144, i32 152, i32 160}
>From a12bcbc287d706c2c7fa56005badb40d4a0fa6fc Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 4 Feb 2025 12:59:13 -0800
Subject: [PATCH 06/13] Move skipping of implicit initializer of hlsl_constant
decls to a different PR.
---
clang/lib/Sema/SemaDecl.cpp | 6 ------
1 file changed, 6 deletions(-)
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index ba424567b23e0..7c70150871da9 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14184,12 +14184,6 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
Var->getType().getAddressSpace() == LangAS::opencl_local)
return;
- // In HLSL, objects in the hlsl_constat address space are initialized
- // externaly, so don't synthesize an implicit initializer.
- if (getLangOpts().HLSL &&
- Var->getType().getAddressSpace() == LangAS::hlsl_constant)
- return;
-
// C++03 [dcl.init]p9:
// If no initializer is specified for an object, and the
// object is of (possibly cv-qualified) non-POD class type (or
>From 66ae78472080bb2b9de4b99ff63b5219f14c75c8 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 4 Feb 2025 17:58:43 -0800
Subject: [PATCH 07/13] Add LayoutStruct to HLSLBufferDecl; add skipping of
implicit initializers
---
clang/include/clang/AST/Decl.h | 5 ++++-
clang/lib/AST/Decl.cpp | 15 +++++----------
clang/lib/Sema/SemaDecl.cpp | 6 ++++++
clang/lib/Sema/SemaHLSL.cpp | 2 +-
4 files changed, 16 insertions(+), 12 deletions(-)
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index e1c7e3817699c..05e56978977f2 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -5035,6 +5035,8 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext {
/// HasValidPackoffset - Whether the buffer has valid packoffset annotations
// on all declarations
bool HasPackoffset;
+ // LayoutStruct - Layout struct for the buffer
+ CXXRecordDecl *LayoutStruct;
HLSLBufferDecl(DeclContext *DC, bool CBuffer, SourceLocation KwLoc,
IdentifierInfo *ID, SourceLocation IDLoc,
@@ -5057,7 +5059,8 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext {
bool isCBuffer() const { return IsCBuffer; }
void setHasPackoffset(bool PO) { HasPackoffset = PO; }
bool hasPackoffset() const { return HasPackoffset; }
- const CXXRecordDecl *getLayoutStruct() const;
+ const CXXRecordDecl *getLayoutStruct() const { return LayoutStruct; }
+ void addLayoutStruct(CXXRecordDecl *LS);
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index fa7d03354a993..4c5201d0ba2ee 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -5717,7 +5717,7 @@ HLSLBufferDecl::HLSLBufferDecl(DeclContext *DC, bool CBuffer,
SourceLocation IDLoc, SourceLocation LBrace)
: NamedDecl(Decl::Kind::HLSLBuffer, DC, IDLoc, DeclarationName(ID)),
DeclContext(Decl::Kind::HLSLBuffer), LBraceLoc(LBrace), KwLoc(KwLoc),
- IsCBuffer(CBuffer), HasPackoffset(false) {}
+ IsCBuffer(CBuffer), HasPackoffset(false), LayoutStruct(nullptr) {}
HLSLBufferDecl *HLSLBufferDecl::Create(ASTContext &C,
DeclContext *LexicalParent, bool CBuffer,
@@ -5747,15 +5747,10 @@ HLSLBufferDecl *HLSLBufferDecl::CreateDeserialized(ASTContext &C,
SourceLocation(), SourceLocation());
}
-const CXXRecordDecl *HLSLBufferDecl::getLayoutStruct() const {
- // Layout struct is the last decl in the HLSLBufferDecl.
- if (CXXRecordDecl *RD = llvm::dyn_cast_or_null<CXXRecordDecl>(LastDecl)) {
- assert(RD->getName().starts_with(
- ("__cblayout_" + getIdentifier()->getName()).str()) &&
- "expected buffer layout struct");
- return RD;
- }
- llvm_unreachable("HLSL buffer is missing a layout struct");
+void HLSLBufferDecl::addLayoutStruct(CXXRecordDecl *LS) {
+ assert(LayoutStruct == nullptr && "layout struct has already been set");
+ LayoutStruct = LS;
+ addDecl(LS);
}
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 7c70150871da9..5497c30ed09ff 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14184,6 +14184,12 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
Var->getType().getAddressSpace() == LangAS::opencl_local)
return;
+ // In HLSL, objects in the hlsl_constant address space are initialized
+ // externally, so don't synthesize an implicit initializer.
+ if (getLangOpts().HLSL &&
+ Var->getType().getAddressSpace() == LangAS::hlsl_constant)
+ return;
+
// C++03 [dcl.init]p9:
// If no initializer is specified for an object, and the
// object is of (possibly cv-qualified) non-POD class type (or
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 2807cc773320b..d80e605055ad7 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -502,7 +502,7 @@ void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) {
}
}
LS->completeDefinition();
- BufDecl->addDecl(LS);
+ BufDecl->addLayoutStruct(LS);
}
// Handle end of cbuffer/tbuffer declaration
>From e042f72eee72ffb58d27dfd5e6011bd2e510ab84 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 4 Feb 2025 20:52:25 -0800
Subject: [PATCH 08/13] desugar types and check for resource builtin type
---
clang/lib/Sema/SemaHLSL.cpp | 3 ++-
clang/test/AST/HLSL/cbuffer.hlsl | 2 ++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index b71dd2b273a1c..a4d5b89794af4 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -282,6 +282,7 @@ static bool isResourceRecordTypeOrArrayOf(const Type *Ty) {
// array, or a builtin intangible type. Returns false it is a valid leaf element
// type or if it is a record type that needs to be inspected further.
static bool isInvalidConstantBufferLeafElementType(const Type *Ty) {
+ Ty = Ty->getUnqualifiedDesugaredType();
if (isResourceRecordTypeOrArrayOf(Ty))
return true;
if (Ty->isRecordType())
@@ -289,7 +290,7 @@ static bool isInvalidConstantBufferLeafElementType(const Type *Ty) {
if (Ty->isConstantArrayType() &&
isZeroSizedArray(cast<ConstantArrayType>(Ty)))
return true;
- if (Ty->isHLSLBuiltinIntangibleType())
+ if (Ty->isHLSLBuiltinIntangibleType() || Ty->isHLSLAttributedResourceType())
return true;
return false;
}
diff --git a/clang/test/AST/HLSL/cbuffer.hlsl b/clang/test/AST/HLSL/cbuffer.hlsl
index 865db1201baa5..87202d7998bdb 100644
--- a/clang/test/AST/HLSL/cbuffer.hlsl
+++ b/clang/test/AST/HLSL/cbuffer.hlsl
@@ -75,6 +75,8 @@ cbuffer CB {
groupshared float g2;
// CHECK: VarDecl {{.*}} e2 'hlsl_constant float'
float e2;
+ // CHECK: VarDecl {{.*}} h2 '__hlsl_resource_t'
+ __hlsl_resource_t h2;
// CHECK: CXXRecordDecl {{.*}} implicit referenced struct __cblayout_CB_1 definition
// CHECK: PackedAttr
// CHECK-NEXT: FieldDecl {{.*}} a2 'float'
>From b62863b900dd63eb1c8e3ffe656bbcbb6770dbdd Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 11 Feb 2025 20:32:51 -0800
Subject: [PATCH 09/13] Rework cbuffer codegen to use the target("dx.Layout",
...) type
---
clang/include/clang/AST/Decl.h | 6 +-
clang/lib/AST/Decl.cpp | 2 +-
clang/lib/CodeGen/CGHLSLRuntime.cpp | 226 +++++-------------
clang/lib/CodeGen/CGHLSLRuntime.h | 20 +-
clang/lib/CodeGen/CMakeLists.txt | 1 +
clang/lib/CodeGen/TargetInfo.h | 4 +-
clang/lib/CodeGen/Targets/DirectX.cpp | 42 +++-
clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp | 201 ++++++++++++++++
clang/lib/CodeGen/Targets/HLSLTargetInfo.h | 39 +++
clang/lib/CodeGen/Targets/SPIR.cpp | 16 +-
clang/lib/Sema/SemaHLSL.cpp | 2 +-
clang/test/CodeGenHLSL/cbuffer.hlsl | 120 +++++-----
.../CodeGenHLSL/cbuffer_and_namespaces.hlsl | 23 +-
.../CodeGenHLSL/cbuffer_and_namespaces.ll | 49 ++++
.../CodeGenHLSL/cbuffer_with_packoffset.hlsl | 10 +-
...uffer_with_static_global_and_function.hlsl | 7 +-
16 files changed, 482 insertions(+), 286 deletions(-)
create mode 100644 clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp
create mode 100644 clang/lib/CodeGen/Targets/HLSLTargetInfo.h
create mode 100644 clang/test/CodeGenHLSL/cbuffer_and_namespaces.ll
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 05e56978977f2..85cef38bc03db 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -5034,7 +5034,7 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext {
bool IsCBuffer;
/// HasValidPackoffset - Whether the buffer has valid packoffset annotations
// on all declarations
- bool HasPackoffset;
+ bool HasValidPackoffset;
// LayoutStruct - Layout struct for the buffer
CXXRecordDecl *LayoutStruct;
@@ -5057,8 +5057,8 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext {
SourceLocation getRBraceLoc() const { return RBraceLoc; }
void setRBraceLoc(SourceLocation L) { RBraceLoc = L; }
bool isCBuffer() const { return IsCBuffer; }
- void setHasPackoffset(bool PO) { HasPackoffset = PO; }
- bool hasPackoffset() const { return HasPackoffset; }
+ void setHasValidPackoffset(bool PO) { HasValidPackoffset = PO; }
+ bool hasValidPackoffset() const { return HasValidPackoffset; }
const CXXRecordDecl *getLayoutStruct() const { return LayoutStruct; }
void addLayoutStruct(CXXRecordDecl *LS);
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 4c5201d0ba2ee..95b25164d63dc 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -5717,7 +5717,7 @@ HLSLBufferDecl::HLSLBufferDecl(DeclContext *DC, bool CBuffer,
SourceLocation IDLoc, SourceLocation LBrace)
: NamedDecl(Decl::Kind::HLSLBuffer, DC, IDLoc, DeclarationName(ID)),
DeclContext(Decl::Kind::HLSLBuffer), LBraceLoc(LBrace), KwLoc(KwLoc),
- IsCBuffer(CBuffer), HasPackoffset(false), LayoutStruct(nullptr) {}
+ IsCBuffer(CBuffer), HasValidPackoffset(false), LayoutStruct(nullptr) {}
HLSLBufferDecl *HLSLBufferDecl::Create(ASTContext &C,
DeclContext *LexicalParent, bool CBuffer,
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 52247173b6990..fde801dd1a8a4 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/Type.h"
#include "clang/Basic/TargetOptions.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/LLVMContext.h"
@@ -70,11 +71,14 @@ void addDisableOptimizations(llvm::Module &M) {
} // namespace
-llvm::Type *CGHLSLRuntime::convertHLSLSpecificType(const Type *T) {
+llvm::Type *
+CGHLSLRuntime::convertHLSLSpecificType(const Type *T,
+ SmallVector<unsigned> *Packoffsets) {
assert(T->isHLSLSpecificType() && "Not an HLSL specific type!");
// Check if the target has a specific translation for this type first.
- if (llvm::Type *TargetTy = CGM.getTargetCodeGenInfo().getHLSLType(CGM, T))
+ if (llvm::Type *TargetTy =
+ CGM.getTargetCodeGenInfo().getHLSLType(CGM, T, Packoffsets))
return TargetTy;
llvm_unreachable("Generic handling of HLSL types is not supported.");
@@ -96,153 +100,28 @@ static bool isResourceRecordTypeOrArrayOf(const clang::Type *Ty) {
return isResourceRecordType(Ty);
}
-static ConstantAsMetadata *getConstIntMetadata(LLVMContext &Ctx, uint32_t value,
- bool isSigned = false) {
- return ConstantAsMetadata::get(
- ConstantInt::get(Ctx, llvm::APInt(32, value, isSigned)));
-}
-
-static unsigned getScalarOrVectorSize(llvm::Type *Ty) {
- assert(Ty->isVectorTy() || Ty->isIntegerTy() || Ty->isFloatingPointTy());
- if (Ty->isVectorTy()) {
- llvm::FixedVectorType *FVT = cast<llvm::FixedVectorType>(Ty);
- return FVT->getNumElements() *
- (FVT->getElementType()->getScalarSizeInBits() / 8);
- }
- return Ty->getScalarSizeInBits() / 8;
-}
-
-// Returns size of a struct in constant buffer layout. The sizes are cached
-// in StructSizesForBuffer map. The map is also an indicator if a layout
-// metadata for this struct has been added to the module.
-// If the struct type is not in the map, this method will calculate the struct
-// layout, add a metadata node describing it to the module, and add the struct
-// size to the map.
-size_t
-CGHLSLRuntime::getOrCalculateStructSizeForBuffer(llvm::StructType *StructTy) {
- // check if we already have a side for this struct
- auto SizeIt = StructSizesForBuffer.find(StructTy);
- if (SizeIt != StructSizesForBuffer.end())
- return SizeIt->getSecond();
-
- // if not, calculate the struct layout and create a metadata node
- LLVMContext &Ctx = CGM.getLLVMContext();
- SmallVector<llvm::Metadata *> LayoutItems;
-
- // start metadata list with a struct name and reserve one slot for its size
- LayoutItems.push_back(MDString::get(Ctx, StructTy->getName()));
- LayoutItems.push_back(nullptr);
-
- // add element offsets
- size_t StructSize = 0;
- for (llvm::Type *ElTy : StructTy->elements()) {
- size_t Offset = calculateBufferElementOffset(ElTy, &StructSize);
- LayoutItems.push_back(getConstIntMetadata(CGM.getLLVMContext(), Offset));
- }
- // set the size of the buffer to the reserved slot
- LayoutItems[1] = getConstIntMetadata(Ctx, StructSize);
-
- // add the struct layout to metadata
- CGM.getModule()
- .getOrInsertNamedMetadata("hlsl.cblayouts")
- ->addOperand(MDNode::get(CGM.getLLVMContext(), LayoutItems));
-
- // add struct size to list and return it
- StructSizesForBuffer[StructTy] = StructSize;
- return StructSize;
-}
-
-// Calculates offset of a single element in constant buffer layout.
-// The provided LayoutEndOffset marks the end of the layout so far (end offset
-// of the buffer or struct). After the element offset calculations are done it
-// will be updated the new end of layout value.
-// If the PackoffsetAttrs is not nullptr the offset will be based on the
-// packoffset annotation.
-size_t CGHLSLRuntime::calculateBufferElementOffset(
- llvm::Type *LayoutTy, size_t *LayoutEndOffset,
- HLSLPackOffsetAttr *PackoffsetAttr) {
-
- size_t ElemOffset = 0;
- size_t ElemSize = 0;
- size_t ArrayCount = 1;
- size_t ArrayStride = 0;
- size_t EndOffset = *LayoutEndOffset;
- size_t NextRowOffset = llvm::alignTo(EndOffset, 16U);
-
- if (LayoutTy->isArrayTy()) {
- llvm::Type *Ty = LayoutTy;
- while (Ty->isArrayTy()) {
- ArrayCount *= Ty->getArrayNumElements();
- Ty = Ty->getArrayElementType();
- }
- ElemSize =
- Ty->isStructTy()
- ? getOrCalculateStructSizeForBuffer(cast<llvm::StructType>(Ty))
- : getScalarOrVectorSize(Ty);
- ArrayStride = llvm::alignTo(ElemSize, 16U);
- ElemOffset =
- PackoffsetAttr ? PackoffsetAttr->getOffsetInBytes() : NextRowOffset;
-
- } else if (LayoutTy->isStructTy()) {
- ElemOffset =
- PackoffsetAttr ? PackoffsetAttr->getOffsetInBytes() : NextRowOffset;
- ElemSize =
- getOrCalculateStructSizeForBuffer(cast<llvm::StructType>(LayoutTy));
-
- } else {
- size_t Align = 0;
- if (LayoutTy->isVectorTy()) {
- llvm::FixedVectorType *FVT = cast<llvm::FixedVectorType>(LayoutTy);
- size_t SubElemSize = FVT->getElementType()->getScalarSizeInBits() / 8;
- ElemSize = FVT->getNumElements() * SubElemSize;
- Align = SubElemSize;
- } else {
- assert(LayoutTy->isIntegerTy() || LayoutTy->isFloatingPointTy());
- ElemSize = LayoutTy->getScalarSizeInBits() / 8;
- Align = ElemSize;
- }
- if (PackoffsetAttr) {
- ElemOffset = PackoffsetAttr->getOffsetInBytes();
- } else {
- ElemOffset = llvm::alignTo(EndOffset, Align);
- // if the element does not fit, move it to the next row
- if (ElemOffset + ElemSize > NextRowOffset)
- ElemOffset = NextRowOffset;
- }
- }
-
- // Update end offset of the buffer/struct layout; do not update it if
- // the provided EndOffset is already bigger than the new one value
- // (which may happen with packoffset annotations)
- unsigned NewEndOffset =
- ElemOffset + (ArrayCount - 1) * ArrayStride + ElemSize;
- *LayoutEndOffset = std::max<size_t>(EndOffset, NewEndOffset);
-
- return ElemOffset;
-}
-
-// Emits constant global variables for buffer declarations, creates metadata
-// linking the constant globals with the buffer. Also calculates the buffer
-// layout and creates metadata node describing it.
+// Emits constant global variables for buffer constants declarations
+// and creates metadata linking the constant globals with the buffer global.
void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
llvm::GlobalVariable *BufGV) {
LLVMContext &Ctx = CGM.getLLVMContext();
+
+ // get the layout struct from constant buffer target type
+ llvm::Type *BufType = BufGV->getValueType();
+ assert(isa<llvm::TargetExtType>(BufType) &&
+ "expected target type for HLSL buffer resource");
+ llvm::Type *BufLayoutType =
+ cast<llvm::TargetExtType>(BufType)->getTypeParameter(0);
+ assert(isa<llvm::TargetExtType>(BufLayoutType) &&
+ "expected target type for buffer layout struct");
llvm::StructType *LayoutStruct = cast<llvm::StructType>(
- cast<llvm::TargetExtType>(BufGV->getValueType())->getTypeParameter(0));
+ cast<llvm::TargetExtType>(BufLayoutType)->getTypeParameter(0));
// Start metadata list associating the buffer global variable with its
// constatns
SmallVector<llvm::Metadata *> BufGlobals;
BufGlobals.push_back(ValueAsMetadata::get(BufGV));
- // Start layout metadata list with a struct name and reserve one slot for
- // the buffer size
- SmallVector<llvm::Metadata *> LayoutItems;
- LayoutItems.push_back(MDString::get(Ctx, LayoutStruct->getName()));
- LayoutItems.push_back(nullptr);
-
- size_t BufferSize = 0;
- bool UsePackoffset = BufDecl->hasPackoffset();
const auto *ElemIt = LayoutStruct->element_begin();
for (Decl *D : BufDecl->decls()) {
if (isa<CXXRecordDecl, EmptyDecl>(D))
@@ -275,17 +154,6 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
"number of elements in layout struct does not match");
llvm::Type *LayoutType = *ElemIt++;
- // Make sure the type of the VarDecl type matches the type of the layout
- // struct element, or that it is a layout struct with the same name
- assert((CGM.getTypes().ConvertTypeForMem(VDTy) == LayoutType ||
- (LayoutType->isStructTy() &&
- cast<llvm::StructType>(LayoutType)
- ->getName()
- .starts_with(("struct.__cblayout_" +
- VDTy->getAsCXXRecordDecl()->getName())
- .str()))) &&
- "layout type does not match the converted element type");
-
// there might be resources inside the used defined structs
if (VDTy->isStructureType() && VDTy->isHLSLIntangibleType())
// FIXME: handle resources in cbuffer structs
@@ -295,29 +163,15 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
GlobalVariable *ElemGV =
cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(VD, LayoutType));
BufGlobals.push_back(ValueAsMetadata::get(ElemGV));
-
- // get offset of the global and and to metadata list
- assert(((UsePackoffset && VD->hasAttr<HLSLPackOffsetAttr>()) ||
- !UsePackoffset) &&
- "expected packoffset attribute on every declaration");
- size_t Offset = calculateBufferElementOffset(
- LayoutType, &BufferSize,
- UsePackoffset ? VD->getAttr<HLSLPackOffsetAttr>() : nullptr);
- LayoutItems.push_back(getConstIntMetadata(Ctx, Offset));
}
assert(ElemIt == LayoutStruct->element_end() &&
"number of elements in layout struct does not match");
// set the size of the buffer
- LayoutItems[1] = getConstIntMetadata(Ctx, BufferSize);
// add buffer metadata to the module
CGM.getModule()
.getOrInsertNamedMetadata("hlsl.cbs")
->addOperand(MDNode::get(Ctx, BufGlobals));
-
- CGM.getModule()
- .getOrInsertNamedMetadata("hlsl.cblayouts")
- ->addOperand(MDNode::get(Ctx, LayoutItems));
}
// Creates resource handle type for the HLSL buffer declaration
@@ -331,6 +185,25 @@ createBufferHandleType(const HLSLBufferDecl *BufDecl) {
return cast<HLSLAttributedResourceType>(QT.getTypePtr());
}
+static void fillPackoffsetLayout(const HLSLBufferDecl *BufDecl,
+ SmallVector<unsigned> &Layout) {
+ assert(Layout.empty() && "expected empty vector for layout");
+ assert(BufDecl->hasValidPackoffset());
+
+ for (Decl *D : BufDecl->decls()) {
+ if (isa<CXXRecordDecl, EmptyDecl>(D) || isa<FunctionDecl>(D)) {
+ continue;
+ }
+ VarDecl *VD = dyn_cast<VarDecl>(D);
+ if (!VD || VD->getType().getAddressSpace() != LangAS::hlsl_constant)
+ continue;
+ assert(VD->hasAttr<HLSLPackOffsetAttr>() &&
+ "expected packoffset attribute on every declaration");
+ size_t Offset = VD->getAttr<HLSLPackOffsetAttr>()->getOffsetInBytes();
+ Layout.push_back(Offset);
+ }
+}
+
// Codegen for HLSLBufferDecl
void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
@@ -345,16 +218,20 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
return;
// create global variable for the constant buffer
- llvm::Module &M = CGM.getModule();
+ SmallVector<unsigned> Layout;
+ if (BufDecl->hasValidPackoffset())
+ fillPackoffsetLayout(BufDecl, Layout);
+
llvm::TargetExtType *TargetTy =
- cast<llvm::TargetExtType>(convertHLSLSpecificType(ResHandleTy));
+ cast<llvm::TargetExtType>(convertHLSLSpecificType(
+ ResHandleTy, BufDecl->hasValidPackoffset() ? &Layout : nullptr));
llvm::GlobalVariable *BufGV =
new GlobalVariable(TargetTy, /*isConstant*/ true,
GlobalValue::LinkageTypes::ExternalLinkage, nullptr,
llvm::formatv("{0}{1}", BufDecl->getName(),
BufDecl->isCBuffer() ? ".cb" : ".tb"),
GlobalValue::NotThreadLocal);
- M.insertGlobalVariable(BufGV);
+ CGM.getModule().insertGlobalVariable(BufGV);
// Add globals for constant buffer elements and create metadata nodes
emitBufferGlobalsAndMetadata(BufDecl, BufGV);
@@ -368,6 +245,21 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
RBA->getSpaceNumber());
}
+llvm::Type *
+CGHLSLRuntime::getHLSLBufferLayoutType(const RecordType *StructType) {
+ const auto Entry = LayoutTypes.find(StructType);
+ if (Entry != LayoutTypes.end())
+ return Entry->getSecond();
+ return nullptr;
+}
+
+void CGHLSLRuntime::addHLSLBufferLayoutType(const RecordType *StructType,
+ llvm::Type *LayoutTy) {
+ assert(getHLSLBufferLayoutType(StructType) == nullptr &&
+ "layout type for this struct already exist");
+ LayoutTypes[StructType] = LayoutTy;
+}
+
void CGHLSLRuntime::finishCodeGen() {
auto &TargetOpts = CGM.getTarget().getTargetOpts();
llvm::Module &M = CGM.getModule();
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 8658cb8653fb4..6d2054e9efd50 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -63,6 +63,7 @@ class ParmVarDecl;
class HLSLBufferDecl;
class HLSLResourceBindingAttr;
class Type;
+class RecordType;
class DeclContext;
class HLSLPackOffsetAttr;
@@ -141,7 +142,9 @@ class CGHLSLRuntime {
CGHLSLRuntime(CodeGenModule &CGM) : CGM(CGM) {}
virtual ~CGHLSLRuntime() {}
- llvm::Type *convertHLSLSpecificType(const Type *T);
+ llvm::Type *
+ convertHLSLSpecificType(const Type *T,
+ SmallVector<unsigned> *Packoffsets = nullptr);
void annotateHLSLResource(const VarDecl *D, llvm::GlobalVariable *GV);
void generateGlobalCtorDtorCalls();
@@ -157,6 +160,10 @@ class CGHLSLRuntime {
llvm::Instruction *getConvergenceToken(llvm::BasicBlock &BB);
+ llvm::Type *getHLSLBufferLayoutType(const RecordType *LayoutStructTy);
+ void addHLSLBufferLayoutType(const RecordType *LayoutStructTy,
+ llvm::Type *LayoutTy);
+
private:
void addBufferResourceAnnotation(llvm::GlobalVariable *GV,
llvm::hlsl::ResourceClass RC,
@@ -165,18 +172,9 @@ class CGHLSLRuntime {
BufferResBinding &Binding);
void emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
llvm::GlobalVariable *BufGV);
-
- size_t
- calculateBufferElementOffset(llvm::Type *LayoutTy, size_t *LayoutEndOffset,
- HLSLPackOffsetAttr *PackoffsetAttr = nullptr);
-
- size_t getOrCalculateStructSizeForBuffer(llvm::StructType *StructTy);
-
llvm::Triple::ArchType getArch();
- // Sizes of structs in constant buffer layout. Structs in the map
- // had their layout calculated and added to the module as metadata.
- llvm::DenseMap<llvm::StructType *, size_t> StructSizesForBuffer;
+ llvm::DenseMap<const clang::RecordType *, llvm::Type *> LayoutTypes;
};
} // namespace CodeGen
diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt
index 868ec847b9634..1a6b25883d9c8 100644
--- a/clang/lib/CodeGen/CMakeLists.txt
+++ b/clang/lib/CodeGen/CMakeLists.txt
@@ -124,6 +124,7 @@ add_clang_library(clangCodeGen
Targets/CSKY.cpp
Targets/DirectX.cpp
Targets/Hexagon.cpp
+ Targets/HLSLTargetInfo.cpp
Targets/Lanai.cpp
Targets/LoongArch.cpp
Targets/M68k.cpp
diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h
index 4a66683a3b91f..86057c14a549e 100644
--- a/clang/lib/CodeGen/TargetInfo.h
+++ b/clang/lib/CodeGen/TargetInfo.h
@@ -439,7 +439,9 @@ class TargetCodeGenInfo {
}
/// Return an LLVM type that corresponds to a HLSL type
- virtual llvm::Type *getHLSLType(CodeGenModule &CGM, const Type *T) const {
+ virtual llvm::Type *
+ getHLSLType(CodeGenModule &CGM, const Type *T,
+ const SmallVector<unsigned> *Packoffsets = nullptr) const {
return nullptr;
}
diff --git a/clang/lib/CodeGen/Targets/DirectX.cpp b/clang/lib/CodeGen/Targets/DirectX.cpp
index ec7fa342d5846..3d4b65aec0a3a 100644
--- a/clang/lib/CodeGen/Targets/DirectX.cpp
+++ b/clang/lib/CodeGen/Targets/DirectX.cpp
@@ -7,8 +7,13 @@
//===----------------------------------------------------------------------===//
#include "ABIInfoImpl.h"
+#include "CodeGenModule.h"
+#include "HLSLTargetInfo.h"
#include "TargetInfo.h"
+#include "clang/AST/Type.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Type.h"
using namespace clang;
using namespace clang::CodeGen;
@@ -19,16 +24,30 @@ using namespace clang::CodeGen;
namespace {
-class DirectXTargetCodeGenInfo : public TargetCodeGenInfo {
+class DirectXTargetCodeGenInfo : public CommonHLSLTargetCodeGenInfo {
public:
DirectXTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
- : TargetCodeGenInfo(std::make_unique<DefaultABIInfo>(CGT)) {}
+ : CommonHLSLTargetCodeGenInfo(std::make_unique<DefaultABIInfo>(CGT)) {}
- llvm::Type *getHLSLType(CodeGenModule &CGM, const Type *T) const override;
+ llvm::Type *getHLSLType(
+ CodeGenModule &CGM, const Type *T,
+ const SmallVector<unsigned> *Packoffsets = nullptr) const override;
+
+ llvm::Type *getHLSLLayoutType(CodeGenModule &CGM,
+ llvm::StructType *LayoutStructTy,
+ SmallVector<unsigned> Layout) const override;
};
-llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM,
- const Type *Ty) const {
+llvm::Type *DirectXTargetCodeGenInfo::getHLSLLayoutType(
+ CodeGenModule &CGM, llvm::StructType *LayoutStructTy,
+ SmallVector<unsigned> Layout) const {
+ return llvm::TargetExtType::get(CGM.getLLVMContext(), "dx.Layout",
+ {LayoutStructTy}, Layout);
+}
+
+llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(
+ CodeGenModule &CGM, const Type *Ty,
+ const SmallVector<unsigned> *Packoffsets) const {
auto *ResType = dyn_cast<HLSLAttributedResourceType>(Ty);
if (!ResType)
return nullptr;
@@ -57,11 +76,16 @@ llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM,
return llvm::TargetExtType::get(Ctx, TypeName, {ElemType}, Ints);
}
case llvm::dxil::ResourceClass::CBuffer: {
- QualType StructTy = ResType->getContainedType();
- if (StructTy.isNull())
+ QualType ContainedTy = ResType->getContainedType();
+ if (ContainedTy.isNull() || !ContainedTy->isStructureType())
return nullptr;
- llvm::Type *Ty = CGM.getTypes().ConvertType(StructTy);
- return llvm::TargetExtType::get(Ctx, "dx.CBuffer", {Ty});
+
+ llvm::Type *BufferLayoutTy = this->createHLSLBufferLayoutType(
+ CGM, ContainedTy->getAsStructureType(), Packoffsets);
+ if (!BufferLayoutTy)
+ return nullptr;
+
+ return llvm::TargetExtType::get(Ctx, "dx.CBuffer", {BufferLayoutTy});
}
case llvm::dxil::ResourceClass::Sampler:
llvm_unreachable("dx.Sampler handles are not implemented yet");
diff --git a/clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp b/clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp
new file mode 100644
index 0000000000000..e0e7f6daddcfa
--- /dev/null
+++ b/clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp
@@ -0,0 +1,201 @@
+//===- HLSLTargetInto.cpp--------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "HLSLTargetInfo.h"
+#include "CGHLSLRuntime.h"
+#include "TargetInfo.h"
+#include "clang/AST/DeclCXX.h"
+
+//===----------------------------------------------------------------------===//
+// Target codegen info implementation common between DirectX and SPIR/SPIR-V.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+// Creates a new array type with the same dimentions
+// but with the new element type.
+static llvm::Type *
+createArrayWithNewElementType(CodeGenModule &CGM,
+ const ConstantArrayType *ArrayType,
+ llvm::Type *NewElemType) {
+ const clang::Type *ArrayElemType = ArrayType->getArrayElementTypeNoTypeQual();
+ if (ArrayElemType->isConstantArrayType())
+ NewElemType = createArrayWithNewElementType(
+ CGM, cast<const ConstantArrayType>(ArrayElemType), NewElemType);
+ return llvm::ArrayType::get(NewElemType, ArrayType->getSExtSize());
+}
+
+// Returns the size of a scalar or vector in bytes/
+static unsigned getScalarOrVectorSize(llvm::Type *Ty) {
+ assert(Ty->isVectorTy() || Ty->isIntegerTy() || Ty->isFloatingPointTy());
+ if (Ty->isVectorTy()) {
+ llvm::FixedVectorType *FVT = cast<llvm::FixedVectorType>(Ty);
+ return FVT->getNumElements() *
+ (FVT->getElementType()->getScalarSizeInBits() / 8);
+ }
+ return Ty->getScalarSizeInBits() / 8;
+}
+
+} // namespace
+
+// Creates a layout type for given struct with HLSL constant buffer layout
+// taking into account Packoffsets, if provided.
+// Previously created layout types are cached in CGHLSLRuntime because
+// TargetCodeGenInto info is cannot store any data
+// (CGM.getTargetCodeGenInfo() returns a const reference to TargetCondegenInfo).
+//
+// The function iterates over all fields of the StructType (including base
+// classes), converts each field to its corresponding LLVM type and calculated
+// it's HLSL constant bufffer layout (offset and size). Any embedded struct (or
+// arrays of structs) are converted to target layout types as well.
+llvm::Type *CommonHLSLTargetCodeGenInfo::createHLSLBufferLayoutType(
+ CodeGenModule &CGM, const RecordType *StructType,
+ const SmallVector<unsigned> *Packoffsets) const {
+
+ // check if we already have the layout type for this struct
+ if (llvm::Type *Ty = CGM.getHLSLRuntime().getHLSLBufferLayoutType(StructType))
+ return Ty;
+
+ SmallVector<unsigned> Layout;
+ SmallVector<llvm::Type *> LayoutElements;
+ unsigned Index = 0; // packoffset index
+ unsigned EndOffset = 0;
+
+ // reserve first spot in the layout vector for buffer size
+ Layout.push_back(0);
+
+ // iterate over all fields of the record, including fields on base classes
+ llvm::SmallVector<const RecordType *> RecordTypes;
+ RecordTypes.push_back(StructType);
+ while (RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
+ CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl();
+ assert(D->getNumBases() == 1 &&
+ "HLSL doesn't support multiple inheritance");
+ RecordTypes.push_back(D->bases_begin()->getType()->getAs<RecordType>());
+ }
+ while (!RecordTypes.empty()) {
+ const RecordType *RT = RecordTypes.back();
+ RecordTypes.pop_back();
+
+ for (const auto *FD : RT->getDecl()->fields()) {
+ assert(!Packoffsets || Index < Packoffsets->size() &&
+ "number of elements in layout struct does not "
+ "match number of packoffset annotations");
+ // Size of element; for arrays this is a size of a single element in the
+ // array. Total array size of calculated as (ArrayCount-1) * ArrayStride +
+ // ElemSize.
+ unsigned ElemSize = 0;
+
+ unsigned ElemOffset = 0;
+ unsigned ArrayCount = 1;
+ unsigned ArrayStride = 0;
+ unsigned NextRowOffset = llvm::alignTo(EndOffset, 16U);
+ llvm::Type *ElemLayoutTy = nullptr;
+
+ QualType FieldTy = FD->getType();
+
+ if (FieldTy->isConstantArrayType()) {
+ // Unwrap array to find the element type and get combined array size.
+ QualType Ty = FieldTy;
+ while (Ty->isConstantArrayType()) {
+ const ConstantArrayType *ArrayTy = cast<ConstantArrayType>(Ty);
+ ArrayCount *= ArrayTy->getSExtSize();
+ Ty = ArrayTy->getElementType();
+ }
+ // For array of structures, create a new array with a layout type
+ // instead of the structure type.
+ if (Ty->isStructureType()) {
+ llvm::Type *NewTy = cast<llvm::TargetExtType>(
+ createHLSLBufferLayoutType(CGM, Ty->getAsStructureType()));
+ if (!NewTy)
+ return nullptr;
+ assert(isa<llvm::TargetExtType>(NewTy) && "expected target type");
+ ElemSize = cast<llvm::TargetExtType>(NewTy)->getIntParameter(0);
+ ElemLayoutTy = createArrayWithNewElementType(
+ CGM, cast<ConstantArrayType>(FieldTy.getTypePtr()), NewTy);
+ } else {
+ // Array of vectors or scalars
+ ElemSize =
+ getScalarOrVectorSize(CGM.getTypes().ConvertTypeForMem(Ty));
+ ElemLayoutTy = CGM.getTypes().ConvertTypeForMem(FieldTy);
+ }
+ ArrayStride = llvm::alignTo(ElemSize, 16U);
+ ElemOffset =
+ Packoffsets != nullptr ? (*Packoffsets)[Index] : NextRowOffset;
+
+ } else if (FieldTy->isStructureType()) {
+ // Create a layout type for the structure
+ ElemLayoutTy =
+ createHLSLBufferLayoutType(CGM, FieldTy->getAsStructureType());
+ if (!ElemLayoutTy)
+ return nullptr;
+ assert(isa<llvm::TargetExtType>(ElemLayoutTy) &&
+ "expected target type");
+ ElemSize = cast<llvm::TargetExtType>(ElemLayoutTy)->getIntParameter(0);
+ ElemOffset =
+ Packoffsets != nullptr ? (*Packoffsets)[Index] : NextRowOffset;
+ } else {
+ // scalar or vector - find element size and alignment
+ unsigned Align = 0;
+ ElemLayoutTy = CGM.getTypes().ConvertTypeForMem(FieldTy);
+ if (ElemLayoutTy->isVectorTy()) {
+ // align vectors by sub element size
+ const llvm::FixedVectorType *FVT =
+ cast<llvm::FixedVectorType>(ElemLayoutTy);
+ unsigned SubElemSize =
+ FVT->getElementType()->getScalarSizeInBits() / 8;
+ ElemSize = FVT->getNumElements() * SubElemSize;
+ Align = SubElemSize;
+ } else {
+ assert(ElemLayoutTy->isIntegerTy() ||
+ ElemLayoutTy->isFloatingPointTy());
+ ElemSize = ElemLayoutTy->getScalarSizeInBits() / 8;
+ Align = ElemSize;
+ }
+ // calculate or get element offset for the vector or scalar
+ if (Packoffsets != nullptr) {
+ ElemOffset = (*Packoffsets)[Index];
+ } else {
+ ElemOffset = llvm::alignTo(EndOffset, Align);
+ // if the element does not fit, move it to the next row
+ if (ElemOffset + ElemSize > NextRowOffset)
+ ElemOffset = NextRowOffset;
+ }
+ }
+
+ // Update end offset of the layout; do not update it if the EndOffset
+ // is already bigger than the new value (which may happen with unordered
+ // packoffset annotations)
+ unsigned NewEndOffset =
+ ElemOffset + (ArrayCount - 1) * ArrayStride + ElemSize;
+ EndOffset = std::max<unsigned>(EndOffset, NewEndOffset);
+
+ // add the layout element and offset to the lists
+ Layout.push_back(ElemOffset);
+ LayoutElements.push_back(ElemLayoutTy);
+ Index++;
+ }
+ }
+
+ // set the size of the buffer
+ Layout[0] = EndOffset;
+
+ // create the layout struct type; anonymous struct have empty name but
+ // non-empty qualified name
+ const CXXRecordDecl *Decl = StructType->getAsCXXRecordDecl();
+ std::string Name =
+ Decl->getName().empty() ? "anon" : Decl->getQualifiedNameAsString();
+ llvm::StructType *StructTy =
+ llvm::StructType::create(LayoutElements, Name, true);
+
+ // create target layout type
+ llvm::Type *NewLayoutTy = this->getHLSLLayoutType(CGM, StructTy, Layout);
+ if (NewLayoutTy)
+ CGM.getHLSLRuntime().addHLSLBufferLayoutType(StructType, NewLayoutTy);
+ return NewLayoutTy;
+}
diff --git a/clang/lib/CodeGen/Targets/HLSLTargetInfo.h b/clang/lib/CodeGen/Targets/HLSLTargetInfo.h
new file mode 100644
index 0000000000000..279ce4fba3dad
--- /dev/null
+++ b/clang/lib/CodeGen/Targets/HLSLTargetInfo.h
@@ -0,0 +1,39 @@
+//===- HLSLTargetInfo.h ---------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "ABIInfoImpl.h"
+#include "TargetInfo.h"
+
+using namespace clang;
+using namespace clang::CodeGen;
+
+//===----------------------------------------------------------------------===//
+// Target codegen info implementation common between DirectX and SPIR/SPIR-V.
+//===----------------------------------------------------------------------===//
+
+class CommonHLSLTargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ CommonHLSLTargetCodeGenInfo(std::unique_ptr<ABIInfo> Info)
+ : TargetCodeGenInfo(std::move(Info)) {}
+
+ // Returns LLVM target extension type "dx.Layout" or "spv.Layout"
+ // for given structure type and layout data. The first number in
+ // the Layout is the size followed by offsets for each struct element.
+ virtual llvm::Type *getHLSLLayoutType(CodeGenModule &CGM,
+ llvm::StructType *LayoutStructTy,
+ SmallVector<unsigned> Layout) const {
+ return nullptr;
+ };
+
+protected:
+ // Creates a layout type for given struct with HLSL constant buffer layout
+ // taking into account Packoffsets, if provided.
+ virtual llvm::Type *createHLSLBufferLayoutType(
+ CodeGenModule &CGM, const clang::RecordType *StructType,
+ const SmallVector<unsigned> *Packoffsets = nullptr) const;
+};
diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp
index 5c75e985e953d..a1d8ffbf73284 100644
--- a/clang/lib/CodeGen/Targets/SPIR.cpp
+++ b/clang/lib/CodeGen/Targets/SPIR.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "ABIInfoImpl.h"
+#include "HLSLTargetInfo.h"
#include "TargetInfo.h"
using namespace clang;
@@ -38,12 +39,12 @@ class SPIRVABIInfo : public CommonSPIRABIInfo {
};
} // end anonymous namespace
namespace {
-class CommonSPIRTargetCodeGenInfo : public TargetCodeGenInfo {
+class CommonSPIRTargetCodeGenInfo : public CommonHLSLTargetCodeGenInfo {
public:
CommonSPIRTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
- : TargetCodeGenInfo(std::make_unique<CommonSPIRABIInfo>(CGT)) {}
+ : CommonHLSLTargetCodeGenInfo(std::make_unique<CommonSPIRABIInfo>(CGT)) {}
CommonSPIRTargetCodeGenInfo(std::unique_ptr<ABIInfo> ABIInfo)
- : TargetCodeGenInfo(std::move(ABIInfo)) {}
+ : CommonHLSLTargetCodeGenInfo(std::move(ABIInfo)) {}
LangAS getASTAllocaAddressSpace() const override {
return getLangASFromTargetAS(
@@ -52,7 +53,9 @@ class CommonSPIRTargetCodeGenInfo : public TargetCodeGenInfo {
unsigned getOpenCLKernelCallingConv() const override;
llvm::Type *getOpenCLType(CodeGenModule &CGM, const Type *T) const override;
- llvm::Type *getHLSLType(CodeGenModule &CGM, const Type *Ty) const override;
+ llvm::Type *getHLSLType(
+ CodeGenModule &CGM, const Type *Ty,
+ const SmallVector<unsigned> *Packoffsets = nullptr) const override;
llvm::Type *getSPIRVImageTypeFromHLSLResource(
const HLSLAttributedResourceType::Attributes &attributes,
llvm::Type *ElementType, llvm::LLVMContext &Ctx) const;
@@ -364,8 +367,9 @@ llvm::Type *CommonSPIRTargetCodeGenInfo::getOpenCLType(CodeGenModule &CGM,
return nullptr;
}
-llvm::Type *CommonSPIRTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM,
- const Type *Ty) const {
+llvm::Type *CommonSPIRTargetCodeGenInfo::getHLSLType(
+ CodeGenModule &CGM, const Type *Ty,
+ const SmallVector<unsigned> *Packoffsets) const {
auto *ResType = dyn_cast<HLSLAttributedResourceType>(Ty);
if (!ResType)
return nullptr;
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 1537a88731892..c011b46d11ac1 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -261,7 +261,7 @@ static void validatePackoffset(Sema &S, HLSLBufferDecl *BufDecl) {
IsValid = false;
}
}
- BufDecl->setHasPackoffset(IsValid);
+ BufDecl->setHasValidPackoffset(IsValid);
}
// Returns true if the array has a zero size = if any of the dimensions is 0
diff --git a/clang/test/CodeGenHLSL/cbuffer.hlsl b/clang/test/CodeGenHLSL/cbuffer.hlsl
index 9a3f632e859c7..38093c6dfacd7 100644
--- a/clang/test/CodeGenHLSL/cbuffer.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer.hlsl
@@ -1,14 +1,24 @@
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-compute \
// RUN: -fnative-half-type -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
-// CHECK: %struct.__cblayout_CBScalars = type <{ float, double, half, i64, i32, i16, i32, i64 }>
-// CHECK: %struct.__cblayout_CBVectors = type <{ <3 x float>, <3 x double>, <2 x half>, <3 x i64>, <4 x i32>, <3 x i16>, <3 x i64> }>
-// CHECK: %struct.__cblayout_CBArrays = type <{ [3 x float], [2 x <3 x double>], [2 x [2 x half]], [3 x i64], [2 x [3 x [4 x <4 x i32>]]], [1 x i16], [2 x i64], [4 x i32] }>
-// CHECK: %struct.__cblayout_CBStructs = type { %struct.A, %struct.B, %struct.C, [5 x %struct.A], %struct.__cblayout_D, half, %struct.B, <3 x i16> }
-// CHECK: %struct.A = type { <2 x float> }
-// CHECK: %struct.C = type { i32, %struct.A }
-// CHECK: %struct.__cblayout_D = type { [2 x [3 x %struct.B]] }
-// CHECK: %struct.B = type { %struct.A, <3 x i16> }
+// CHECK: %__cblayout_CBScalars = type <{ float, double, half, i64, i32, i16, i32, i64 }>
+// CHECK: %__cblayout_CBVectors = type <{ <3 x float>, <3 x double>, <2 x half>, <3 x i64>, <4 x i32>, <3 x i16>, <3 x i64> }>
+// CHECK: %__cblayout_CBArrays = type <{ [3 x float], [2 x <3 x double>], [2 x [2 x half]], [3 x i64], [2 x [3 x [4 x <4 x i32>]]], [1 x i16], [2 x i64], [4 x i32] }>
+// CHECK: %__cblayout_CBStructs = type <{ target("dx.Layout", %A, 8, 0), target("dx.Layout", %B, 14, 0, 8),
+// CHECK-SAME: target("dx.Layout", %C, 24, 0, 16), [5 x target("dx.Layout", %A, 8, 0)],
+// CHECK-SAME: target("dx.Layout", %__cblayout_D, 94, 0), half, <3 x i16> }>
+
+// CHECK: %A = type <{ <2 x float> }>
+// CHECK: %B = type <{ <2 x float>, <3 x i16> }>
+// CHECK: %C = type <{ i32, target("dx.Layout", %A, 8, 0) }>
+// CHECK: %__cblayout_D = type <{ [2 x [3 x target("dx.Layout", %B, 14, 0, 8)]] }>
+
+// CHECK: %__cblayout_CBMix = type <{ [2 x target("dx.Layout", %Test, 8, 0, 4)], float, [3 x [2 x <2 x float>]], float,
+// CHECK-SAME: target("dx.Layout", %anon, 4, 0), double, target("dx.Layout", %anon.0, 8, 0), float, <1 x double>, i16 }>
+
+// CHECK: %Test = type <{ float, float }>
+// CHECK: %anon = type <{ float }>
+// CHECK: %anon.0 = type <{ <2 x i32> }>
cbuffer CBScalars : register(b1, space5) {
float a1;
@@ -21,7 +31,8 @@ cbuffer CBScalars : register(b1, space5) {
int64_t a8;
}
-// CHECK: @CBScalars.cb = external constant target("dx.CBuffer", %struct.__cblayout_CBScalars)
+// CHECK: @CBScalars.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_CBScalars,
+// CHECK-SAME: 56, 0, 8, 16, 24, 32, 36, 40, 48))
// CHECK: @a1 = external addrspace(2) global float, align 4
// CHECK: @a2 = external addrspace(2) global double, align 8
// CHECK: @a3 = external addrspace(2) global half, align 2
@@ -39,10 +50,11 @@ cbuffer CBVectors {
int4 b5;
uint16_t3 b6;
int64_t3 b7;
- // FIXME: add s bool vectors after llvm-project/llvm#91639 is added
+ // FIXME: add a bool vectors after llvm-project/llvm#91639 is added
}
-// CHECK: @CBVectors.cb = external constant target("dx.CBuffer", %struct.__cblayout_CBVectors)
+// CHECK: @CBVectors.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_CBVectors,
+// CHECK-SAME: 136, 0, 16, 40, 48, 80, 96, 112))
// CHECK: @b1 = external addrspace(2) global <3 x float>, align 16
// CHECK: @b2 = external addrspace(2) global <3 x double>, align 32
// CHECK: @b3 = external addrspace(2) global <2 x half>, align 4
@@ -62,7 +74,8 @@ cbuffer CBArrays : register(b2) {
bool c8[4];
}
-// CHECK: @CBArrays.cb = external constant target("dx.CBuffer", %struct.__cblayout_CBArrays)
+// CHECK: @CBArrays.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_CBArrays,
+// CHECK-SAME: 708, 0, 48, 112, 176, 224, 608, 624, 656))
// CHECK: @c1 = external addrspace(2) global [3 x float], align 4
// CHECK: @c2 = external addrspace(2) global [2 x <3 x double>], align 32
// CHECK: @c3 = external addrspace(2) global [2 x [2 x half]], align 2
@@ -92,13 +105,15 @@ struct D {
Empty es;
};
-// CHECK: @CBStructs.cb = external constant target("dx.CBuffer", %struct.__cblayout_CBStructs)
-// CHECK: @a = external addrspace(2) global %struct.A, align 8
-// CHECK: @b = external addrspace(2) global %struct.B, align 8
-// CHECK: @c = external addrspace(2) global %struct.C, align 8
-// CHECK: @array_of_A = external addrspace(2) global [5 x %struct.A], align 8
-// CHECK: @d = external addrspace(2) global %struct.__cblayout_D, align 8
+// CHECK: @CBStructs.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_CBStructs,
+// CHECK-SAME: 246, 0, 16, 32, 64, 144, 238, 240))
+// CHECK: @a = external addrspace(2) global target("dx.Layout", %A, 8, 0), align 8
+// CHECK: @b = external addrspace(2) global target("dx.Layout", %B, 14, 0, 8), align 8
+// CHECK: @c = external addrspace(2) global target("dx.Layout", %C, 24, 0, 16), align 8
+// CHECK: @array_of_A = external addrspace(2) global [5 x target("dx.Layout", %A, 8, 0)], align 8
+// CHECK: @d = external addrspace(2) global target("dx.Layout", %__cblayout_D, 94, 0), align 8
// CHECK: @e = external addrspace(2) global half, align 2
+// CHECK: @f = external addrspace(2) global <3 x i16>, align 8
cbuffer CBStructs {
A a;
@@ -107,55 +122,56 @@ cbuffer CBStructs {
A array_of_A[5];
D d;
half e;
- B f;
- uint16_t3 g;
+ uint16_t3 f;
};
struct Test {
float a, b;
};
-// CHECK: @CBMix.cb = external constant target("dx.CBuffer", %struct.__cblayout_CBMix)
-// CHECK: @test = external addrspace(2) global [2 x %struct.Test], align 4
+// CHECK: @CBMix.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_CBMix,
+// CHECK-SAME: 170, 0, 24, 32, 120, 128, 136, 144, 152, 160, 168))
+// CHECK: @test = external addrspace(2) global [2 x target("dx.Layout", %Test, 8, 0, 4)], align 4
// CHECK: @f1 = external addrspace(2) global float, align 4
// CHECK: @f2 = external addrspace(2) global [3 x [2 x <2 x float>]], align 8
// CHECK: @f3 = external addrspace(2) global float, align 4
-// CHECK: @s = external addrspace(2) global %struct.anon, align 4
-// CHECK: @dd = external addrspace(2) global double, align 8
-// CHECK: @f4 = external addrspace(2) global float, align 4
-// CHECK: @dv = external addrspace(2) global <1 x double>, align 8
-// CHECK: @uv = external addrspace(2) global i16, align 2
+// CHECK: @f4 = external addrspace(2) global target("dx.Layout", %anon, 4, 0), align 4
+// CHECK: @f5 = external addrspace(2) global double, align 8
+// CHECK: @f6 = external addrspace(2) global target("dx.Layout", %anon.0, 8, 0), align 8
+// CHECK: @f7 = external addrspace(2) global float, align 4
+// CHECK: @f8 = external addrspace(2) global <1 x double>, align 8
+// CHECK: @f9 = external addrspace(2) global i16, align 2
cbuffer CBMix {
Test test[2];
float f1;
float2 f2[3][2];
float f3;
- struct { float c; } s;
- double dd;
- float f4;
- vector<double,1> dv;
- uint16_t uv;
+ struct { float c; } f4;
+ double f5;
+ struct { int2 i; } f6;
+ float f7;
+ vector<double,1> f8;
+ uint16_t f9;
};
-// CHECK: efine internal void @_init_resource_CBScalars.cb()
+// CHECK: define internal void @_init_resource_CBScalars.cb()
// CHECK-NEXT: entry:
-// CHECK-NEXT: %[[HANDLE1:.*]] = call target("dx.CBuffer", %struct.__cblayout_CBScalars)
-// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_s_struct.__cblayout_CBScalarsst(i32 5, i32 1, i32 1, i32 0, i1 false)
-// CHECK-NEXT: store target("dx.CBuffer", %struct.__cblayout_CBScalars) %[[HANDLE1]], ptr @CBScalars.cb, align 4
+// CHECK-NEXT: %[[HANDLE1:.*]] = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBScalars, 56, 0, 8, 16, 24, 32, 36, 40, 48))
+// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBScalarss_56_0_8_16_24_32_36_40_48tt(i32 5, i32 1, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBScalars, 56, 0, 8, 16, 24, 32, 36, 40, 48)) %CBScalars.cb_h, ptr @CBScalars.cb, align 4
// CHECK: define internal void @_init_resource_CBArrays.cb()
// CHECK-NEXT: entry:
-// CHECK-NEXT: %[[HANDLE2:.*]] = call target("dx.CBuffer", %struct.__cblayout_CBArrays)
-// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_s_struct.__cblayout_CBArraysst(i32 0, i32 2, i32 1, i32 0, i1 false)
-// CHECK-NEXT: store target("dx.CBuffer", %struct.__cblayout_CBArrays) %[[HANDLE2]], ptr @CBArrays.cb, align 4
+// CHECK-NEXT: %[[HANDLE2:.*]] = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBArrays, 708, 0, 48, 112, 176, 224, 608, 624, 656))
+// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBArrayss_708_0_48_112_176_224_608_624_656tt(i32 0, i32 2, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBArrays, 708, 0, 48, 112, 176, 224, 608, 624, 656)) %CBArrays.cb_h, ptr @CBArrays.cb, align 4
RWBuffer<float> Buf;
[numthreads(4,1,1)]
void main() {
- //Buf[0] = a1 + b1.z + c1[2] + a.f1.y;
- Buf[0] = a.f1.y;
+ Buf[0] = a1 + b1.z + c1[2] + a.f1.y + f1;
}
// CHECK: define internal void @_GLOBAL__sub_I_cbuffer.hlsl()
@@ -165,10 +181,6 @@ void main() {
// CHECK: !hlsl.cbs = !{![[CBSCALARS:[0-9]+]], ![[CBVECTORS:[0-9]+]], ![[CBARRAYS:[0-9]+]], ![[CBSTRUCTS:[0-9]+]], ![[CBMIX:[0-9]+]]}
-// CHECK: !hlsl.cblayouts = !{![[CBSCALARS_LAYOUT:[0-9]+]], ![[CBVECTORS_LAYOUT:[0-9]+]], ![[CBARRAYS_LAYOUT:[0-9]+]], ![[A_LAYOUT:[0-9]+]],
-// CHECK-SAME: ![[B_LAYOUT:[0-9]+]], ![[C_LAYOUT:[0-9]+]], ![[D_LAYOUT:[0-9]+]], ![[CBSTRUCTS_LAYOUT:[0-9]+]], ![[TEST_LAYOUT:[0-9]+]],
-// CHECK-SAME: ![[ANON_LAYOUT:[0-9]+]], ![[CBMIX_LAYOUT:[0-9]+]]}
-
// CHECK: ![[CBSCALARS]] = !{ptr @CBScalars.cb, ptr addrspace(2) @a1, ptr addrspace(2) @a2, ptr addrspace(2) @a3, ptr addrspace(2) @a4,
// CHECK-SAME: ptr addrspace(2) @a5, ptr addrspace(2) @a6, ptr addrspace(2) @a7, ptr addrspace(2) @a8}
@@ -179,21 +191,7 @@ void main() {
// CHECK-SAME: ptr addrspace(2) @c5, ptr addrspace(2) @c6, ptr addrspace(2) @c7, ptr addrspace(2) @c8}
// CHECK: ![[CBSTRUCTS]] = !{ptr @CBStructs.cb, ptr addrspace(2) @a, ptr addrspace(2) @b, ptr addrspace(2) @c, ptr addrspace(2) @array_of_A,
-// CHECK-SAME: ptr addrspace(2) @d, ptr addrspace(2) @e, ptr addrspace(2) @f, ptr addrspace(2) @g}
+// CHECK-SAME: ptr addrspace(2) @d, ptr addrspace(2) @e, ptr addrspace(2) @f}
// CHECK: ![[CBMIX]] = !{ptr @CBMix.cb, ptr addrspace(2) @test, ptr addrspace(2) @f1, ptr addrspace(2) @f2, ptr addrspace(2) @f3,
-// CHECK-SAME: ptr addrspace(2) @s, ptr addrspace(2) @dd, ptr addrspace(2) @f4, ptr addrspace(2) @dv, ptr addrspace(2) @uv}
-
-// CHECK: ![[CBSCALARS_LAYOUT]] = !{!"struct.__cblayout_CBScalars", i32 56, i32 0, i32 8, i32 16, i32 24, i32 32, i32 36, i32 40, i32 48}
-// CHECK: ![[CBVECTORS_LAYOUT]] = !{!"struct.__cblayout_CBVectors", i32 136, i32 0, i32 16, i32 40, i32 48, i32 80, i32 96, i32 112}
-
-// CHECK: ![[CBARRAYS_LAYOUT]] = !{!"struct.__cblayout_CBArrays", i32 708, i32 0, i32 48, i32 112, i32 176, i32 224, i32 608, i32 624, i32 656}
-
-// CHECK: ![[A_LAYOUT]] = !{!"struct.A", i32 8, i32 0}
-// CHECK: ![[B_LAYOUT]] = !{!"struct.B", i32 14, i32 0, i32 8}
-// CHECK: ![[C_LAYOUT]] = !{!"struct.C", i32 24, i32 0, i32 16}
-// CHECK: ![[D_LAYOUT]] = !{!"struct.__cblayout_D", i32 94, i32 0}
-// CHECK: ![[CBSTRUCTS_LAYOUT]] = !{!"struct.__cblayout_CBStructs", i32 262, i32 0, i32 16, i32 32, i32 64, i32 144, i32 238, i32 240, i32 256}
-// CHECK: ![[TEST_LAYOUT]] = !{!"struct.Test", i32 8, i32 0, i32 4}
-// CHECK: ![[ANON_LAYOUT]] = !{!"struct.anon", i32 4, i32 0}
-// CHECK: ![[CBMIX_LAYOUT]] = !{!"struct.__cblayout_CBMix", i32 162, i32 0, i32 24, i32 32, i32 120, i32 128, i32 136, i32 144, i32 152, i32 160}
+// CHECK-SAME: ptr addrspace(2) @f4, ptr addrspace(2) @f5, ptr addrspace(2) @f6, ptr addrspace(2) @f7, ptr addrspace(2) @f8, ptr addrspace(2) @f9}
diff --git a/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl b/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl
index aa5659af414ef..393ca3825c638 100644
--- a/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl
@@ -4,20 +4,20 @@
// Make sure cbuffer inside namespace works.
-// CHECK: %"struct.n0::n1::__cblayout_A" = type { float }
-// CHECK: %"struct.n0::__cblayout_B" = type { float }
-// CHECK: %"struct.n0::n2::__cblayout_C" = type { float, %"struct.n0::Foo" }
-// CHECK: %"struct.n0::Foo" = type { float }
+// CHECK: %"n0::n1::__cblayout_A" = type <{ float }>
+// CHECK: %"n0::__cblayout_B" = type <{ float }>
+// CHECK: %"n0::n2::__cblayout_C" = type <{ float, target("dx.Layout", %"n0::Foo", 4, 0) }>
+// CHECK: %"n0::Foo" = type <{ float }>
-// CHECK: @A.cb = external constant target("dx.CBuffer", %"struct.n0::n1::__cblayout_A")
+// CHECK: @A.cb = external constant target("dx.CBuffer", target("dx.Layout", %"n0::n1::__cblayout_A", 4, 0))
// CHECK: @_ZN2n02n11aE = external addrspace(2) global float, align 4
-// CHECK: @B.cb = external constant target("dx.CBuffer", %"struct.n0::__cblayout_B")
+// CHECK: @B.cb = external constant target("dx.CBuffer", target("dx.Layout", %"n0::__cblayout_B", 4, 0))
// CHECK: @_ZN2n01aE = external addrspace(2) global float, align 4
-// CHECK: @C.cb = external constant target("dx.CBuffer", %"struct.n0::n2::__cblayout_C")
+// CHECK: @C.cb = external constant target("dx.CBuffer", target("dx.Layout", %"n0::n2::__cblayout_C", 20, 0, 16))
// CHECK: @_ZN2n02n21aE = external addrspace(2) global float, align 4
-// CHECK: @_ZN2n02n21bE = external addrspace(2) global %"struct.n0::Foo", align 4
+// CHECK: external addrspace(2) global target("dx.Layout", %"n0::Foo", 4, 0), align 4
namespace n0 {
struct Foo {
@@ -51,13 +51,6 @@ float foo() {
void main() {}
// CHECK: !hlsl.cbs = !{![[A:[0-9]+]], ![[B:[0-9]+]], ![[C:[0-9]+]]}
-// CHECK: !hlsl.cblayouts = !{![[A_LAYOUT:[0-9]+]], ![[B_LAYOUT:[0-9]+]], ![[FOO_LAYOUT:[0-9]+]], ![[C_LAYOUT:[0-9]+]]}
-
// CHECK: [[A]] = !{ptr @A.cb, ptr addrspace(2) @_ZN2n02n11aE}
// CHECK: [[B]] = !{ptr @B.cb, ptr addrspace(2) @_ZN2n01aE}
// CHECK: [[C]] = !{ptr @C.cb, ptr addrspace(2) @_ZN2n02n21aE, ptr addrspace(2) @_ZN2n02n21bE}
-
-// CHECK: ![[A_LAYOUT]] = !{!"struct.n0::n1::__cblayout_A", i32 4, i32 0}
-// CHECK: ![[B_LAYOUT]] = !{!"struct.n0::__cblayout_B", i32 4, i32 0}
-// CHECK: ![[FOO_LAYOUT]] = !{!"struct.n0::Foo", i32 4, i32 0}
-// CHECK: ![[C_LAYOUT]] = !{!"struct.n0::n2::__cblayout_C", i32 20, i32 0, i32 16}
diff --git a/clang/test/CodeGenHLSL/cbuffer_and_namespaces.ll b/clang/test/CodeGenHLSL/cbuffer_and_namespaces.ll
new file mode 100644
index 0000000000000..faa1931222ade
--- /dev/null
+++ b/clang/test/CodeGenHLSL/cbuffer_and_namespaces.ll
@@ -0,0 +1,49 @@
+; ModuleID = 'C:\llvm-project\clang\test\CodeGenHLSL\cbuffer_and_namespaces.hlsl'
+source_filename = "C:\\llvm-project\\clang\\test\\CodeGenHLSL\\cbuffer_and_namespaces.hlsl"
+target datalayout = "e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64"
+target triple = "dxilv1.3-pc-shadermodel6.3-library"
+
+%__cblayout_A = type <{ float }>
+%__cblayout_B = type <{ float }>
+%__cblayout_C = type <{ float, target("dx.Layout", %Foo, 4, 0) }>
+%Foo = type <{ float }>
+
+ at A.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_A, 4, 0))
+ at _ZN2n02n11aE = external addrspace(2) global float, align 4
+ at B.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_B, 4, 0))
+ at _ZN2n01aE = external addrspace(2) global float, align 4
+ at C.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_C, 20, 0, 16))
+ at _ZN2n02n21aE = external addrspace(2) global float, align 4
+ at _ZN2n02n21bE = external addrspace(2) global target("dx.Layout", %Foo, 4, 0), align 4
+
+; Function Attrs: alwaysinline convergent mustprogress norecurse nounwind
+define noundef nofpclass(nan inf) float @_Z3foov() #0 {
+entry:
+ %0 = load float, ptr addrspace(2) @_ZN2n02n11aE, align 4
+ %1 = load float, ptr addrspace(2) @_ZN2n01aE, align 4
+ %add = fadd reassoc nnan ninf nsz arcp afn float %0, %1
+ %2 = load float, ptr addrspace(2) @_ZN2n02n21aE, align 4
+ %add1 = fadd reassoc nnan ninf nsz arcp afn float %add, %2
+ ret float %add1
+}
+
+; Function Attrs: alwaysinline convergent mustprogress norecurse nounwind
+define void @_Z4mainv() #0 {
+entry:
+ ret void
+}
+
+attributes #0 = { alwaysinline convergent mustprogress norecurse nounwind "approx-func-fp-math"="true" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
+
+!hlsl.cbs = !{!0, !1, !2}
+!llvm.module.flags = !{!3, !4}
+!dx.valver = !{!5}
+!llvm.ident = !{!6}
+
+!0 = !{ptr @A.cb, ptr addrspace(2) @_ZN2n02n11aE}
+!1 = !{ptr @B.cb, ptr addrspace(2) @_ZN2n01aE}
+!2 = !{ptr @C.cb, ptr addrspace(2) @_ZN2n02n21aE, ptr addrspace(2) @_ZN2n02n21bE}
+!3 = !{i32 1, !"wchar_size", i32 4}
+!4 = !{i32 4, !"dx.disable_optimizations", i32 1}
+!5 = !{i32 1, i32 8}
+!6 = !{!"clang version 20.0.0git (C:/llvm-project/clang a8cdd4536867465e3d6e2b4ad8c49b27ee94dec8)"}
diff --git a/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl b/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
index f5b5cba6197b3..870593986a976 100644
--- a/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
@@ -2,9 +2,9 @@
// RUN: dxil-pc-shadermodel6.3-compute %s \
// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-// CHECK: %struct.__cblayout_CB = type <{ float, double, <2 x i32> }>
+// CHECK: %__cblayout_CB = type <{ float, double, <2 x i32> }>
-// CHECK: @CB.cb = external constant target("dx.CBuffer", %struct.__cblayout_CB)
+// CHECK: @CB.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 176, 16, 168, 88))
// CHECK: @a = external addrspace(2) global float, align 4
// CHECK: @b = external addrspace(2) global double, align 8
// CHECK: @c = external addrspace(2) global <2 x i32>, align 8
@@ -17,7 +17,8 @@ cbuffer CB : register(b1, space3) {
// CHECK: define internal void @_init_resource_CB.cb()
// CHECK-NEXT: entry:
-// CHECK-NEXT: %CB.cb_h = call target("dx.CBuffer", %struct.__cblayout_CB) @llvm.dx.resource.handlefrombinding.tdx.CBuffer_s_struct.__cblayout_CBst(i32 3, i32 1, i32 1, i32 0, i1 false)
+// CHECK-NEXT: %CB.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 176, 16, 168, 88))
+// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBs_176_16_168_88tt(i32 3, i32 1, i32 1, i32 0, i1 false)
float foo() {
// CHECK: load float, ptr addrspace(2) @a, align 4
@@ -34,7 +35,4 @@ void main() {
}
// CHECK: !hlsl.cbs = !{![[CB:[0-9]+]]}
-// CHECK: !hlsl.cblayouts = !{![[CB_LAYOUT:[0-9]+]]}
-
// CHECK: ![[CB]] = !{ptr @CB.cb, ptr addrspace(2) @a, ptr addrspace(2) @b, ptr addrspace(2) @c}
-// CHECK: ![[CB_LAYOUT]] = !{!"struct.__cblayout_CB", i32 176, i32 16, i32 168, i32 88}
diff --git a/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl b/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl
index 8994640d5b311..99f40d8fc93d7 100644
--- a/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl
@@ -1,9 +1,9 @@
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library %s \
// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-// CHECK: %struct.__cblayout_A = type { float }
+// CHECK: %__cblayout_A = type <{ float }>
-// CHECK: @A.cb = external constant target("dx.CBuffer", %struct.__cblayout_A)
+// CHECK: @A.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_A, 4, 0))
// CHECK: @a = external addrspace(2) global float, align 4
// CHECK-DAG: @_ZL1b = internal global float 3.000000e+00, align 4
// CHECK-NOT: @B.cb
@@ -26,7 +26,4 @@ extern float bar() {
}
// CHECK: !hlsl.cbs = !{![[CB:[0-9]+]]}
-// CHECK: !hlsl.cblayouts = !{![[CB_LAYOUT:[0-9]+]]}
-
// CHECK: ![[CB]] = !{ptr @A.cb, ptr addrspace(2) @a}
-// CHECK: ![[CB_LAYOUT]] = !{!"struct.__cblayout_A", i32 4, i32 0}
>From 62094b2c5c754d4d077cbd2925950914e7c1c4af Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Fri, 14 Feb 2025 18:31:31 -0800
Subject: [PATCH 10/13] code review feedback - add named constant, rename
function, remove file
---
clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp | 11 +++--
.../CodeGenHLSL/cbuffer_and_namespaces.ll | 49 -------------------
2 files changed, 6 insertions(+), 54 deletions(-)
delete mode 100644 clang/test/CodeGenHLSL/cbuffer_and_namespaces.ll
diff --git a/clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp b/clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp
index e0e7f6daddcfa..e634e47853d35 100644
--- a/clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp
+++ b/clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp
@@ -31,7 +31,7 @@ createArrayWithNewElementType(CodeGenModule &CGM,
}
// Returns the size of a scalar or vector in bytes/
-static unsigned getScalarOrVectorSize(llvm::Type *Ty) {
+static unsigned getScalarOrVectorSizeInBytes(llvm::Type *Ty) {
assert(Ty->isVectorTy() || Ty->isIntegerTy() || Ty->isFloatingPointTy());
if (Ty->isVectorTy()) {
llvm::FixedVectorType *FVT = cast<llvm::FixedVectorType>(Ty);
@@ -65,6 +65,7 @@ llvm::Type *CommonHLSLTargetCodeGenInfo::createHLSLBufferLayoutType(
SmallVector<llvm::Type *> LayoutElements;
unsigned Index = 0; // packoffset index
unsigned EndOffset = 0;
+ const unsigned BufferRowAlign = 16U;
// reserve first spot in the layout vector for buffer size
Layout.push_back(0);
@@ -94,7 +95,7 @@ llvm::Type *CommonHLSLTargetCodeGenInfo::createHLSLBufferLayoutType(
unsigned ElemOffset = 0;
unsigned ArrayCount = 1;
unsigned ArrayStride = 0;
- unsigned NextRowOffset = llvm::alignTo(EndOffset, 16U);
+ unsigned NextRowOffset = llvm::alignTo(EndOffset, BufferRowAlign);
llvm::Type *ElemLayoutTy = nullptr;
QualType FieldTy = FD->getType();
@@ -120,11 +121,11 @@ llvm::Type *CommonHLSLTargetCodeGenInfo::createHLSLBufferLayoutType(
CGM, cast<ConstantArrayType>(FieldTy.getTypePtr()), NewTy);
} else {
// Array of vectors or scalars
- ElemSize =
- getScalarOrVectorSize(CGM.getTypes().ConvertTypeForMem(Ty));
+ ElemSize = getScalarOrVectorSizeInBytes(
+ CGM.getTypes().ConvertTypeForMem(Ty));
ElemLayoutTy = CGM.getTypes().ConvertTypeForMem(FieldTy);
}
- ArrayStride = llvm::alignTo(ElemSize, 16U);
+ ArrayStride = llvm::alignTo(ElemSize, BufferRowAlign);
ElemOffset =
Packoffsets != nullptr ? (*Packoffsets)[Index] : NextRowOffset;
diff --git a/clang/test/CodeGenHLSL/cbuffer_and_namespaces.ll b/clang/test/CodeGenHLSL/cbuffer_and_namespaces.ll
deleted file mode 100644
index faa1931222ade..0000000000000
--- a/clang/test/CodeGenHLSL/cbuffer_and_namespaces.ll
+++ /dev/null
@@ -1,49 +0,0 @@
-; ModuleID = 'C:\llvm-project\clang\test\CodeGenHLSL\cbuffer_and_namespaces.hlsl'
-source_filename = "C:\\llvm-project\\clang\\test\\CodeGenHLSL\\cbuffer_and_namespaces.hlsl"
-target datalayout = "e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64"
-target triple = "dxilv1.3-pc-shadermodel6.3-library"
-
-%__cblayout_A = type <{ float }>
-%__cblayout_B = type <{ float }>
-%__cblayout_C = type <{ float, target("dx.Layout", %Foo, 4, 0) }>
-%Foo = type <{ float }>
-
- at A.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_A, 4, 0))
- at _ZN2n02n11aE = external addrspace(2) global float, align 4
- at B.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_B, 4, 0))
- at _ZN2n01aE = external addrspace(2) global float, align 4
- at C.cb = external constant target("dx.CBuffer", target("dx.Layout", %__cblayout_C, 20, 0, 16))
- at _ZN2n02n21aE = external addrspace(2) global float, align 4
- at _ZN2n02n21bE = external addrspace(2) global target("dx.Layout", %Foo, 4, 0), align 4
-
-; Function Attrs: alwaysinline convergent mustprogress norecurse nounwind
-define noundef nofpclass(nan inf) float @_Z3foov() #0 {
-entry:
- %0 = load float, ptr addrspace(2) @_ZN2n02n11aE, align 4
- %1 = load float, ptr addrspace(2) @_ZN2n01aE, align 4
- %add = fadd reassoc nnan ninf nsz arcp afn float %0, %1
- %2 = load float, ptr addrspace(2) @_ZN2n02n21aE, align 4
- %add1 = fadd reassoc nnan ninf nsz arcp afn float %add, %2
- ret float %add1
-}
-
-; Function Attrs: alwaysinline convergent mustprogress norecurse nounwind
-define void @_Z4mainv() #0 {
-entry:
- ret void
-}
-
-attributes #0 = { alwaysinline convergent mustprogress norecurse nounwind "approx-func-fp-math"="true" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
-
-!hlsl.cbs = !{!0, !1, !2}
-!llvm.module.flags = !{!3, !4}
-!dx.valver = !{!5}
-!llvm.ident = !{!6}
-
-!0 = !{ptr @A.cb, ptr addrspace(2) @_ZN2n02n11aE}
-!1 = !{ptr @B.cb, ptr addrspace(2) @_ZN2n01aE}
-!2 = !{ptr @C.cb, ptr addrspace(2) @_ZN2n02n21aE, ptr addrspace(2) @_ZN2n02n21bE}
-!3 = !{i32 1, !"wchar_size", i32 4}
-!4 = !{i32 4, !"dx.disable_optimizations", i32 1}
-!5 = !{i32 1, i32 8}
-!6 = !{!"clang version 20.0.0git (C:/llvm-project/clang a8cdd4536867465e3d6e2b4ad8c49b27ee94dec8)"}
>From eaeaf2a76d78a1070a733e0692654d059c41a4ea Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Wed, 19 Feb 2025 11:13:08 -0800
Subject: [PATCH 11/13] code review feedback - minor changes
---
clang/lib/CodeGen/CGHLSLRuntime.cpp | 20 +++++++++-----------
1 file changed, 9 insertions(+), 11 deletions(-)
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 31da7432b3145..3f1ccce9c6271 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -103,12 +103,8 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
// get the layout struct from constant buffer target type
llvm::Type *BufType = BufGV->getValueType();
- assert(isa<llvm::TargetExtType>(BufType) &&
- "expected target type for HLSL buffer resource");
llvm::Type *BufLayoutType =
cast<llvm::TargetExtType>(BufType)->getTypeParameter(0);
- assert(isa<llvm::TargetExtType>(BufLayoutType) &&
- "expected target type for buffer layout struct");
llvm::StructType *LayoutStruct = cast<llvm::StructType>(
cast<llvm::TargetExtType>(BufLayoutType)->getTypeParameter(0));
@@ -139,9 +135,13 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
// Emit static and groupshared variables and resource classes inside
// cbuffer as regular globals
CGM.EmitGlobal(VD);
+ } else {
+ // Anything else that is not in the hlsl_constant address space must be
+ // an empty struct or a zero-sized array and can be ignored
+ assert(BufDecl->getASTContext().getTypeSize(VDTy) == 0 &&
+ "constant buffer decl with non-zero sized type outside of "
+ "hlsl_constant address space");
}
- // Anything else that is not in the hlsl_constant address space must be
- // an empty struct or a zero-sized array and can be ignored
continue;
}
@@ -149,10 +149,8 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
"number of elements in layout struct does not match");
llvm::Type *LayoutType = *ElemIt++;
- // there might be resources inside the used defined structs
- if (VDTy->isStructureType() && VDTy->isHLSLIntangibleType())
- // FIXME: handle resources in cbuffer structs
- llvm_unreachable("resources in cbuffer are not supported yet");
+ // FIXME: handle resources inside user defined structs
+ // (llvm/wg-hlsl#175)
// create global variable for the constant and to metadata list
GlobalVariable *ElemGV =
@@ -161,7 +159,6 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
}
assert(ElemIt == LayoutStruct->element_end() &&
"number of elements in layout struct does not match");
- // set the size of the buffer
// add buffer metadata to the module
CGM.getModule()
@@ -235,6 +232,7 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
const HLSLResourceBindingAttr *RBA =
BufDecl->getAttr<HLSLResourceBindingAttr>();
// FIXME: handle implicit binding if no binding attribute is found
+ // (llvm/llvm-project#110722)
if (RBA)
createResourceInitFn(CGM, BufGV, RBA->getSlotNumber(),
RBA->getSpaceNumber());
>From d3c887280943d8d3ac5184088bcc39f8a5e42dce Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Wed, 19 Feb 2025 14:14:13 -0800
Subject: [PATCH 12/13] code review feedback - move layout calculations into a
separate builder class instead of target info
---
clang/lib/CodeGen/CGHLSLRuntime.cpp | 4 +-
clang/lib/CodeGen/CGHLSLRuntime.h | 7 +-
clang/lib/CodeGen/CMakeLists.txt | 20 +-
clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp | 229 ++++++++++++++++++
clang/lib/CodeGen/HLSLBufferLayoutBuilder.h | 48 ++++
clang/lib/CodeGen/Targets/DirectX.cpp | 22 +-
clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp | 202 ---------------
clang/lib/CodeGen/Targets/HLSLTargetInfo.h | 39 ---
clang/lib/CodeGen/Targets/SPIR.cpp | 7 +-
9 files changed, 303 insertions(+), 275 deletions(-)
create mode 100644 clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp
create mode 100644 clang/lib/CodeGen/HLSLBufferLayoutBuilder.h
delete mode 100644 clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp
delete mode 100644 clang/lib/CodeGen/Targets/HLSLTargetInfo.h
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index b9ded3d3700db..4aa5a7ead14a2 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -240,7 +240,7 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
RBA->getSpaceNumber());
}
-llvm::Type *
+llvm::TargetExtType *
CGHLSLRuntime::getHLSLBufferLayoutType(const RecordType *StructType) {
const auto Entry = LayoutTypes.find(StructType);
if (Entry != LayoutTypes.end())
@@ -249,7 +249,7 @@ CGHLSLRuntime::getHLSLBufferLayoutType(const RecordType *StructType) {
}
void CGHLSLRuntime::addHLSLBufferLayoutType(const RecordType *StructType,
- llvm::Type *LayoutTy) {
+ llvm::TargetExtType *LayoutTy) {
assert(getHLSLBufferLayoutType(StructType) == nullptr &&
"layout type for this struct already exist");
LayoutTypes[StructType] = LayoutTy;
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 0f346410eccd4..a9da42324a038 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -162,9 +162,10 @@ class CGHLSLRuntime {
llvm::Instruction *getConvergenceToken(llvm::BasicBlock &BB);
- llvm::Type *getHLSLBufferLayoutType(const RecordType *LayoutStructTy);
+ llvm::TargetExtType *
+ getHLSLBufferLayoutType(const RecordType *LayoutStructTy);
void addHLSLBufferLayoutType(const RecordType *LayoutStructTy,
- llvm::Type *LayoutTy);
+ llvm::TargetExtType *LayoutTy);
void emitInitListOpaqueValues(CodeGenFunction &CGF, InitListExpr *E);
private:
@@ -177,7 +178,7 @@ class CGHLSLRuntime {
llvm::GlobalVariable *BufGV);
llvm::Triple::ArchType getArch();
- llvm::DenseMap<const clang::RecordType *, llvm::Type *> LayoutTypes;
+ llvm::DenseMap<const clang::RecordType *, llvm::TargetExtType *> LayoutTypes;
};
} // namespace CodeGen
diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt
index 1a6b25883d9c8..0f3a106cea1b9 100644
--- a/clang/lib/CodeGen/CMakeLists.txt
+++ b/clang/lib/CodeGen/CMakeLists.txt
@@ -31,25 +31,26 @@ set(LLVM_LINK_COMPONENTS
Target
TargetParser
TransformUtils
- )
+)
# Workaround for MSVC ARM64 performance regression:
# https://developercommunity.visualstudio.com/t/Compiling-a-specific-code-for-ARM64-with/10444970
# Since /O1 and /O2 represent a set of optimizations,
# our goal is to disable the /Og flag while retaining the other optimizations from the /O1|/O2 set
if(MSVC AND NOT CMAKE_CXX_COMPILER_ID MATCHES Clang
- AND MSVC_VERSION VERSION_GREATER_EQUAL 1932
- AND MSVC_VERSION VERSION_LESS 1939
- AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64")
-
+ AND MSVC_VERSION VERSION_GREATER_EQUAL 1932
+ AND MSVC_VERSION VERSION_LESS 1939
+ AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64")
string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE)
string(REGEX MATCHALL "/[Oo][12]" opt_flags "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${uppercase_CMAKE_BUILD_TYPE}}")
- if (opt_flags)
+
+ if(opt_flags)
if(opt_flags MATCHES "1$")
set(opt_flags "/Od;/Os;/Oy;/Ob2;/GF;/Gy")
- elseif (opt_flags MATCHES "2$")
+ elseif(opt_flags MATCHES "2$")
set(opt_flags "/Od;/Oi;/Ot;/Oy;/Ob2;/GF;/Gy")
endif()
+
set_source_files_properties(CGBuiltin.cpp PROPERTIES COMPILE_OPTIONS "${opt_flags}")
endif()
endif()
@@ -106,6 +107,7 @@ add_clang_library(clangCodeGen
ConstantInitBuilder.cpp
CoverageMappingGen.cpp
ItaniumCXXABI.cpp
+ HLSLBufferLayoutBuilder.cpp
LinkInModulesPass.cpp
MacroPPCallbacks.cpp
MicrosoftCXXABI.cpp
@@ -124,7 +126,6 @@ add_clang_library(clangCodeGen
Targets/CSKY.cpp
Targets/DirectX.cpp
Targets/Hexagon.cpp
- Targets/HLSLTargetInfo.cpp
Targets/Lanai.cpp
Targets/LoongArch.cpp
Targets/M68k.cpp
@@ -148,6 +149,7 @@ add_clang_library(clangCodeGen
vt_gen
intrinsics_gen
ClangDriverOptions
+
# These generated headers are included transitively.
ARMTargetParserTableGen
AArch64TargetParserTableGen
@@ -159,4 +161,4 @@ add_clang_library(clangCodeGen
clangFrontend
clangLex
clangSerialization
- )
+)
diff --git a/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp b/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp
new file mode 100644
index 0000000000000..1ae00023ab2bc
--- /dev/null
+++ b/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp
@@ -0,0 +1,229 @@
+//===- HLSLBufferLayoutBuilder.cpp ----------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "HLSLBufferLayoutBuilder.h"
+#include "CGHLSLRuntime.h"
+#include "CodeGenModule.h"
+#include "clang/AST/Type.h"
+
+//===----------------------------------------------------------------------===//
+// Implementation of constant buffer layout common between DirectX and
+// SPIR/SPIR-V.
+//===----------------------------------------------------------------------===//
+
+using namespace clang;
+using namespace clang::CodeGen;
+
+namespace {
+
+// Creates a new array type with the same dimentions but with the new
+// element type.
+static llvm::Type *
+createArrayWithNewElementType(CodeGenModule &CGM,
+ const ConstantArrayType *ArrayType,
+ llvm::Type *NewElemType) {
+ const clang::Type *ArrayElemType = ArrayType->getArrayElementTypeNoTypeQual();
+ if (ArrayElemType->isConstantArrayType())
+ NewElemType = createArrayWithNewElementType(
+ CGM, cast<const ConstantArrayType>(ArrayElemType), NewElemType);
+ return llvm::ArrayType::get(NewElemType, ArrayType->getSExtSize());
+}
+
+// Returns the size of a scalar or vector in bytes
+static unsigned getScalarOrVectorSizeInBytes(llvm::Type *Ty) {
+ assert(Ty->isVectorTy() || Ty->isIntegerTy() || Ty->isFloatingPointTy());
+ if (Ty->isVectorTy()) {
+ llvm::FixedVectorType *FVT = cast<llvm::FixedVectorType>(Ty);
+ return FVT->getNumElements() *
+ (FVT->getElementType()->getScalarSizeInBits() / 8);
+ }
+ return Ty->getScalarSizeInBits() / 8;
+}
+
+} // namespace
+
+namespace clang {
+namespace CodeGen {
+
+// Creates a layout type for given struct with HLSL constant buffer layout
+// taking into account Packoffsets, if provided.
+// Previously created layout types are cached by CGHLSLRuntime.
+//
+// The function iterates over all fields of the StructType (including base
+// classes) and calls layoutField to converts each field to its corresponding
+// LLVM type and to calculate its HLSL constant buffer layout. Any embedded
+// structs (or arrays of structs) are converted to target layout types as well.
+llvm::TargetExtType *HLSLBufferLayoutBuilder::createLayoutType(
+ const RecordType *StructType,
+ const llvm::SmallVector<unsigned> *Packoffsets) {
+
+ // check if we already have the layout type for this struct
+ if (llvm::TargetExtType *Ty =
+ CGM.getHLSLRuntime().getHLSLBufferLayoutType(StructType))
+ return Ty;
+
+ SmallVector<unsigned> Layout;
+ SmallVector<llvm::Type *> LayoutElements;
+ unsigned Index = 0; // packoffset index
+ unsigned EndOffset = 0;
+
+ // reserve first spot in the layout vector for buffer size
+ Layout.push_back(0);
+
+ // iterate over all fields of the record, including fields on base classes
+ llvm::SmallVector<const RecordType *> RecordTypes;
+ RecordTypes.push_back(StructType);
+ while (RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
+ CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl();
+ assert(D->getNumBases() == 1 &&
+ "HLSL doesn't support multiple inheritance");
+ RecordTypes.push_back(D->bases_begin()->getType()->getAs<RecordType>());
+ }
+ while (!RecordTypes.empty()) {
+ const RecordType *RT = RecordTypes.back();
+ RecordTypes.pop_back();
+
+ for (const auto *FD : RT->getDecl()->fields()) {
+ assert(!Packoffsets || Index < Packoffsets->size() &&
+ "number of elements in layout struct does not "
+ "match number of packoffset annotations");
+
+ if (!layoutField(FD, EndOffset, Layout, LayoutElements,
+ Packoffsets ? (*Packoffsets)[Index] : -1))
+ return nullptr;
+ Index++;
+ }
+ }
+
+ // set the size of the buffer
+ Layout[0] = EndOffset;
+
+ // create the layout struct type; anonymous struct have empty name but
+ // non-empty qualified name
+ const CXXRecordDecl *Decl = StructType->getAsCXXRecordDecl();
+ std::string Name =
+ Decl->getName().empty() ? "anon" : Decl->getQualifiedNameAsString();
+ llvm::StructType *StructTy =
+ llvm::StructType::create(LayoutElements, Name, true);
+
+ // create target layout type
+ llvm::TargetExtType *NewLayoutTy = llvm::TargetExtType::get(
+ CGM.getLLVMContext(), LayoutTypeName, {StructTy}, Layout);
+ if (NewLayoutTy)
+ CGM.getHLSLRuntime().addHLSLBufferLayoutType(StructType, NewLayoutTy);
+ return NewLayoutTy;
+}
+
+// The function converts a single field of HLSL Buffer to its corresponding
+// LLVM type and calculates it's layout. Any embedded structs (or
+// arrays of structs) are converted to target layout types as well.
+// The converted type is appended to the LayoutElements list, the element
+// offset is added to the Layout list and the EndOffset updated to the offset
+// just after the lay-ed out element (which is basically the size of the
+// buffer).
+// Returns true if the conversion was successful.
+// The packoffset parameter contains the field's layout offset provided by the
+// user or -1 if there was no packoffset (or register(cX)) annotation.
+bool HLSLBufferLayoutBuilder::layoutField(
+ const FieldDecl *FD, unsigned &EndOffset, SmallVector<unsigned> &Layout,
+ SmallVector<llvm::Type *> &LayoutElements, int Packoffset) {
+
+ // Size of element; for arrays this is a size of a single element in the
+ // array. Total array size of calculated as (ArrayCount-1) * ArrayStride +
+ // ElemSize.
+ unsigned ElemSize = 0;
+ unsigned ElemOffset = 0;
+ unsigned ArrayCount = 1;
+ unsigned ArrayStride = 0;
+
+ const unsigned BufferRowAlign = 16U;
+ unsigned NextRowOffset = llvm::alignTo(EndOffset, BufferRowAlign);
+
+ llvm::Type *ElemLayoutTy = nullptr;
+ QualType FieldTy = FD->getType();
+
+ if (FieldTy->isConstantArrayType()) {
+ // Unwrap array to find the element type and get combined array size.
+ QualType Ty = FieldTy;
+ while (Ty->isConstantArrayType()) {
+ const ConstantArrayType *ArrayTy = cast<ConstantArrayType>(Ty);
+ ArrayCount *= ArrayTy->getSExtSize();
+ Ty = ArrayTy->getElementType();
+ }
+ // For array of structures, create a new array with a layout type
+ // instead of the structure type.
+ if (Ty->isStructureType()) {
+ llvm::Type *NewTy =
+ cast<llvm::TargetExtType>(createLayoutType(Ty->getAsStructureType()));
+ if (!NewTy)
+ return false;
+ assert(isa<llvm::TargetExtType>(NewTy) && "expected target type");
+ ElemSize = cast<llvm::TargetExtType>(NewTy)->getIntParameter(0);
+ ElemLayoutTy = createArrayWithNewElementType(
+ CGM, cast<ConstantArrayType>(FieldTy.getTypePtr()), NewTy);
+ } else {
+ // Array of vectors or scalars
+ ElemSize =
+ getScalarOrVectorSizeInBytes(CGM.getTypes().ConvertTypeForMem(Ty));
+ ElemLayoutTy = CGM.getTypes().ConvertTypeForMem(FieldTy);
+ }
+ ArrayStride = llvm::alignTo(ElemSize, BufferRowAlign);
+ ElemOffset = (Packoffset != -1) ? Packoffset : NextRowOffset;
+
+ } else if (FieldTy->isStructureType()) {
+ // Create a layout type for the structure
+ ElemLayoutTy = createLayoutType(FieldTy->getAsStructureType());
+ if (!ElemLayoutTy)
+ return false;
+ assert(isa<llvm::TargetExtType>(ElemLayoutTy) && "expected target type");
+ ElemSize = cast<llvm::TargetExtType>(ElemLayoutTy)->getIntParameter(0);
+ ElemOffset = (Packoffset != -1) ? Packoffset : NextRowOffset;
+
+ } else {
+ // scalar or vector - find element size and alignment
+ unsigned Align = 0;
+ ElemLayoutTy = CGM.getTypes().ConvertTypeForMem(FieldTy);
+ if (ElemLayoutTy->isVectorTy()) {
+ // align vectors by sub element size
+ const llvm::FixedVectorType *FVT =
+ cast<llvm::FixedVectorType>(ElemLayoutTy);
+ unsigned SubElemSize = FVT->getElementType()->getScalarSizeInBits() / 8;
+ ElemSize = FVT->getNumElements() * SubElemSize;
+ Align = SubElemSize;
+ } else {
+ assert(ElemLayoutTy->isIntegerTy() || ElemLayoutTy->isFloatingPointTy());
+ ElemSize = ElemLayoutTy->getScalarSizeInBits() / 8;
+ Align = ElemSize;
+ }
+
+ // calculate or get element offset for the vector or scalar
+ if (Packoffset != -1) {
+ ElemOffset = Packoffset;
+ } else {
+ ElemOffset = llvm::alignTo(EndOffset, Align);
+ // if the element does not fit, move it to the next row
+ if (ElemOffset + ElemSize > NextRowOffset)
+ ElemOffset = NextRowOffset;
+ }
+ }
+
+ // Update end offset of the layout; do not update it if the EndOffset
+ // is already bigger than the new value (which may happen with unordered
+ // packoffset annotations)
+ unsigned NewEndOffset =
+ ElemOffset + (ArrayCount - 1) * ArrayStride + ElemSize;
+ EndOffset = std::max<unsigned>(EndOffset, NewEndOffset);
+
+ // add the layout element and offset to the lists
+ Layout.push_back(ElemOffset);
+ LayoutElements.push_back(ElemLayoutTy);
+ return true;
+}
+
+} // namespace CodeGen
+} // namespace clang
diff --git a/clang/lib/CodeGen/HLSLBufferLayoutBuilder.h b/clang/lib/CodeGen/HLSLBufferLayoutBuilder.h
new file mode 100644
index 0000000000000..57bb17c557b9c
--- /dev/null
+++ b/clang/lib/CodeGen/HLSLBufferLayoutBuilder.h
@@ -0,0 +1,48 @@
+//===- HLSLBufferLayoutBuilder.h ------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/IR/DerivedTypes.h"
+
+namespace clang {
+class RecordType;
+class FieldDecl;
+
+namespace CodeGen {
+class CodeGenModule;
+
+//===----------------------------------------------------------------------===//
+// Implementation of constant buffer layout common between DirectX and
+// SPIR/SPIR-V.
+//===----------------------------------------------------------------------===//
+
+class HLSLBufferLayoutBuilder {
+private:
+ CodeGenModule &CGM;
+ llvm::StringRef LayoutTypeName;
+
+public:
+ HLSLBufferLayoutBuilder(CodeGenModule &CGM, llvm::StringRef LayoutTypeName)
+ : CGM(CGM), LayoutTypeName(LayoutTypeName) {}
+
+ // Returns LLVM target extension type with the name LayoutTypeName
+ // for given structure type and layout data. The first number in
+ // the Layout is the size followed by offsets for each struct element.
+ llvm::TargetExtType *
+ createLayoutType(const RecordType *StructType,
+ const llvm::SmallVector<unsigned> *Packoffsets = nullptr);
+
+private:
+ bool layoutField(const clang::FieldDecl *FD, unsigned &EndOffset,
+ llvm::SmallVector<unsigned> &Layout,
+ llvm::SmallVector<llvm::Type *> &LayoutElements,
+ int Packoffset);
+};
+
+} // namespace CodeGen
+} // namespace clang
diff --git a/clang/lib/CodeGen/Targets/DirectX.cpp b/clang/lib/CodeGen/Targets/DirectX.cpp
index 3d4b65aec0a3a..77091eb45f5cf 100644
--- a/clang/lib/CodeGen/Targets/DirectX.cpp
+++ b/clang/lib/CodeGen/Targets/DirectX.cpp
@@ -8,7 +8,7 @@
#include "ABIInfoImpl.h"
#include "CodeGenModule.h"
-#include "HLSLTargetInfo.h"
+#include "HLSLBufferLayoutBuilder.h"
#include "TargetInfo.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/SmallVector.h"
@@ -24,27 +24,16 @@ using namespace clang::CodeGen;
namespace {
-class DirectXTargetCodeGenInfo : public CommonHLSLTargetCodeGenInfo {
+class DirectXTargetCodeGenInfo : public TargetCodeGenInfo {
public:
DirectXTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
- : CommonHLSLTargetCodeGenInfo(std::make_unique<DefaultABIInfo>(CGT)) {}
+ : TargetCodeGenInfo(std::make_unique<DefaultABIInfo>(CGT)) {}
llvm::Type *getHLSLType(
CodeGenModule &CGM, const Type *T,
const SmallVector<unsigned> *Packoffsets = nullptr) const override;
-
- llvm::Type *getHLSLLayoutType(CodeGenModule &CGM,
- llvm::StructType *LayoutStructTy,
- SmallVector<unsigned> Layout) const override;
};
-llvm::Type *DirectXTargetCodeGenInfo::getHLSLLayoutType(
- CodeGenModule &CGM, llvm::StructType *LayoutStructTy,
- SmallVector<unsigned> Layout) const {
- return llvm::TargetExtType::get(CGM.getLLVMContext(), "dx.Layout",
- {LayoutStructTy}, Layout);
-}
-
llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(
CodeGenModule &CGM, const Type *Ty,
const SmallVector<unsigned> *Packoffsets) const {
@@ -80,8 +69,9 @@ llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(
if (ContainedTy.isNull() || !ContainedTy->isStructureType())
return nullptr;
- llvm::Type *BufferLayoutTy = this->createHLSLBufferLayoutType(
- CGM, ContainedTy->getAsStructureType(), Packoffsets);
+ llvm::Type *BufferLayoutTy =
+ HLSLBufferLayoutBuilder(CGM, "dx.Layout")
+ .createLayoutType(ContainedTy->getAsStructureType(), Packoffsets);
if (!BufferLayoutTy)
return nullptr;
diff --git a/clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp b/clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp
deleted file mode 100644
index e634e47853d35..0000000000000
--- a/clang/lib/CodeGen/Targets/HLSLTargetInfo.cpp
+++ /dev/null
@@ -1,202 +0,0 @@
-//===- HLSLTargetInto.cpp--------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "HLSLTargetInfo.h"
-#include "CGHLSLRuntime.h"
-#include "TargetInfo.h"
-#include "clang/AST/DeclCXX.h"
-
-//===----------------------------------------------------------------------===//
-// Target codegen info implementation common between DirectX and SPIR/SPIR-V.
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-// Creates a new array type with the same dimentions
-// but with the new element type.
-static llvm::Type *
-createArrayWithNewElementType(CodeGenModule &CGM,
- const ConstantArrayType *ArrayType,
- llvm::Type *NewElemType) {
- const clang::Type *ArrayElemType = ArrayType->getArrayElementTypeNoTypeQual();
- if (ArrayElemType->isConstantArrayType())
- NewElemType = createArrayWithNewElementType(
- CGM, cast<const ConstantArrayType>(ArrayElemType), NewElemType);
- return llvm::ArrayType::get(NewElemType, ArrayType->getSExtSize());
-}
-
-// Returns the size of a scalar or vector in bytes/
-static unsigned getScalarOrVectorSizeInBytes(llvm::Type *Ty) {
- assert(Ty->isVectorTy() || Ty->isIntegerTy() || Ty->isFloatingPointTy());
- if (Ty->isVectorTy()) {
- llvm::FixedVectorType *FVT = cast<llvm::FixedVectorType>(Ty);
- return FVT->getNumElements() *
- (FVT->getElementType()->getScalarSizeInBits() / 8);
- }
- return Ty->getScalarSizeInBits() / 8;
-}
-
-} // namespace
-
-// Creates a layout type for given struct with HLSL constant buffer layout
-// taking into account Packoffsets, if provided.
-// Previously created layout types are cached in CGHLSLRuntime because
-// TargetCodeGenInto info is cannot store any data
-// (CGM.getTargetCodeGenInfo() returns a const reference to TargetCondegenInfo).
-//
-// The function iterates over all fields of the StructType (including base
-// classes), converts each field to its corresponding LLVM type and calculated
-// it's HLSL constant bufffer layout (offset and size). Any embedded struct (or
-// arrays of structs) are converted to target layout types as well.
-llvm::Type *CommonHLSLTargetCodeGenInfo::createHLSLBufferLayoutType(
- CodeGenModule &CGM, const RecordType *StructType,
- const SmallVector<unsigned> *Packoffsets) const {
-
- // check if we already have the layout type for this struct
- if (llvm::Type *Ty = CGM.getHLSLRuntime().getHLSLBufferLayoutType(StructType))
- return Ty;
-
- SmallVector<unsigned> Layout;
- SmallVector<llvm::Type *> LayoutElements;
- unsigned Index = 0; // packoffset index
- unsigned EndOffset = 0;
- const unsigned BufferRowAlign = 16U;
-
- // reserve first spot in the layout vector for buffer size
- Layout.push_back(0);
-
- // iterate over all fields of the record, including fields on base classes
- llvm::SmallVector<const RecordType *> RecordTypes;
- RecordTypes.push_back(StructType);
- while (RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
- CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl();
- assert(D->getNumBases() == 1 &&
- "HLSL doesn't support multiple inheritance");
- RecordTypes.push_back(D->bases_begin()->getType()->getAs<RecordType>());
- }
- while (!RecordTypes.empty()) {
- const RecordType *RT = RecordTypes.back();
- RecordTypes.pop_back();
-
- for (const auto *FD : RT->getDecl()->fields()) {
- assert(!Packoffsets || Index < Packoffsets->size() &&
- "number of elements in layout struct does not "
- "match number of packoffset annotations");
- // Size of element; for arrays this is a size of a single element in the
- // array. Total array size of calculated as (ArrayCount-1) * ArrayStride +
- // ElemSize.
- unsigned ElemSize = 0;
-
- unsigned ElemOffset = 0;
- unsigned ArrayCount = 1;
- unsigned ArrayStride = 0;
- unsigned NextRowOffset = llvm::alignTo(EndOffset, BufferRowAlign);
- llvm::Type *ElemLayoutTy = nullptr;
-
- QualType FieldTy = FD->getType();
-
- if (FieldTy->isConstantArrayType()) {
- // Unwrap array to find the element type and get combined array size.
- QualType Ty = FieldTy;
- while (Ty->isConstantArrayType()) {
- const ConstantArrayType *ArrayTy = cast<ConstantArrayType>(Ty);
- ArrayCount *= ArrayTy->getSExtSize();
- Ty = ArrayTy->getElementType();
- }
- // For array of structures, create a new array with a layout type
- // instead of the structure type.
- if (Ty->isStructureType()) {
- llvm::Type *NewTy = cast<llvm::TargetExtType>(
- createHLSLBufferLayoutType(CGM, Ty->getAsStructureType()));
- if (!NewTy)
- return nullptr;
- assert(isa<llvm::TargetExtType>(NewTy) && "expected target type");
- ElemSize = cast<llvm::TargetExtType>(NewTy)->getIntParameter(0);
- ElemLayoutTy = createArrayWithNewElementType(
- CGM, cast<ConstantArrayType>(FieldTy.getTypePtr()), NewTy);
- } else {
- // Array of vectors or scalars
- ElemSize = getScalarOrVectorSizeInBytes(
- CGM.getTypes().ConvertTypeForMem(Ty));
- ElemLayoutTy = CGM.getTypes().ConvertTypeForMem(FieldTy);
- }
- ArrayStride = llvm::alignTo(ElemSize, BufferRowAlign);
- ElemOffset =
- Packoffsets != nullptr ? (*Packoffsets)[Index] : NextRowOffset;
-
- } else if (FieldTy->isStructureType()) {
- // Create a layout type for the structure
- ElemLayoutTy =
- createHLSLBufferLayoutType(CGM, FieldTy->getAsStructureType());
- if (!ElemLayoutTy)
- return nullptr;
- assert(isa<llvm::TargetExtType>(ElemLayoutTy) &&
- "expected target type");
- ElemSize = cast<llvm::TargetExtType>(ElemLayoutTy)->getIntParameter(0);
- ElemOffset =
- Packoffsets != nullptr ? (*Packoffsets)[Index] : NextRowOffset;
- } else {
- // scalar or vector - find element size and alignment
- unsigned Align = 0;
- ElemLayoutTy = CGM.getTypes().ConvertTypeForMem(FieldTy);
- if (ElemLayoutTy->isVectorTy()) {
- // align vectors by sub element size
- const llvm::FixedVectorType *FVT =
- cast<llvm::FixedVectorType>(ElemLayoutTy);
- unsigned SubElemSize =
- FVT->getElementType()->getScalarSizeInBits() / 8;
- ElemSize = FVT->getNumElements() * SubElemSize;
- Align = SubElemSize;
- } else {
- assert(ElemLayoutTy->isIntegerTy() ||
- ElemLayoutTy->isFloatingPointTy());
- ElemSize = ElemLayoutTy->getScalarSizeInBits() / 8;
- Align = ElemSize;
- }
- // calculate or get element offset for the vector or scalar
- if (Packoffsets != nullptr) {
- ElemOffset = (*Packoffsets)[Index];
- } else {
- ElemOffset = llvm::alignTo(EndOffset, Align);
- // if the element does not fit, move it to the next row
- if (ElemOffset + ElemSize > NextRowOffset)
- ElemOffset = NextRowOffset;
- }
- }
-
- // Update end offset of the layout; do not update it if the EndOffset
- // is already bigger than the new value (which may happen with unordered
- // packoffset annotations)
- unsigned NewEndOffset =
- ElemOffset + (ArrayCount - 1) * ArrayStride + ElemSize;
- EndOffset = std::max<unsigned>(EndOffset, NewEndOffset);
-
- // add the layout element and offset to the lists
- Layout.push_back(ElemOffset);
- LayoutElements.push_back(ElemLayoutTy);
- Index++;
- }
- }
-
- // set the size of the buffer
- Layout[0] = EndOffset;
-
- // create the layout struct type; anonymous struct have empty name but
- // non-empty qualified name
- const CXXRecordDecl *Decl = StructType->getAsCXXRecordDecl();
- std::string Name =
- Decl->getName().empty() ? "anon" : Decl->getQualifiedNameAsString();
- llvm::StructType *StructTy =
- llvm::StructType::create(LayoutElements, Name, true);
-
- // create target layout type
- llvm::Type *NewLayoutTy = this->getHLSLLayoutType(CGM, StructTy, Layout);
- if (NewLayoutTy)
- CGM.getHLSLRuntime().addHLSLBufferLayoutType(StructType, NewLayoutTy);
- return NewLayoutTy;
-}
diff --git a/clang/lib/CodeGen/Targets/HLSLTargetInfo.h b/clang/lib/CodeGen/Targets/HLSLTargetInfo.h
deleted file mode 100644
index 279ce4fba3dad..0000000000000
--- a/clang/lib/CodeGen/Targets/HLSLTargetInfo.h
+++ /dev/null
@@ -1,39 +0,0 @@
-//===- HLSLTargetInfo.h ---------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "ABIInfoImpl.h"
-#include "TargetInfo.h"
-
-using namespace clang;
-using namespace clang::CodeGen;
-
-//===----------------------------------------------------------------------===//
-// Target codegen info implementation common between DirectX and SPIR/SPIR-V.
-//===----------------------------------------------------------------------===//
-
-class CommonHLSLTargetCodeGenInfo : public TargetCodeGenInfo {
-public:
- CommonHLSLTargetCodeGenInfo(std::unique_ptr<ABIInfo> Info)
- : TargetCodeGenInfo(std::move(Info)) {}
-
- // Returns LLVM target extension type "dx.Layout" or "spv.Layout"
- // for given structure type and layout data. The first number in
- // the Layout is the size followed by offsets for each struct element.
- virtual llvm::Type *getHLSLLayoutType(CodeGenModule &CGM,
- llvm::StructType *LayoutStructTy,
- SmallVector<unsigned> Layout) const {
- return nullptr;
- };
-
-protected:
- // Creates a layout type for given struct with HLSL constant buffer layout
- // taking into account Packoffsets, if provided.
- virtual llvm::Type *createHLSLBufferLayoutType(
- CodeGenModule &CGM, const clang::RecordType *StructType,
- const SmallVector<unsigned> *Packoffsets = nullptr) const;
-};
diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp
index 3cf95483dc4fa..c94db31ae1a89 100644
--- a/clang/lib/CodeGen/Targets/SPIR.cpp
+++ b/clang/lib/CodeGen/Targets/SPIR.cpp
@@ -7,7 +7,6 @@
//===----------------------------------------------------------------------===//
#include "ABIInfoImpl.h"
-#include "HLSLTargetInfo.h"
#include "TargetInfo.h"
using namespace clang;
@@ -39,12 +38,12 @@ class SPIRVABIInfo : public CommonSPIRABIInfo {
};
} // end anonymous namespace
namespace {
-class CommonSPIRTargetCodeGenInfo : public CommonHLSLTargetCodeGenInfo {
+class CommonSPIRTargetCodeGenInfo : public TargetCodeGenInfo {
public:
CommonSPIRTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
- : CommonHLSLTargetCodeGenInfo(std::make_unique<CommonSPIRABIInfo>(CGT)) {}
+ : TargetCodeGenInfo(std::make_unique<CommonSPIRABIInfo>(CGT)) {}
CommonSPIRTargetCodeGenInfo(std::unique_ptr<ABIInfo> ABIInfo)
- : CommonHLSLTargetCodeGenInfo(std::move(ABIInfo)) {}
+ : TargetCodeGenInfo(std::move(ABIInfo)) {}
LangAS getASTAllocaAddressSpace() const override {
return getLangASFromTargetAS(
>From 77987bd26cc81c2b08e52a3b2cdf6ac2c18ae0e0 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Wed, 19 Feb 2025 14:20:15 -0800
Subject: [PATCH 13/13] revert clang/lib/CodeGen/CMakeLists.txt whitespace
changes
---
clang/lib/CodeGen/CMakeLists.txt | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt
index 0f3a106cea1b9..05ab6671453f8 100644
--- a/clang/lib/CodeGen/CMakeLists.txt
+++ b/clang/lib/CodeGen/CMakeLists.txt
@@ -31,26 +31,25 @@ set(LLVM_LINK_COMPONENTS
Target
TargetParser
TransformUtils
-)
+ )
# Workaround for MSVC ARM64 performance regression:
# https://developercommunity.visualstudio.com/t/Compiling-a-specific-code-for-ARM64-with/10444970
# Since /O1 and /O2 represent a set of optimizations,
# our goal is to disable the /Og flag while retaining the other optimizations from the /O1|/O2 set
if(MSVC AND NOT CMAKE_CXX_COMPILER_ID MATCHES Clang
- AND MSVC_VERSION VERSION_GREATER_EQUAL 1932
- AND MSVC_VERSION VERSION_LESS 1939
- AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64")
+ AND MSVC_VERSION VERSION_GREATER_EQUAL 1932
+ AND MSVC_VERSION VERSION_LESS 1939
+ AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64")
+
string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE)
string(REGEX MATCHALL "/[Oo][12]" opt_flags "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${uppercase_CMAKE_BUILD_TYPE}}")
-
- if(opt_flags)
+ if (opt_flags)
if(opt_flags MATCHES "1$")
set(opt_flags "/Od;/Os;/Oy;/Ob2;/GF;/Gy")
- elseif(opt_flags MATCHES "2$")
+ elseif (opt_flags MATCHES "2$")
set(opt_flags "/Od;/Oi;/Ot;/Oy;/Ob2;/GF;/Gy")
endif()
-
set_source_files_properties(CGBuiltin.cpp PROPERTIES COMPILE_OPTIONS "${opt_flags}")
endif()
endif()
@@ -149,7 +148,6 @@ add_clang_library(clangCodeGen
vt_gen
intrinsics_gen
ClangDriverOptions
-
# These generated headers are included transitively.
ARMTargetParserTableGen
AArch64TargetParserTableGen
@@ -161,4 +159,4 @@ add_clang_library(clangCodeGen
clangFrontend
clangLex
clangSerialization
-)
+ )
More information about the cfe-commits
mailing list