https://github.com/hekota created https://github.com/llvm/llvm-project/pull/107954
This PR introduces new HLSL resource type attribute `[[hlsl::row_access]]`. Presence of this attribute on a resource handle means that the resource must be accessed in 16-byte blocks at-a-time, or four 32-bit components, also known as rows. This information is necessary in order to properly distinguish between handles for typed buffer types (like `RWBuffer<float4>`) which require row-level access and will be translated to target extension type `dx.TypedBuffer` versus buffer types that do not have this access constraint (like `RWStructuredBuffer<float4>`) and will be using target ext. type `dx.RawBuffer`. Fixes #107907 >From 1c66d2767ca20f42b6edaae834cc186be7d23712 Mon Sep 17 00:00:00 2001 From: Helena Kotas <heko...@microsoft.com> Date: Mon, 9 Sep 2024 19:39:02 -0700 Subject: [PATCH] [HLSL] Add `[[hlsl::row_access]]` attribute This PR introduces new HLSL resource type attribute [[hlsl::row_access]]. Presence of this attribute means that the resource must be accessed in 16-byte blocks at-a-time, or four 32-bit components, also knows as rows. This information is necessary in order to properly distinguish between a typed buffer like `RWBuffer<float4>` which is translated to `dx.TypedBuffer` vs. `RWStructuredBuffer<float4>` which does not have this access constraint and will be translated to `dx.RawBuffer`. Fixes #107907 --- clang/include/clang/AST/Type.h | 11 ++++++++--- clang/include/clang/AST/TypeProperties.td | 5 ++++- clang/include/clang/Basic/Attr.td | 6 ++++++ clang/lib/AST/ASTStructuralEquivalence.cpp | 4 ++-- clang/lib/AST/TypePrinter.cpp | 3 +++ clang/lib/Sema/HLSLExternalSemaSource.cpp | 14 +++++++++----- clang/lib/Sema/SemaHLSL.cpp | 6 ++++++ clang/lib/Sema/SemaType.cpp | 3 ++- .../ParserHLSL/hlsl_resource_handle_attrs.hlsl | 4 ++-- clang/test/ParserHLSL/hlsl_row_access_attr.hlsl | 16 ++++++++++++++++ .../ParserHLSL/hlsl_row_access_attr_error.hlsl | 16 ++++++++++++++++ 11 files changed, 74 insertions(+), 14 deletions(-) create mode 100644 clang/test/ParserHLSL/hlsl_row_access_attr.hlsl create mode 100644 clang/test/ParserHLSL/hlsl_row_access_attr_error.hlsl diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index ef36a73716454f..d8336e1960c64e 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -6169,9 +6169,13 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode { // Data gathered from HLSL resource attributes llvm::dxil::ResourceClass ResourceClass; uint8_t IsROV : 1; - Attributes(llvm::dxil::ResourceClass ResourceClass, bool IsROV) - : ResourceClass(ResourceClass), IsROV(IsROV) {} - Attributes() : ResourceClass(llvm::dxil::ResourceClass::UAV), IsROV(0) {} + uint8_t RowAccess : 1; + Attributes(llvm::dxil::ResourceClass ResourceClass, bool IsROV, + bool RowAccess) + : ResourceClass(ResourceClass), IsROV(IsROV), RowAccess(RowAccess) {} + Attributes() + : ResourceClass(llvm::dxil::ResourceClass::UAV), IsROV(0), + RowAccess(0) {} }; private: @@ -6204,6 +6208,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.RowAccess); } static bool classof(const Type *T) { diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td index 539a344cb0b690..f310996d144959 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<"rowAccess", Bool> { + let Read = [{ node->getAttrs().RowAccess }]; + } 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, rowAccess); return ctx.getHLSLAttributedResourceType(wrappedTy, containedTy, attrs); }]>; } diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 9a7b163b2c6da8..7edf33dee93d0a 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4669,6 +4669,12 @@ def HLSLResourceClass : TypeAttr { let Documentation = [InternalOnly]; } +def HLSLRowAccess : TypeAttr { + let Spellings = [CXX11<"hlsl", "row_access">]; + 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..9896e0f48aed58 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.RowAccess) == + std::tie(Attrs2.ResourceClass, Attrs2.IsROV, Attrs2.RowAccess); } /// Determine structural equivalence of two types. diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index add6a5d10d61f7..61cd88dd642509 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::HLSLRowAccess: llvm_unreachable("HLSL resource type attributes handled separately"); case attr::OpenCLPrivateAddressSpace: @@ -2078,6 +2079,8 @@ void TypePrinter::printHLSLAttributedResourceAfter( << ")]]"; if (Attrs.IsROV) OS << " [[hlsl::is_rov()]]"; + if (Attrs.RowAccess) + OS << " [[hlsl::row_access]]"; } void TypePrinter::printObjCInterfaceBefore(const ObjCInterfaceType *T, diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp index 071e64fe56d48a..1722bb6aba84e6 100644 --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -111,6 +111,7 @@ struct BuiltinTypeDeclBuilder { BuiltinTypeDeclBuilder & addHandleMember(Sema &S, ResourceClass RC, ResourceKind RK, bool IsROV, + bool RowAccess, AccessSpecifier Access = AccessSpecifier::AS_private) { if (Record->isCompleteDefinition()) return *this; @@ -126,7 +127,9 @@ struct BuiltinTypeDeclBuilder { QualType AttributedResTy = QualType(); SmallVector<const Attr *> Attrs = { HLSLResourceClassAttr::CreateImplicit(Record->getASTContext(), RC), - IsROV ? HLSLROVAttr::CreateImplicit(Record->getASTContext()) : nullptr}; + IsROV ? HLSLROVAttr::CreateImplicit(Record->getASTContext()) : nullptr, + RowAccess ? HLSLRowAccessAttr::CreateImplicit(Record->getASTContext()) + : nullptr}; Attr *ResourceAttr = HLSLResourceAttr::CreateImplicit(Record->getASTContext(), RK); if (CreateHLSLAttributedResourceType(S, Ty, Attrs, AttributedResTy)) @@ -495,9 +498,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 RowAccess) { return BuiltinTypeDeclBuilder(Decl) - .addHandleMember(S, RC, RK, IsROV) + .addHandleMember(S, RC, RK, IsROV, RowAccess) .addDefaultHandleConstructor(S, RC); } @@ -510,7 +513,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { onCompletion(Decl, [this](CXXRecordDecl *Decl) { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::TypedBuffer, - /*IsROV=*/false) + /*IsROV=*/false, /*RowAccess=*/true) .addArraySubscriptOperators() .completeDefinition(); }); @@ -521,7 +524,8 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { .Record; onCompletion(Decl, [this](CXXRecordDecl *Decl) { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, - ResourceKind::TypedBuffer, /*IsROV=*/true) + ResourceKind::TypedBuffer, /*IsROV=*/true, + /*RowAccess=*/true) .addArraySubscriptOperators() .completeDefinition(); }); diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 3b91303ac8cb8a..c2a1d7fa5eb844 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -593,6 +593,9 @@ bool clang::CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped, case attr::HLSLROV: ResAttrs.IsROV = true; break; + case attr::HLSLRowAccess: + ResAttrs.RowAccess = true; + break; default: llvm_unreachable("unhandled resource attribute type"); } @@ -645,6 +648,9 @@ bool SemaHLSL::handleResourceTypeAttr(const ParsedAttr &AL) { case ParsedAttr::AT_HLSLROV: A = HLSLROVAttr::Create(getASTContext(), AL.getLoc()); break; + case ParsedAttr::AT_HLSLRowAccess: + A = HLSLRowAccessAttr::Create(getASTContext(), AL.getLoc()); + break; default: llvm_unreachable("unhandled HLSL attribute"); } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 520dce870b7b78..34a963074e1dde 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -8843,7 +8843,8 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, break; } case ParsedAttr::AT_HLSLResourceClass: - case ParsedAttr::AT_HLSLROV: { + case ParsedAttr::AT_HLSLROV: + case ParsedAttr::AT_HLSLRowAccess: { if (state.getSema().HLSL().handleResourceTypeAttr(attr)) attr.setUsedAsTypeAttr(); break; diff --git a/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl b/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl index 6324a11fc8a2df..b8e843eb3448f2 100644 --- a/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl +++ b/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl @@ -3,7 +3,7 @@ // CHECK: -ClassTemplateSpecializationDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> class RWBuffer definition implicit_instantiation // CHECK: -TemplateArgument type 'float' // CHECK: `-BuiltinType 0x{{[0-9a-f]+}} 'float' -// CHECK: -FieldDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> implicit referenced h 'float * {{\[\[}}hlsl::resource_class(UAV)]]':'float *' +// CHECK: -FieldDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> implicit referenced h 'float * {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::row_access]]':'float *' // CHECK: -HLSLResourceAttr 0x{{[0-9a-f]+}} <<invalid sloc>> Implicit TypedBuffer RWBuffer<float> Buffer1; @@ -11,6 +11,6 @@ RWBuffer<float> Buffer1; // CHECK: -TemplateArgument type 'vector<float, 4>' // CHECK: `-ExtVectorType 0x{{[0-9a-f]+}} 'vector<float, 4>' 4 // CHECK: `-BuiltinType 0x{{[0-9a-f]+}} 'float' -// CHECK: -FieldDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> implicit referenced h 'vector<float *, 4> {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::is_rov()]]':'vector<float *, 4>' +// CHECK: -FieldDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> implicit referenced h 'vector<float *, 4> {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::is_rov()]] {{\[\[}}hlsl::row_access]]':'vector<float *, 4>' // CHECK: -HLSLResourceAttr 0x{{[0-9a-f]+}} <<invalid sloc>> Implicit TypedBuffer RasterizerOrderedBuffer<vector<float, 4> > BufferArray3[4]; diff --git a/clang/test/ParserHLSL/hlsl_row_access_attr.hlsl b/clang/test/ParserHLSL/hlsl_row_access_attr.hlsl new file mode 100644 index 00000000000000..3bcaf53f7984ad --- /dev/null +++ b/clang/test/ParserHLSL/hlsl_row_access_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::row_access]]':'__hlsl_resource_t' +struct MyBuffer { + __hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::row_access]] h1; +}; + +// CHECK: VarDecl 0x{{[0-9a-f]+}} <line:10:1, col:70> col:70 h2 '__hlsl_resource_t {{\[\[}}hlsl::resource_class(SRV)]] {{\[\[}}hlsl::row_access]]':'__hlsl_resource_t' +__hlsl_resource_t [[hlsl::row_access]] [[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::row_access]]':'__hlsl_resource_t' +void f() { + __hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::row_access]] h3; +} diff --git a/clang/test/ParserHLSL/hlsl_row_access_attr_error.hlsl b/clang/test/ParserHLSL/hlsl_row_access_attr_error.hlsl new file mode 100644 index 00000000000000..7a3d17be7d02e0 --- /dev/null +++ b/clang/test/ParserHLSL/hlsl_row_access_attr_error.hlsl @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -o - %s -verify + +// expected-error@+1{{'row_access' attribute cannot be applied to a declaration}} +[[hlsl::row_access]] __hlsl_resource_t res0; + +// expected-error@+1{{HLSL resource needs to have [[hlsl::resource_class()]] attribute}} +__hlsl_resource_t [[hlsl::row_access]] res1; + +// expected-error@+1{{'row_access' attribute takes no arguments}} +__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::row_access(3)]] res2; + +// expected-error@+1{{use of undeclared identifier 'gibberish'}} +__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::row_access(gibberish)]] res3; + +// duplicate attribute with the same meaning - no error +__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::row_access]] [[hlsl::row_access]] res4; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits