Skip to content

Commit b8239e1

Browse files
authored
[HLSL] Add StructuredBuffer to external sema source (#106316)
This PR adds `StructuredBuffer` to `HLSLExternalSemaSource.cpp`, by copying the logic from RWBuffer but just replacing the name with StructuredBuffer. The change now allows StructuredBuffers to be defined in HLSL, though they function the same as RWBuffers. Further work to apply the appropriate attributes that distinguish StructuredBuffers from other Buffer types will be deferred. This improves our position on #106189
1 parent c31d343 commit b8239e1

File tree

7 files changed

+195
-0
lines changed

7 files changed

+195
-0
lines changed

clang/lib/Sema/HLSLExternalSemaSource.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,16 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
525525
.addArraySubscriptOperators()
526526
.completeDefinition();
527527
});
528+
529+
Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "StructuredBuffer")
530+
.addSimpleTemplateParams(*SemaPtr, {"element_type"})
531+
.Record;
532+
onCompletion(Decl, [this](CXXRecordDecl *Decl) {
533+
setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
534+
ResourceKind::TypedBuffer, /*IsROV=*/false)
535+
.addArraySubscriptOperators()
536+
.completeDefinition();
537+
});
528538
}
529539

530540
void HLSLExternalSemaSource::onCompletion(CXXRecordDecl *Record,
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump -DEMPTY %s | FileCheck -check-prefix=EMPTY %s
2+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump %s | FileCheck %s
3+
4+
5+
// This test tests two different AST generations. The "EMPTY" test mode verifies
6+
// the AST generated by forward declaration of the HLSL types which happens on
7+
// initializing the HLSL external AST with an AST Context.
8+
9+
// The non-empty mode has a use that requires the StructuredBuffer type be complete,
10+
// which results in the AST being populated by the external AST source. That
11+
// case covers the full implementation of the template declaration and the
12+
// instantiated specialization.
13+
14+
// EMPTY: ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit StructuredBuffer
15+
// EMPTY-NEXT: TemplateTypeParmDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> class depth 0 index 0 element_type
16+
// EMPTY-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit <undeserialized declarations> class StructuredBuffer
17+
// EMPTY-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
18+
19+
// There should be no more occurrances of StructuredBuffer
20+
// EMPTY-NOT: StructuredBuffer
21+
22+
#ifndef EMPTY
23+
24+
StructuredBuffer<float> Buffer;
25+
26+
#endif
27+
28+
// CHECK: ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit StructuredBuffer
29+
// CHECK-NEXT: TemplateTypeParmDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> class depth 0 index 0 element_type
30+
// CHECK-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit class StructuredBuffer definition
31+
32+
// CHECK: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
33+
// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit h 'element_type *'
34+
// CHECK-NEXT: HLSLResourceClassAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit UAV
35+
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer
36+
37+
// CHECK: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'element_type &const (unsigned int) const'
38+
// CHECK-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Idx 'unsigned int'
39+
// CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
40+
// CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
41+
// CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue
42+
// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}}
43+
// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'const StructuredBuffer<element_type>' lvalue implicit this
44+
// CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Idx' 'unsigned int'
45+
// CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline
46+
47+
// CHECK-NEXT: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'element_type &(unsigned int)'
48+
// CHECK-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Idx 'unsigned int'
49+
// CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
50+
// CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
51+
// CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue
52+
// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}}
53+
// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'StructuredBuffer<element_type>' lvalue implicit this
54+
// CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Idx' 'unsigned int'
55+
// CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline
56+
57+
// CHECK: ClassTemplateSpecializationDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> class StructuredBuffer definition
58+
59+
// CHECK: TemplateArgument type 'float'
60+
// CHECK-NEXT: BuiltinType 0x{{[0-9A-Fa-f]+}} 'float'
61+
// CHECK-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
62+
// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit referenced h 'float *'
63+
// CHECK-NEXT: HLSLResourceClassAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit UAV
64+
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
2+
3+
StructuredBuffer<float> Buffer1;
4+
StructuredBuffer<vector<float, 4> > BufferArray[4];
5+
6+
StructuredBuffer<float> Buffer2 : register(u3);
7+
StructuredBuffer<vector<float, 4> > BufferArray2[4] : register(u4);
8+
9+
StructuredBuffer<float> Buffer3 : register(u3, space1);
10+
StructuredBuffer<vector<float, 4> > BufferArray3[4] : register(u4, space1);
11+
12+
[numthreads(1,1,1)]
13+
void main() {
14+
}
15+
16+
// CHECK: !hlsl.uavs = !{![[Single:[0-9]+]], ![[Array:[0-9]+]], ![[SingleAllocated:[0-9]+]], ![[ArrayAllocated:[0-9]+]], ![[SingleSpace:[0-9]+]], ![[ArraySpace:[0-9]+]]}
17+
// CHECK-DAG: ![[Single]] = !{ptr @"?Buffer1@@3V?$StructuredBuffer@M@hlsl@@A", i32 10, i32 9, i1 false, i32 -1, i32 0}
18+
// CHECK-DAG: ![[Array]] = !{ptr @"?BufferArray@@3PAV?$StructuredBuffer@T?$__vector@M$03@__clang@@@hlsl@@A", i32 10, i32 9, i1 false, i32 -1, i32 0}
19+
// CHECK-DAG: ![[SingleAllocated]] = !{ptr @"?Buffer2@@3V?$StructuredBuffer@M@hlsl@@A", i32 10, i32 9, i1 false, i32 3, i32 0}
20+
// CHECK-DAG: ![[ArrayAllocated]] = !{ptr @"?BufferArray2@@3PAV?$StructuredBuffer@T?$__vector@M$03@__clang@@@hlsl@@A", i32 10, i32 9, i1 false, i32 4, i32 0}
21+
// CHECK-DAG: ![[SingleSpace]] = !{ptr @"?Buffer3@@3V?$StructuredBuffer@M@hlsl@@A", i32 10, i32 9, i1 false, i32 3, i32 1}
22+
// CHECK-DAG: ![[ArraySpace]] = !{ptr @"?BufferArray3@@3PAV?$StructuredBuffer@T?$__vector@M$03@__clang@@@hlsl@@A", i32 10, i32 9, i1 false, i32 4, i32 1}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefix=CHECK-SPIRV
2+
3+
StructuredBuffer<float> Buf;
4+
5+
// CHECK: define linkonce_odr noundef ptr @"??0?$StructuredBuffer@M@hlsl@@QAA@XZ"
6+
// CHECK-NEXT: entry:
7+
8+
// CHECK: %[[HandleRes:[0-9]+]] = call ptr @llvm.dx.create.handle(i8 1)
9+
// CHECK: store ptr %[[HandleRes]], ptr %h, align 4
10+
11+
// CHECK-SPIRV: %[[HandleRes:[0-9]+]] = call ptr @llvm.spv.create.handle(i8 1)
12+
// CHECK-SPIRV: store ptr %[[HandleRes]], ptr %h, align 8
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.2-compute -finclude-default-header -fnative-half-type -emit-llvm -o - %s | FileCheck %s
2+
3+
StructuredBuffer<int16_t> BufI16;
4+
StructuredBuffer<uint16_t> BufU16;
5+
StructuredBuffer<int> BufI32;
6+
StructuredBuffer<uint> BufU32;
7+
StructuredBuffer<int64_t> BufI64;
8+
StructuredBuffer<uint64_t> BufU64;
9+
StructuredBuffer<half> BufF16;
10+
StructuredBuffer<float> BufF32;
11+
StructuredBuffer<double> BufF64;
12+
StructuredBuffer< vector<int16_t, 4> > BufI16x4;
13+
StructuredBuffer< vector<uint, 3> > BufU32x3;
14+
StructuredBuffer<half2> BufF16x2;
15+
StructuredBuffer<float3> BufF32x3;
16+
// TODO: StructuredBuffer<snorm half> BufSNormF16; -> 11
17+
// TODO: StructuredBuffer<unorm half> BufUNormF16; -> 12
18+
// TODO: StructuredBuffer<snorm float> BufSNormF32; -> 13
19+
// TODO: StructuredBuffer<unorm float> BufUNormF32; -> 14
20+
// TODO: StructuredBuffer<snorm double> BufSNormF64; -> 15
21+
// TODO: StructuredBuffer<unorm double> BufUNormF64; -> 16
22+
23+
[numthreads(1,1,1)]
24+
void main(int GI : SV_GroupIndex) {
25+
BufI16[GI] = 0;
26+
BufU16[GI] = 0;
27+
BufI32[GI] = 0;
28+
BufU32[GI] = 0;
29+
BufI64[GI] = 0;
30+
BufU64[GI] = 0;
31+
BufF16[GI] = 0;
32+
BufF32[GI] = 0;
33+
BufF64[GI] = 0;
34+
BufI16x4[GI] = 0;
35+
BufU32x3[GI] = 0;
36+
BufF16x2[GI] = 0;
37+
BufF32x3[GI] = 0;
38+
}
39+
40+
// CHECK: !{{[0-9]+}} = !{ptr @"?BufI16@@3V?$StructuredBuffer@F@hlsl@@A", i32 10, i32 2,
41+
// CHECK: !{{[0-9]+}} = !{ptr @"?BufU16@@3V?$StructuredBuffer@G@hlsl@@A", i32 10, i32 3,
42+
// CHECK: !{{[0-9]+}} = !{ptr @"?BufI32@@3V?$StructuredBuffer@H@hlsl@@A", i32 10, i32 4,
43+
// CHECK: !{{[0-9]+}} = !{ptr @"?BufU32@@3V?$StructuredBuffer@I@hlsl@@A", i32 10, i32 5,
44+
// CHECK: !{{[0-9]+}} = !{ptr @"?BufI64@@3V?$StructuredBuffer@J@hlsl@@A", i32 10, i32 6,
45+
// CHECK: !{{[0-9]+}} = !{ptr @"?BufU64@@3V?$StructuredBuffer@K@hlsl@@A", i32 10, i32 7,
46+
// CHECK: !{{[0-9]+}} = !{ptr @"?BufF16@@3V?$StructuredBuffer@$f16@@hlsl@@A", i32 10, i32 8,
47+
// CHECK: !{{[0-9]+}} = !{ptr @"?BufF32@@3V?$StructuredBuffer@M@hlsl@@A", i32 10, i32 9,
48+
// CHECK: !{{[0-9]+}} = !{ptr @"?BufF64@@3V?$StructuredBuffer@N@hlsl@@A", i32 10, i32 10,
49+
// CHECK: !{{[0-9]+}} = !{ptr @"?BufI16x4@@3V?$StructuredBuffer@T?$__vector@F$03@__clang@@@hlsl@@A", i32 10, i32 2,
50+
// CHECK: !{{[0-9]+}} = !{ptr @"?BufU32x3@@3V?$StructuredBuffer@T?$__vector@I$02@__clang@@@hlsl@@A", i32 10, i32 5,
51+
// CHECK: !{{[0-9]+}} = !{ptr @"?BufF16x2@@3V?$StructuredBuffer@T?$__vector@$f16@$01@__clang@@@hlsl@@A", i32 10, i32 8,
52+
// CHECK: !{{[0-9]+}} = !{ptr @"?BufF32x3@@3V?$StructuredBuffer@T?$__vector@M$02@__clang@@@hlsl@@A", i32 10, i32 9,
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -emit-llvm -o - -O0 %s | FileCheck %s
2+
3+
StructuredBuffer<int> In;
4+
StructuredBuffer<int> Out;
5+
6+
[numthreads(1,1,1)]
7+
void main(unsigned GI : SV_GroupIndex) {
8+
Out[GI] = In[GI];
9+
}
10+
11+
// Even at -O0 the subscript operators get inlined. The -O0 IR is a bit messy
12+
// and confusing to follow so the match here is pretty weak.
13+
14+
// CHECK: define internal void @"?main@@YAXI@Z"
15+
// CHECK-NOT: call
16+
// CHECK: ret void
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -fsyntax-only -verify %s
2+
3+
typedef vector<float, 3> float3;
4+
5+
StructuredBuffer<float3> Buffer;
6+
7+
// expected-error@+2 {{class template 'StructuredBuffer' requires template arguments}}
8+
// expected-note@*:* {{template declaration from hidden source: template <class element_type> class StructuredBuffer}}
9+
StructuredBuffer BufferErr1;
10+
11+
// expected-error@+2 {{too few template arguments for class template 'StructuredBuffer'}}
12+
// expected-note@*:* {{template declaration from hidden source: template <class element_type> class StructuredBuffer}}
13+
StructuredBuffer<> BufferErr2;
14+
15+
[numthreads(1,1,1)]
16+
void main() {
17+
(void)Buffer.h; // expected-error {{'h' is a private member of 'hlsl::StructuredBuffer<vector<float, 3> >'}}
18+
// expected-note@* {{implicitly declared private here}}
19+
}

0 commit comments

Comments
 (0)