Skip to content

[HLSL] Add RWStructuredBuffer definition to HLSLExternalSemaSource #113477

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions clang/lib/Sema/HLSLExternalSemaSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,17 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
.addArraySubscriptOperators()
.completeDefinition();
});

Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWStructuredBuffer")
.addSimpleTemplateParams(*SemaPtr, {"element_type"})
.Record;
onCompletion(Decl, [this](CXXRecordDecl *Decl) {
setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
ResourceKind::TypedBuffer, /*IsROV=*/false,
/*RawBuffer=*/true)
.addArraySubscriptOperators()
.completeDefinition();
});
}

void HLSLExternalSemaSource::onCompletion(CXXRecordDecl *Record,
Expand Down
64 changes: 64 additions & 0 deletions clang/test/AST/HLSL/RWStructuredBuffer-AST.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump -DEMPTY %s | FileCheck -check-prefix=EMPTY %s
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump %s | FileCheck %s


// This test tests two different AST generations. The "EMPTY" test mode verifies
// the AST generated by forward declaration of the HLSL types which happens on
// initializing the HLSL external AST with an AST Context.

// The non-empty mode has a use that requires the RWStructuredBuffer type be complete,
// which results in the AST being populated by the external AST source. That
// case covers the full implementation of the template declaration and the
// instantiated specialization.

// EMPTY: ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit RWStructuredBuffer
// EMPTY-NEXT: TemplateTypeParmDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> class depth 0 index 0 element_type
// EMPTY-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit <undeserialized declarations> class RWStructuredBuffer
// EMPTY-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final

// There should be no more occurrances of RWStructuredBuffer
// EMPTY-NOT: {{[^[:alnum:]]}}RWStructuredBuffer

#ifndef EMPTY

RWStructuredBuffer<int> Buffer;

#endif

// CHECK: ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit RWStructuredBuffer
// CHECK-NEXT: TemplateTypeParmDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> class depth 0 index 0 element_type
// CHECK-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit class RWStructuredBuffer definition

// CHECK: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit h '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer

// CHECK: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'element_type &const (unsigned int) const'
// CHECK-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Idx 'unsigned int'
// CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue .e 0x{{[0-9A-Fa-f]+}}
// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'const RWStructuredBuffer<element_type>' lvalue implicit this
// CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline

// CHECK-NEXT: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'element_type &(unsigned int)'
// CHECK-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Idx 'unsigned int'
// CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue .e 0x{{[0-9A-Fa-f]+}}
// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'RWStructuredBuffer<element_type>' lvalue implicit this
// CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline

// CHECK: ClassTemplateSpecializationDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> class RWStructuredBuffer definition

// CHECK: TemplateArgument type 'int'
// CHECK-NEXT: BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
// CHECK-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit h '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(int)]]
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer
2 changes: 1 addition & 1 deletion clang/test/AST/HLSL/StructuredBuffer-AST.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
// EMPTY-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final

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

#ifndef EMPTY

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.2-compute -finclude-default-header -fnative-half-type -emit-llvm -o - %s | FileCheck %s

// NOTE: The number in type name and whether the struct is packed or not will mostly
// likely change once subscript operators are properly implemented (llvm/llvm-project#95956)
// and theinterim field of the contained type is removed.

// CHECK: %"class.hlsl::RWStructuredBuffer" = type <{ target("dx.RawBuffer", i16, 1, 0)
// CHECK: %"class.hlsl::RWStructuredBuffer.0" = type <{ target("dx.RawBuffer", i16, 1, 0)
// CHECK: %"class.hlsl::RWStructuredBuffer.2" = type { target("dx.RawBuffer", i32, 1, 0)
// CHECK: %"class.hlsl::RWStructuredBuffer.3" = type { target("dx.RawBuffer", i32, 1, 0)
// CHECK: %"class.hlsl::RWStructuredBuffer.4" = type { target("dx.RawBuffer", i64, 1, 0)
// CHECK: %"class.hlsl::RWStructuredBuffer.5" = type { target("dx.RawBuffer", i64, 1, 0)
// CHECK: %"class.hlsl::RWStructuredBuffer.6" = type <{ target("dx.RawBuffer", half, 1, 0)
// CHECK: %"class.hlsl::RWStructuredBuffer.8" = type { target("dx.RawBuffer", float, 1, 0)
// CHECK: %"class.hlsl::RWStructuredBuffer.9" = type { target("dx.RawBuffer", double, 1, 0)
// CHECK: %"class.hlsl::RWStructuredBuffer.10" = type { target("dx.RawBuffer", <4 x i16>, 1, 0)
// CHECK: %"class.hlsl::RWStructuredBuffer.11" = type { target("dx.RawBuffer", <3 x i32>, 1, 0)
// CHECK: %"class.hlsl::RWStructuredBuffer.12" = type { target("dx.RawBuffer", <2 x half>, 1, 0)
// CHECK: %"class.hlsl::RWStructuredBuffer.13" = type { target("dx.RawBuffer", <3 x float>, 1, 0)

RWStructuredBuffer<int16_t> BufI16;
RWStructuredBuffer<uint16_t> BufU16;
RWStructuredBuffer<int> BufI32;
RWStructuredBuffer<uint> BufU32;
RWStructuredBuffer<int64_t> BufI64;
RWStructuredBuffer<uint64_t> BufU64;
RWStructuredBuffer<half> BufF16;
RWStructuredBuffer<float> BufF32;
RWStructuredBuffer<double> BufF64;
RWStructuredBuffer< vector<int16_t, 4> > BufI16x4;
RWStructuredBuffer< vector<uint, 3> > BufU32x3;
RWStructuredBuffer<half2> BufF16x2;
RWStructuredBuffer<float3> BufF32x3;
// TODO: RWStructuredBuffer<snorm half> BufSNormF16;
// TODO: RWStructuredBuffer<unorm half> BufUNormF16;
// TODO: RWStructuredBuffer<snorm float> BufSNormF32;
// TODO: RWStructuredBuffer<unorm float> BufUNormF32;
// TODO: RWStructuredBuffer<snorm double> BufSNormF64;
// TODO: RWStructuredBuffer<unorm double> BufUNormF64;

[numthreads(1,1,1)]
void main(int GI : SV_GroupIndex) {
BufI16[GI] = 0;
BufU16[GI] = 0;
BufI32[GI] = 0;
BufU32[GI] = 0;
BufI64[GI] = 0;
BufU64[GI] = 0;
BufF16[GI] = 0;
BufF32[GI] = 0;
BufF64[GI] = 0;
BufI16x4[GI] = 0;
BufU32x3[GI] = 0;
BufF16x2[GI] = 0;
BufF32x3[GI] = 0;
}

// CHECK: !{{[0-9]+}} = !{ptr @BufI16, i32 10, i32 2,
// CHECK: !{{[0-9]+}} = !{ptr @BufU16, i32 10, i32 3,
// CHECK: !{{[0-9]+}} = !{ptr @BufI32, i32 10, i32 4,
// CHECK: !{{[0-9]+}} = !{ptr @BufU32, i32 10, i32 5,
// CHECK: !{{[0-9]+}} = !{ptr @BufI64, i32 10, i32 6,
// CHECK: !{{[0-9]+}} = !{ptr @BufU64, i32 10, i32 7,
// CHECK: !{{[0-9]+}} = !{ptr @BufF16, i32 10, i32 8,
// CHECK: !{{[0-9]+}} = !{ptr @BufF32, i32 10, i32 9,
// CHECK: !{{[0-9]+}} = !{ptr @BufF64, i32 10, i32 10,
// CHECK: !{{[0-9]+}} = !{ptr @BufI16x4, i32 10, i32 2,
// CHECK: !{{[0-9]+}} = !{ptr @BufU32x3, i32 10, i32 5,
// CHECK: !{{[0-9]+}} = !{ptr @BufF16x2, i32 10, i32 8,
// CHECK: !{{[0-9]+}} = !{ptr @BufF32x3, i32 10, i32 9,
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ StructuredBuffer< vector<int16_t, 4> > BufI16x4;
StructuredBuffer< vector<uint, 3> > BufU32x3;
StructuredBuffer<half2> BufF16x2;
StructuredBuffer<float3> BufF32x3;
// TODO: StructuredBuffer<snorm half> BufSNormF16; -> 11
// TODO: StructuredBuffer<unorm half> BufUNormF16; -> 12
// TODO: StructuredBuffer<snorm float> BufSNormF32; -> 13
// TODO: StructuredBuffer<unorm float> BufUNormF32; -> 14
// TODO: StructuredBuffer<snorm double> BufSNormF64; -> 15
// TODO: StructuredBuffer<unorm double> BufUNormF64; -> 16
// TODO: StructuredBuffer<snorm half> BufSNormF16;
// TODO: StructuredBuffer<unorm half> BufUNormF16;
// TODO: StructuredBuffer<snorm float> BufSNormF32;
// TODO: StructuredBuffer<unorm float> BufUNormF32;
// TODO: StructuredBuffer<snorm double> BufSNormF64;
// TODO: StructuredBuffer<unorm double> BufUNormF64;

[numthreads(1,1,1)]
void main(int GI : SV_GroupIndex) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,30 @@
// NOTE: SPIRV codegen for resource types is not yet implemented

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

// CHECK: %"class.hlsl::StructuredBuffer" = type { target("dx.RawBuffer", float, 0, 0), float }
// CHECK: %"class.hlsl::RWStructuredBuffer" = type { target("dx.RawBuffer", float, 1, 0), float }

// CHECK: @Buf = global %"class.hlsl::StructuredBuffer" zeroinitializer, align 4
// CHECK: @Buf2 = global %"class.hlsl::RWStructuredBuffer" zeroinitializer, align 4

// CHECK: define linkonce_odr void @_ZN4hlsl16StructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(8) %this)
// CHECK-NEXT: entry:

// CHECK: define internal void @_GLOBAL__sub_I_StructuredBuffer_constructor.hlsl()
// CHECK: define linkonce_odr void @_ZN4hlsl18RWStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(8) %this)
// CHECK-NEXT: entry:
// CHECK-NEXT: call void @__cxx_global_var_init()
// CHECK-NEXT: call void @_init_resource_bindings()

// CHECK: define internal void @_GLOBAL__sub_I_StructuredBuffers_constructors.hlsl()
// CHECK: entry:
// CHECK: call void @_init_resource_bindings()

// CHECK: define internal void @_init_resource_bindings() {
// CHECK-NEXT: entry:
// 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)
// CHECK-DXIL-NEXT: store target("dx.RawBuffer", float, 0, 0) %Buf_h, ptr @Buf, align 4
// 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)
// CHECK-DXIL-NEXT: store target("dx.RawBuffer", float, 1, 0) %Buf2_h, ptr @Buf2, align 4
// 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)
// CHECK-SPIRV-NEXT: store target("dx.RawBuffer", float, 0, 0) %Buf_h, ptr @Buf", align 4
// 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)
// CHECK-SPIRV-NEXT: store target("dx.RawBuffer", float, 1, 0) %Buf2_h, ptr @Buf2", align 4
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -emit-llvm -o - -O0 %s | FileCheck %s

// FIXME: This tests will fail once StructuredBuffer subscript operator is properly
// implemented (llvm-project/llvm#112977). StructuredBuffer is a read-only resource
// and the result of a subscript operator cannot be assigned to.

StructuredBuffer<int> In;
StructuredBuffer<int> Out;
RWStructuredBuffer<int> Out;

[numthreads(1,1,1)]
void main(unsigned GI : SV_GroupIndex) {
Expand Down
Loading