Author: Helena Kotas Date: 2024-09-16T19:35:24-07:00 New Revision: 5df1b79372a89648cdb4ab798f1c74985e00ac6e
URL: https://github.com/llvm/llvm-project/commit/5df1b79372a89648cdb4ab798f1c74985e00ac6e DIFF: https://github.com/llvm/llvm-project/commit/5df1b79372a89648cdb4ab798f1c74985e00ac6e.diff LOG: [HLSL] Add `[[hlsl::raw_buffer]]` attribute (#107954) This PR introduces new HLSL resource type attribute `[[hlsl::raw_buffer]]`. Presence of this attribute on a resource handle means that the resource does not require typed element access. The attribute will be used on resource handles that represent buffers like `StructuredBuffer` or `ByteAddressBuffer` and in DXIL it will be translated to target extension type `dx.RawBuffer`. Fixes #107907 Added: clang/test/ParserHLSL/hlsl_raw_buffer_attr.hlsl clang/test/ParserHLSL/hlsl_raw_buffer_attr_error.hlsl Modified: clang/include/clang/AST/Type.h clang/include/clang/AST/TypeProperties.td clang/include/clang/Basic/Attr.td clang/lib/AST/ASTStructuralEquivalence.cpp clang/lib/AST/TypePrinter.cpp clang/lib/Sema/HLSLExternalSemaSource.cpp clang/lib/Sema/SemaHLSL.cpp clang/lib/Sema/SemaType.cpp clang/test/AST/HLSL/StructuredBuffer-AST.hlsl Removed: ################################################################################ diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index ef36a73716454f..dc87b84153e74a 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -6168,10 +6168,18 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode { struct Attributes { // Data gathered from HLSL resource attributes llvm::dxil::ResourceClass ResourceClass; + + LLVM_PREFERRED_TYPE(bool) uint8_t IsROV : 1; - Attributes(llvm::dxil::ResourceClass ResourceClass, bool IsROV) - : ResourceClass(ResourceClass), IsROV(IsROV) {} - Attributes() : ResourceClass(llvm::dxil::ResourceClass::UAV), IsROV(0) {} + + LLVM_PREFERRED_TYPE(bool) + uint8_t RawBuffer : 1; + + Attributes(llvm::dxil::ResourceClass ResourceClass, bool IsROV, + bool RawBuffer) + : ResourceClass(ResourceClass), IsROV(IsROV), RawBuffer(RawBuffer) {} + + Attributes() : Attributes(llvm::dxil::ResourceClass::UAV, false, false) {} }; private: @@ -6204,6 +6212,7 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode { ID.AddPointer(Contained.getAsOpaquePtr()); ID.AddInteger(static_cast<uint32_t>(Attrs.ResourceClass)); ID.AddBoolean(Attrs.IsROV); + ID.AddBoolean(Attrs.RawBuffer); } static bool classof(const Type *T) { diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td index 539a344cb0b690..bb7bfa8cd0b76e 100644 --- a/clang/include/clang/AST/TypeProperties.td +++ b/clang/include/clang/AST/TypeProperties.td @@ -697,6 +697,9 @@ let Class = HLSLAttributedResourceType in { def : Property<"isROV", Bool> { let Read = [{ node->getAttrs().IsROV }]; } + def : Property<"rawBuffer", Bool> { + let Read = [{ node->getAttrs().RawBuffer }]; + } def : Property<"wrappedTy", QualType> { let Read = [{ node->getWrappedType() }]; } @@ -704,7 +707,7 @@ let Class = HLSLAttributedResourceType in { let Read = [{ node->getContainedType() }]; } def : Creator<[{ - HLSLAttributedResourceType::Attributes attrs(static_cast<llvm::dxil::ResourceClass>(resClass), isROV); + HLSLAttributedResourceType::Attributes attrs(static_cast<llvm::dxil::ResourceClass>(resClass), isROV, rawBuffer); return ctx.getHLSLAttributedResourceType(wrappedTy, containedTy, attrs); }]>; } diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 3c90dd156fecf5..35b9716e13ff21 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4674,6 +4674,12 @@ def HLSLContainedType : TypeAttr { let Documentation = [InternalOnly]; } +def HLSLRawBuffer : TypeAttr { + let Spellings = [CXX11<"hlsl", "raw_buffer">]; + let LangOpts = [HLSL]; + let Documentation = [InternalOnly]; +} + def HLSLGroupSharedAddressSpace : TypeAttr { let Spellings = [CustomKeyword<"groupshared">]; let Subjects = SubjectList<[Var]>; diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index f13ca2d08d769f..21f0562f9d72ae 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -808,8 +808,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, const HLSLAttributedResourceType::Attributes &Attrs1, const HLSLAttributedResourceType::Attributes &Attrs2) { - return std::tie(Attrs1.ResourceClass, Attrs1.IsROV) == - std::tie(Attrs2.ResourceClass, Attrs2.IsROV); + return std::tie(Attrs1.ResourceClass, Attrs1.IsROV, Attrs1.RawBuffer) == + std::tie(Attrs2.ResourceClass, Attrs2.IsROV, Attrs2.RawBuffer); } /// Determine structural equivalence of two types. diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 8b943f01519ddc..ca75bb97c158e1 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1945,6 +1945,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, case attr::HLSLResourceClass: case attr::HLSLROV: + case attr::HLSLRawBuffer: case attr::HLSLContainedType: llvm_unreachable("HLSL resource type attributes handled separately"); @@ -2079,6 +2080,8 @@ void TypePrinter::printHLSLAttributedResourceAfter( << ")]]"; if (Attrs.IsROV) OS << " [[hlsl::is_rov]]"; + if (Attrs.RawBuffer) + OS << " [[hlsl::raw_buffer]]"; QualType ContainedTy = T->getContainedType(); if (!ContainedTy.isNull()) { diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp index 444303dfd57faf..d19f79b6ddefcd 100644 --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -112,6 +112,7 @@ struct BuiltinTypeDeclBuilder { BuiltinTypeDeclBuilder & addHandleMember(Sema &S, ResourceClass RC, ResourceKind RK, bool IsROV, + bool RawBuffer, AccessSpecifier Access = AccessSpecifier::AS_private) { if (Record->isCompleteDefinition()) return *this; @@ -135,10 +136,11 @@ struct BuiltinTypeDeclBuilder { SmallVector<const Attr *> Attrs = { HLSLResourceClassAttr::CreateImplicit(Record->getASTContext(), RC), IsROV ? HLSLROVAttr::CreateImplicit(Record->getASTContext()) : nullptr, + RawBuffer ? HLSLRawBufferAttr::CreateImplicit(Record->getASTContext()) + : nullptr, ElementTypeInfo ? HLSLContainedTypeAttr::CreateImplicit( Record->getASTContext(), ElementTypeInfo) - : nullptr, - }; + : nullptr}; Attr *ResourceAttr = HLSLResourceAttr::CreateImplicit(Record->getASTContext(), RK); if (CreateHLSLAttributedResourceType(S, Ty, Attrs, AttributedResTy)) @@ -507,9 +509,9 @@ void HLSLExternalSemaSource::defineTrivialHLSLTypes() { /// Set up common members and attributes for buffer types static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S, ResourceClass RC, ResourceKind RK, - bool IsROV) { + bool IsROV, bool RawBuffer) { return BuiltinTypeDeclBuilder(Decl) - .addHandleMember(S, RC, RK, IsROV) + .addHandleMember(S, RC, RK, IsROV, RawBuffer) .addDefaultHandleConstructor(S, RC); } @@ -522,7 +524,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { onCompletion(Decl, [this](CXXRecordDecl *Decl) { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::TypedBuffer, - /*IsROV=*/false) + /*IsROV=*/false, /*RawBuffer=*/false) .addArraySubscriptOperators() .completeDefinition(); }); @@ -533,7 +535,8 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { .Record; onCompletion(Decl, [this](CXXRecordDecl *Decl) { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, - ResourceKind::TypedBuffer, /*IsROV=*/true) + ResourceKind::TypedBuffer, /*IsROV=*/true, + /*RawBuffer=*/false) .addArraySubscriptOperators() .completeDefinition(); }); @@ -543,7 +546,8 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { .Record; onCompletion(Decl, [this](CXXRecordDecl *Decl) { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, - ResourceKind::TypedBuffer, /*IsROV=*/false) + ResourceKind::TypedBuffer, /*IsROV=*/false, + /*RawBuffer=*/true) .addArraySubscriptOperators() .completeDefinition(); }); diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 26de9a986257c5..98c9d25327270e 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -577,7 +577,7 @@ bool clang::CreateHLSLAttributedResourceType( SourceLocation LocBegin = AttrList[0]->getRange().getBegin(); SourceLocation LocEnd = AttrList[0]->getRange().getEnd(); - HLSLAttributedResourceType::Attributes ResAttrs = {}; + HLSLAttributedResourceType::Attributes ResAttrs; bool HasResourceClass = false; for (const Attr *A : AttrList) { @@ -606,6 +606,13 @@ bool clang::CreateHLSLAttributedResourceType( } ResAttrs.IsROV = true; break; + case attr::HLSLRawBuffer: + if (ResAttrs.RawBuffer) { + S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A; + return false; + } + ResAttrs.RawBuffer = true; + break; case attr::HLSLContainedType: { const HLSLContainedTypeAttr *CTAttr = cast<HLSLContainedTypeAttr>(A); QualType Ty = CTAttr->getType(); @@ -679,6 +686,10 @@ bool SemaHLSL::handleResourceTypeAttr(const ParsedAttr &AL) { A = HLSLROVAttr::Create(getASTContext(), AL.getLoc()); break; + case ParsedAttr::AT_HLSLRawBuffer: + A = HLSLRawBufferAttr::Create(getASTContext(), AL.getLoc()); + break; + case ParsedAttr::AT_HLSLContainedType: { if (AL.getNumArgs() != 1 && !AL.hasParsedType()) { Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 04b23ccf53c01c..11adfb0d7f3e98 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -8846,6 +8846,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, } case ParsedAttr::AT_HLSLResourceClass: case ParsedAttr::AT_HLSLROV: + case ParsedAttr::AT_HLSLRawBuffer: case ParsedAttr::AT_HLSLContainedType: { // Only collect HLSL resource type attributes that are in // decl-specifier-seq; do not collect attributes on declarations or those diff --git a/clang/test/AST/HLSL/StructuredBuffer-AST.hlsl b/clang/test/AST/HLSL/StructuredBuffer-AST.hlsl index 821b29ace81d2d..e50ba6a4b5b346 100644 --- a/clang/test/AST/HLSL/StructuredBuffer-AST.hlsl +++ b/clang/test/AST/HLSL/StructuredBuffer-AST.hlsl @@ -30,7 +30,7 @@ StructuredBuffer<float> Buffer; // CHECK-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit class StructuredBuffer 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 'element_type * {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::contained_type(element_type)]]':'element_type *' +// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit h 'element_type * {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::raw_buffer]] {{\[\[}}hlsl::contained_type(element_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' @@ -38,7 +38,7 @@ StructuredBuffer<float> Buffer; // CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> // CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> // CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue -// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type * {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::contained_type(element_type)]]':'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type * {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::raw_buffer]] {{\[\[}}hlsl::contained_type(element_type)]]':'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}} // CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'const StructuredBuffer<element_type>' lvalue implicit this // CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Idx' 'unsigned int' // CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline @@ -48,7 +48,7 @@ StructuredBuffer<float> Buffer; // CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> // CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> // CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue -// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type * {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::contained_type(element_type)]]':'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type * {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::raw_buffer]] {{\[\[}}hlsl::contained_type(element_type)]]':'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}} // CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'StructuredBuffer<element_type>' lvalue implicit this // CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Idx' 'unsigned int' // CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline @@ -58,5 +58,5 @@ StructuredBuffer<float> Buffer; // CHECK: TemplateArgument type 'float' // CHECK-NEXT: BuiltinType 0x{{[0-9A-Fa-f]+}} 'float' // 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 referenced h 'float * {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::contained_type(float)]]':'float *' +// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit referenced h 'float * {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::raw_buffer]] {{\[\[}}hlsl::contained_type(float)]]':'float *' // CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer diff --git a/clang/test/ParserHLSL/hlsl_raw_buffer_attr.hlsl b/clang/test/ParserHLSL/hlsl_raw_buffer_attr.hlsl new file mode 100644 index 00000000000000..1955be63cf7607 --- /dev/null +++ b/clang/test/ParserHLSL/hlsl_raw_buffer_attr.hlsl @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -o - %s | FileCheck %s + +// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} struct MyBuffer definition +// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:6:3, col:72> col:72 h1 '__hlsl_resource_t {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::raw_buffer]]':'__hlsl_resource_t' +struct MyBuffer { + __hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::raw_buffer]] h1; +}; + +// CHECK: VarDecl 0x{{[0-9a-f]+}} <line:10:1, col:70> col:70 h2 '__hlsl_resource_t {{\[\[}}hlsl::resource_class(SRV)]] {{\[\[}}hlsl::raw_buffer]]':'__hlsl_resource_t' +__hlsl_resource_t [[hlsl::raw_buffer]] [[hlsl::resource_class(SRV)]] h2; + +// CHECK: FunctionDecl 0x{{[0-9a-f]+}} <line:14:1, line:16:1> line:14:6 f 'void () +// CHECK: VarDecl 0x{{[0-9a-f]+}} <col:3, col:72> col:72 h3 '__hlsl_resource_t {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::raw_buffer]]':'__hlsl_resource_t' +void f() { + __hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::raw_buffer]] h3; +} diff --git a/clang/test/ParserHLSL/hlsl_raw_buffer_attr_error.hlsl b/clang/test/ParserHLSL/hlsl_raw_buffer_attr_error.hlsl new file mode 100644 index 00000000000000..83273426017ed0 --- /dev/null +++ b/clang/test/ParserHLSL/hlsl_raw_buffer_attr_error.hlsl @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -o - %s -verify + +// expected-error@+1{{'raw_buffer' attribute cannot be applied to a declaration}} +[[hlsl::raw_buffer]] __hlsl_resource_t res0; + +// expected-error@+1{{'raw_buffer' attribute takes no arguments}} +__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::raw_buffer(3)]] res2; + +// expected-error@+1{{use of undeclared identifier 'gibberish'}} +__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::raw_buffer(gibberish)]] res3; + +// expected-warning@+1{{attribute 'raw_buffer' is already applied}} +__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::raw_buffer]] [[hlsl::raw_buffer]] res4; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits