Skip to content

Commit af872d5

Browse files
authored
[HLSL] Add RWStructuredBuffer definition to HLSLExternalSemaSource (#113477)
Add tests for RWStructuredBuffer class definition. Use shared test files for all structured buffers' constructor and subscript tests. Keep AST and element-type tests separate for each buffer type because they longer and failures would be harder to match. Fixes #112775
1 parent 4bce214 commit af872d5

7 files changed

+166
-16
lines changed

clang/lib/Sema/HLSLExternalSemaSource.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,17 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
519519
.addArraySubscriptOperators()
520520
.completeDefinition();
521521
});
522+
523+
Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWStructuredBuffer")
524+
.addSimpleTemplateParams(*SemaPtr, {"element_type"})
525+
.Record;
526+
onCompletion(Decl, [this](CXXRecordDecl *Decl) {
527+
setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
528+
ResourceKind::TypedBuffer, /*IsROV=*/false,
529+
/*RawBuffer=*/true)
530+
.addArraySubscriptOperators()
531+
.completeDefinition();
532+
});
522533
}
523534

524535
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 RWStructuredBuffer 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 RWStructuredBuffer
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 RWStructuredBuffer
17+
// EMPTY-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
18+
19+
// There should be no more occurrances of RWStructuredBuffer
20+
// EMPTY-NOT: {{[^[:alnum:]]}}RWStructuredBuffer
21+
22+
#ifndef EMPTY
23+
24+
RWStructuredBuffer<int> Buffer;
25+
26+
#endif
27+
28+
// CHECK: ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit RWStructuredBuffer
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 RWStructuredBuffer 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 '__hlsl_resource_t
34+
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
35+
// CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]]
36+
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
37+
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer
38+
39+
// CHECK: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'element_type &const (unsigned int) const'
40+
// CHECK-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Idx 'unsigned int'
41+
// CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
42+
// CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
43+
// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue .e 0x{{[0-9A-Fa-f]+}}
44+
// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'const RWStructuredBuffer<element_type>' lvalue implicit this
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: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue .e 0x{{[0-9A-Fa-f]+}}
52+
// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'RWStructuredBuffer<element_type>' lvalue implicit this
53+
// CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline
54+
55+
// CHECK: ClassTemplateSpecializationDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> class RWStructuredBuffer definition
56+
57+
// CHECK: TemplateArgument type 'int'
58+
// CHECK-NEXT: BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
59+
// CHECK-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
60+
// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit h '__hlsl_resource_t
61+
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
62+
// CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]]
63+
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(int)]]
64+
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer

clang/test/AST/HLSL/StructuredBuffer-AST.hlsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
// EMPTY-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
1818

1919
// There should be no more occurrances of StructuredBuffer
20-
// EMPTY-NOT: StructuredBuffer
20+
// EMPTY-NOT: {{[^[:alnum:]]}}StructuredBuffer
2121

