From 5dc371e289584928345f74f560a18a805226b5f8 Mon Sep 17 00:00:00 2001 From: Joshua Batista Date: Fri, 12 Jul 2024 13:10:34 -0700 Subject: [PATCH] [HLSL] Split out resource class data from resource attribute (#98419) The ability to spell out and specify the resource class is necessary for testing various resource binding behaviors. Though it is not intended for users to use this in customized HLSL source code, the ability to specify the resource class via an attribute is immensely helpful for writing thorough tests. This PR introduces a new attribute, hlsl::resource_attribute, that can only be applied on structs. This attribute only has 1 required argument, and must be one of: ``` SRV UAV CBuffer Sampler ``` By applying this attribute to a struct, the struct will have the `HLSLResourceClassAttr` attribute attached to it in the AST representation, which provides information on the type of resource class the struct is meant to be. The resource class data that was originally contained within the `HLSLResourceAttr` attribute has been removed in favor of this new attribute, and so certain ast-dump tests need to be modified so that the same information can be represented via 2 attributes instead of one. Fixes #98193 --------- Co-authored-by: Damyan Pepper --- clang/include/clang/Basic/Attr.td | 19 ++++++++--- clang/include/clang/Sema/SemaHLSL.h | 1 + clang/lib/CodeGen/CGHLSLRuntime.cpp | 11 ++++--- clang/lib/Sema/HLSLExternalSemaSource.cpp | 13 ++++---- clang/lib/Sema/SemaDeclAttr.cpp | 3 ++ clang/lib/Sema/SemaHLSL.cpp | 22 +++++++++++++ clang/test/AST/HLSL/RWBuffer-AST.hlsl | 6 ++-- ...a-attribute-supported-attributes-list.test | 1 + .../ParserHLSL/hlsl_resource_class_attr.hlsl | 32 +++++++++++++++++++ .../hlsl_resource_class_attr_error.hlsl | 15 +++++++++ 10 files changed, 105 insertions(+), 18 deletions(-) create mode 100644 clang/test/ParserHLSL/hlsl_resource_class_attr.hlsl create mode 100644 clang/test/ParserHLSL/hlsl_resource_class_attr_error.hlsl diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 6d80f0a0a65863..1293d0ddbc117d 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4561,11 +4561,7 @@ def HLSLResource : InheritableAttr { let Spellings = []; let Subjects = SubjectList<[Struct]>; let LangOpts = [HLSL]; - let Args = [ - EnumArgument<"ResourceClass", "llvm::hlsl::ResourceClass", - /*is_string=*/0, ["SRV", "UAV", "CBuffer", "Sampler"], - ["SRV", "UAV", "CBuffer", "Sampler"], - /*opt=*/0, /*fake=*/0, /*isExternalType=*/1>, + let Args = [ EnumArgument< "ResourceKind", "llvm::hlsl::ResourceKind", /*is_string=*/0, @@ -4589,6 +4585,19 @@ def HLSLResource : InheritableAttr { let Documentation = [InternalOnly]; } +def HLSLResourceClass : InheritableAttr { + let Spellings = [CXX11<"hlsl", "resource_class">]; + let Subjects = SubjectList<[Struct]>; + let LangOpts = [HLSL]; + let Args = [ + EnumArgument<"ResourceClass", "llvm::hlsl::ResourceClass", + /*is_string=*/true, ["SRV", "UAV", "CBuffer", "Sampler"], + ["SRV", "UAV", "CBuffer", "Sampler"], + /*opt=*/0, /*fake=*/0, /*isExternalType=*/1> + ]; + let Documentation = [InternalOnly]; +} + def HLSLGroupSharedAddressSpace : TypeAttr { let Spellings = [CustomKeyword<"groupshared">]; let Subjects = SubjectList<[Var]>; diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index 4d6958a1be3e5b..2ddbee67c414bb 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -56,6 +56,7 @@ class SemaHLSL : public SemaBase { void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL); void handlePackOffsetAttr(Decl *D, const ParsedAttr &AL); void handleShaderAttr(Decl *D, const ParsedAttr &AL); + void handleResourceClassAttr(Decl *D, const ParsedAttr &AL); void handleResourceBindingAttr(Decl *D, const ParsedAttr &AL); void handleParamModifierAttr(Decl *D, const ParsedAttr &AL); diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index 55ba21ae2ba69b..6a6aff594fb0ff 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -280,13 +280,14 @@ void CGHLSLRuntime::annotateHLSLResource(const VarDecl *D, GlobalVariable *GV) { const auto *RD = Ty->getAsCXXRecordDecl(); if (!RD) return; - const auto *Attr = RD->getAttr(); - if (!Attr) + const auto *HLSLResAttr = RD->getAttr(); + const auto *HLSLResClassAttr = RD->getAttr(); + if (!HLSLResAttr || !HLSLResClassAttr) return; - llvm::hlsl::ResourceClass RC = Attr->getResourceClass(); - llvm::hlsl::ResourceKind RK = Attr->getResourceKind(); - bool IsROV = Attr->getIsROV(); + llvm::hlsl::ResourceClass RC = HLSLResClassAttr->getResourceClass(); + llvm::hlsl::ResourceKind RK = HLSLResAttr->getResourceKind(); + bool IsROV = HLSLResAttr->getIsROV(); llvm::hlsl::ElementType ET = calculateElementType(CGM.getContext(), Ty); BufferResBinding Binding(D->getAttr()); diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp index a2b29a7bdf505c..7fcf5754f9dd73 100644 --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -115,12 +115,14 @@ struct BuiltinTypeDeclBuilder { return addMemberVariable("h", Ty, Access); } - BuiltinTypeDeclBuilder &annotateResourceClass(ResourceClass RC, - ResourceKind RK, bool IsROV) { + BuiltinTypeDeclBuilder &annotateHLSLResource(ResourceClass RC, + ResourceKind RK, bool IsROV) { if (Record->isCompleteDefinition()) return *this; - Record->addAttr(HLSLResourceAttr::CreateImplicit(Record->getASTContext(), - RC, RK, IsROV)); + Record->addAttr( + HLSLResourceClassAttr::CreateImplicit(Record->getASTContext(), RC)); + Record->addAttr( + HLSLResourceAttr::CreateImplicit(Record->getASTContext(), RK, IsROV)); return *this; } @@ -171,7 +173,6 @@ struct BuiltinTypeDeclBuilder { DeclRefExpr *Fn = lookupBuiltinFunction(AST, S, "__builtin_hlsl_create_handle"); - Expr *RCExpr = emitResourceClassExpr(AST, RC); Expr *Call = CallExpr::Create(AST, Fn, {RCExpr}, AST.VoidPtrTy, VK_PRValue, SourceLocation(), FPOptionsOverride()); @@ -496,7 +497,7 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S, return BuiltinTypeDeclBuilder(Decl) .addHandleMember() .addDefaultHandleConstructor(S, RC) - .annotateResourceClass(RC, RK, IsROV); + .annotateHLSLResource(RC, RK, IsROV); } void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index f2cd46d1e7c932..20f46c003a464a 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -7053,6 +7053,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_HLSLResourceBinding: S.HLSL().handleResourceBindingAttr(D, AL); break; + case ParsedAttr::AT_HLSLResourceClass: + S.HLSL().handleResourceClassAttr(D, AL); + break; case ParsedAttr::AT_HLSLParamModifier: S.HLSL().handleParamModifierAttr(D, AL); break; diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index babb984995f133..9940bc5b4a606a 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -437,6 +437,28 @@ void SemaHLSL::handleShaderAttr(Decl *D, const ParsedAttr &AL) { D->addAttr(NewAttr); } +void SemaHLSL::handleResourceClassAttr(Decl *D, const ParsedAttr &AL) { + if (!AL.isArgIdent(0)) { + Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIdentifier; + return; + } + + IdentifierLoc *Loc = AL.getArgAsIdent(0); + StringRef Identifier = Loc->Ident->getName(); + SourceLocation ArgLoc = Loc->Loc; + + // Validate. + llvm::dxil::ResourceClass RC; + if (!HLSLResourceClassAttr::ConvertStrToResourceClass(Identifier, RC)) { + Diag(ArgLoc, diag::warn_attribute_type_not_supported) + << "ResourceClass" << Identifier; + return; + } + + D->addAttr(HLSLResourceClassAttr::Create(getASTContext(), RC, ArgLoc)); +} + void SemaHLSL::handleResourceBindingAttr(Decl *D, const ParsedAttr &AL) { StringRef Space = "space0"; StringRef Slot = ""; diff --git a/clang/test/AST/HLSL/RWBuffer-AST.hlsl b/clang/test/AST/HLSL/RWBuffer-AST.hlsl index ac54194be7f0dd..cb66a703a4ec98 100644 --- a/clang/test/AST/HLSL/RWBuffer-AST.hlsl +++ b/clang/test/AST/HLSL/RWBuffer-AST.hlsl @@ -34,7 +34,8 @@ RWBuffer Buffer; // CHECK-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <> implicit class RWBuffer definition // CHECK: FinalAttr 0x{{[0-9A-Fa-f]+}} <> Implicit final -// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <> Implicit UAV TypedBuffer +// CHECK-NEXT: HLSLResourceClassAttr 0x{{[0-9A-Fa-f]+}} <> Implicit UAV +// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <> Implicit TypedBuffer // CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <> implicit h 'element_type *' // CHECK: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <> operator[] 'element_type &const (unsigned int) const' @@ -62,5 +63,6 @@ RWBuffer Buffer; // CHECK: TemplateArgument type 'float' // CHECK-NEXT: BuiltinType 0x{{[0-9A-Fa-f]+}} 'float' // CHECK-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <> Implicit final -// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <> Implicit UAV TypedBuffer +// CHECK-NEXT: HLSLResourceClassAttr 0x{{[0-9A-Fa-f]+}} <> Implicit UAV +// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <> Implicit TypedBuffer // CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <> implicit referenced h 'float *' diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test index 28df04c5e33ef4..33f9c2f51363c6 100644 --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -81,6 +81,7 @@ // CHECK-NEXT: FunctionReturnThunks (SubjectMatchRule_function) // CHECK-NEXT: GNUInline (SubjectMatchRule_function) // CHECK-NEXT: HIPManaged (SubjectMatchRule_variable) +// CHECK-NEXT: HLSLResourceClass (SubjectMatchRule_record_not_is_union) // CHECK-NEXT: Hot (SubjectMatchRule_function) // CHECK-NEXT: IBAction (SubjectMatchRule_objc_method_is_instance) // CHECK-NEXT: IFunc (SubjectMatchRule_function) diff --git a/clang/test/ParserHLSL/hlsl_resource_class_attr.hlsl b/clang/test/ParserHLSL/hlsl_resource_class_attr.hlsl new file mode 100644 index 00000000000000..410b4524f1c3df --- /dev/null +++ b/clang/test/ParserHLSL/hlsl_resource_class_attr.hlsl @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -o - %s | FileCheck %s + + +// CHECK: -HLSLResourceClassAttr 0x{{[0-9a-f]+}} SRV +struct [[hlsl::resource_class(SRV)]] Eg1 { + int i; +}; + +Eg1 e1; + +// CHECK: -CXXRecordDecl 0x{{[0-9a-f]+}} line:13:38 referenced struct Eg2 definition +// CHECK: -HLSLResourceClassAttr 0x{{[0-9a-f]+}} UAV +struct [[hlsl::resource_class(UAV)]] Eg2 { + int i; +}; +Eg2 e2; + +// CHECK: -CXXRecordDecl 0x{{[0-9a-f]+}} line:20:42 referenced struct Eg3 definition +// CHECK: -HLSLResourceClassAttr 0x{{[0-9a-f]+}} CBuffer +struct [[hlsl::resource_class(CBuffer)]] Eg3 { + int i; +}; +Eg3 e3; + +// CHECK: -CXXRecordDecl 0x{{[0-9a-f]+}} line:27:42 referenced struct Eg4 definition +// CHECK: -HLSLResourceClassAttr 0x{{[0-9a-f]+}} Sampler +struct [[hlsl::resource_class(Sampler)]] Eg4 { + int i; +}; +Eg4 e4; + +RWBuffer In : register(u1); diff --git a/clang/test/ParserHLSL/hlsl_resource_class_attr_error.hlsl b/clang/test/ParserHLSL/hlsl_resource_class_attr_error.hlsl new file mode 100644 index 00000000000000..00fcd769760bba --- /dev/null +++ b/clang/test/ParserHLSL/hlsl_resource_class_attr_error.hlsl @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -o - %s -verify + +// expected-error@+1{{'resource_class' attribute takes one argument}} +struct [[hlsl::resource_class()]] Eg1 { + int i; +}; + +Eg1 e1; + +// expected-warning@+1{{ResourceClass attribute argument not supported: gibberish}} +struct [[hlsl::resource_class(gibberish)]] Eg2 { + int i; +}; + +Eg2 e2;