2222
#ifndef EMPTY
2323

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.2-compute -finclude-default-header -fnative-half-type -emit-llvm -o - %s | FileCheck %s
2+
3+
// NOTE: The number in type name and whether the struct is packed or not will mostly
4+
// likely change once subscript operators are properly implemented (llvm/llvm-project#95956)
5+
// and theinterim field of the contained type is removed.
6+
7+
// CHECK: %"class.hlsl::RWStructuredBuffer" = type <{ target("dx.RawBuffer", i16, 1, 0)
8+
// CHECK: %"class.hlsl::RWStructuredBuffer.0" = type <{ target("dx.RawBuffer", i16, 1, 0)
9+
// CHECK: %"class.hlsl::RWStructuredBuffer.2" = type { target("dx.RawBuffer", i32, 1, 0)
10+
// CHECK: %"class.hlsl::RWStructuredBuffer.3" = type { target("dx.RawBuffer", i32, 1, 0)
11+
// CHECK: %"class.hlsl::RWStructuredBuffer.4" = type { target("dx.RawBuffer", i64, 1, 0)
12+
// CHECK: %"class.hlsl::RWStructuredBuffer.5" = type { target("dx.RawBuffer", i64, 1, 0)
13+
// CHECK: %"class.hlsl::RWStructuredBuffer.6" = type <{ target("dx.RawBuffer", half, 1, 0)
14+
// CHECK: %"class.hlsl::RWStructuredBuffer.8" = type { target("dx.RawBuffer", float, 1, 0)
15+
// CHECK: %"class.hlsl::RWStructuredBuffer.9" = type { target("dx.RawBuffer", double, 1, 0)
16+
// CHECK: %"class.hlsl::RWStructuredBuffer.10" = type { target("dx.RawBuffer", <4 x i16>, 1, 0)
17+
// CHECK: %"class.hlsl::RWStructuredBuffer.11" = type { target("dx.RawBuffer", <3 x i32>, 1, 0)
18+
// CHECK: %"class.hlsl::RWStructuredBuffer.12" = type { target("dx.RawBuffer", <2 x half>, 1, 0)
19+
// CHECK: %"class.hlsl::RWStructuredBuffer.13" = type { target("dx.RawBuffer", <3 x float>, 1, 0)
20+
21+
RWStructuredBuffer<int16_t> BufI16;
22+
RWStructuredBuffer<uint16_t> BufU16;
23+
RWStructuredBuffer<int> BufI32;
24+
RWStructuredBuffer<uint> BufU32;
25+
RWStructuredBuffer<int64_t> BufI64;
26+
RWStructuredBuffer<uint64_t> BufU64;
27+
RWStructuredBuffer<half> BufF16;
28+
RWStructuredBuffer<float> BufF32;
29+
RWStructuredBuffer<double> BufF64;
30+
RWStructuredBuffer< vector<int16_t, 4> > BufI16x4;
31+
RWStructuredBuffer< vector<uint, 3> > BufU32x3;
32+
RWStructuredBuffer<half2> BufF16x2;
33+
RWStructuredBuffer<float3> BufF32x3;
34+
// TODO: RWStructuredBuffer<snorm half> BufSNormF16;
35+
// TODO: RWStructuredBuffer<unorm half> BufUNormF16;
36+
// TODO: RWStructuredBuffer<snorm float> BufSNormF32;
37+
// TODO: RWStructuredBuffer<unorm float> BufUNormF32;
38+
// TODO: RWStructuredBuffer<snorm double> BufSNormF64;
39+
// TODO: RWStructuredBuffer<unorm double> BufUNormF64;
40+
41+
[numthreads(1,1,1)]
42+
void main(int GI : SV_GroupIndex) {
43+
BufI16[GI] = 0;
44+
BufU16[GI] = 0;
45+
BufI32[GI] = 0;
46+
BufU32[GI] = 0;
47+
BufI64[GI] = 0;
48+
BufU64[GI] = 0;
49+
BufF16[GI] = 0;
50+
BufF32[GI] = 0;
51+
BufF64[GI] = 0;
52+
BufI16x4[GI] = 0;
53+
BufU32x3[GI] = 0;
54+
BufF16x2[GI] = 0;
55+
BufF32x3[GI] = 0;
56+
}
57+
58+
// CHECK: !{{[0-9]+}} = !{ptr @BufI16, i32 10, i32 2,
59+
// CHECK: !{{[0-9]+}} = !{ptr @BufU16, i32 10, i32 3,
60+
// CHECK: !{{[0-9]+}} = !{ptr @BufI32, i32 10, i32 4,
61+
// CHECK: !{{[0-9]+}} = !{ptr @BufU32, i32 10, i32 5,
62+
// CHECK: !{{[0-9]+}} = !{ptr @BufI64, i32 10, i32 6,
63+
// CHECK: !{{[0-9]+}} = !{ptr @BufU64, i32 10, i32 7,
64+
// CHECK: !{{[0-9]+}} = !{ptr @BufF16, i32 10, i32 8,
65+
// CHECK: !{{[0-9]+}} = !{ptr @BufF32, i32 10, i32 9,
66+
// CHECK: !{{[0-9]+}} = !{ptr @BufF64, i32 10, i32 10,
67+
// CHECK: !{{[0-9]+}} = !{ptr @BufI16x4, i32 10, i32 2,
68+
// CHECK: !{{[0-9]+}} = !{ptr @BufU32x3, i32 10, i32 5,
69+
// CHECK: !{{[0-9]+}} = !{ptr @BufF16x2, i32 10, i32 8,
70+
// CHECK: !{{[0-9]+}} = !{ptr @BufF32x3, i32 10, i32 9,

clang/test/CodeGenHLSL/builtins/StructuredBuffer-elementtype.hlsl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,12 @@ StructuredBuffer< vector<int16_t, 4> > BufI16x4;
3131
StructuredBuffer< vector<uint, 3> > BufU32x3;
3232
StructuredBuffer<half2> BufF16x2;
3333
StructuredBuffer<float3> BufF32x3;
34-
// TODO: StructuredBuffer<snorm half> BufSNormF16; -> 11
35-
// TODO: StructuredBuffer<unorm half> BufUNormF16; -> 12
36-
// TODO: StructuredBuffer<snorm float> BufSNormF32; -> 13
37-
// TODO: StructuredBuffer<unorm float> BufUNormF32; -> 14
38-
// TODO: StructuredBuffer<snorm double> BufSNormF64; -> 15
39-
// TODO: StructuredBuffer<unorm double> BufUNormF64; -> 16
34+
// TODO: StructuredBuffer<snorm half> BufSNormF16;
35+
// TODO: StructuredBuffer<unorm half> BufUNormF16;
36+
// TODO: StructuredBuffer<snorm float> BufSNormF32;
37+
// TODO: StructuredBuffer<unorm float> BufUNormF32;
38+
// TODO: StructuredBuffer<snorm double> BufSNormF64;
39+
// TODO: StructuredBuffer<unorm double> BufUNormF64;
4040

4141
[numthreads(1,1,1)]
4242
void main(int GI : SV_GroupIndex) {

clang/test/CodeGenHLSL/builtins/StructuredBuffer-constructor.hlsl renamed to clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,30 @@
44
// NOTE: SPIRV codegen for resource types is not yet implemented
55

66
StructuredBuffer<float> Buf : register(t10);
7+
RWStructuredBuffer<float> Buf2 : register(u5, space1);
78

89
// CHECK: %"class.hlsl::StructuredBuffer" = type { target("dx.RawBuffer", float, 0, 0), float }
10+
// CHECK: %"class.hlsl::RWStructuredBuffer" = type { target("dx.RawBuffer", float, 1, 0), float }
11+
912
// CHECK: @Buf = global %"class.hlsl::StructuredBuffer" zeroinitializer, align 4
13+
// CHECK: @Buf2 = global %"class.hlsl::RWStructuredBuffer" zeroinitializer, align 4
1014

1115
// CHECK: define linkonce_odr void @_ZN4hlsl16StructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(8) %this)
1216
// CHECK-NEXT: entry:
13-
14-
// CHECK: define internal void @_GLOBAL__sub_I_StructuredBuffer_constructor.hlsl()
17+
// CHECK: define linkonce_odr void @_ZN4hlsl18RWStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(8) %this)
1518
// CHECK-NEXT: entry:
16-
// CHECK-NEXT: call void @__cxx_global_var_init()
17-
// CHECK-NEXT: call void @_init_resource_bindings()
19+
20+
// CHECK: define internal void @_GLOBAL__sub_I_StructuredBuffers_constructors.hlsl()
21+
// CHECK: entry:
22+
// CHECK: call void @_init_resource_bindings()
1823

1924
// CHECK: define internal void @_init_resource_bindings() {
2025
// CHECK-NEXT: entry:
2126
// CHECK-DXIL-NEXT: %Buf_h = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.handle.fromBinding.tdx.RawBuffer_f32_0_0t(i32 0, i32 10, i32 1, i32 0, i1 false)
2227
// CHECK-DXIL-NEXT: store target("dx.RawBuffer", float, 0, 0) %Buf_h, ptr @Buf, align 4
28+
// CHECK-DXIL-NEXT: %Buf2_h = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.handle.fromBinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 5, i32 1, i32 0, i1 false)
29+
// CHECK-DXIL-NEXT: store target("dx.RawBuffer", float, 1, 0) %Buf2_h, ptr @Buf2, align 4
2330
// CHECK-SPIRV-NEXT: %Buf_h = call target("dx.RawBuffer", float, 0, 0) @llvm.spv.handle.fromBinding.tdx.RawBuffer_f32_0_0t(i32 0, i32 10, i32 1, i32 0, i1 false)
2431
// CHECK-SPIRV-NEXT: store target("dx.RawBuffer", float, 0, 0) %Buf_h, ptr @Buf", align 4
32+
// CHECK-SPIRV-NEXT: %Buf2_h = call target("dx.RawBuffer", float, 1, 0) @llvm.spv.handle.fromBinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 5, i32 1, i32 0, i1 false)
33+
// CHECK-SPIRV-NEXT: store target("dx.RawBuffer", float, 1, 0) %Buf2_h, ptr @Buf2", align 4

clang/test/CodeGenHLSL/builtins/StructuredBuffer-subscript.hlsl renamed to clang/test/CodeGenHLSL/builtins/StructuredBuffers-subscripts.hlsl

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -emit-llvm -o - -O0 %s | FileCheck %s
22

3-
// FIXME: This tests will fail once StructuredBuffer subscript operator is properly
4-
// implemented (llvm-project/llvm#112977). StructuredBuffer is a read-only resource
5-
// and the result of a subscript operator cannot be assigned to.
6-
73
StructuredBuffer<int> In;
8-
StructuredBuffer<int> Out;
4+
RWStructuredBuffer<int> Out;
95

106
[numthreads(1,1,1)]
117
void main(unsigned GI : SV_GroupIndex) {

0 commit comments

Comments
 (0)