-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
[HLSL] Add [[hlsl::raw_buffer]]
attribute
#107954
Conversation
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 llvm#107907
@llvm/pr-subscribers-hlsl @llvm/pr-subscribers-clang Author: Helena Kotas (hekota) ChangesThis PR introduces new HLSL resource type attribute This information is necessary in order to properly distinguish between handles for typed buffer types (like Fixes #107907 Full diff: https://github.com/llvm/llvm-project/pull/107954.diff 12 Files Affected:
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..5f741e3124461f 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -593,6 +593,13 @@ bool clang::CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped,
case attr::HLSLROV:
ResAttrs.IsROV = true;
break;
+ case attr::HLSLRowAccess:
+ if (ResAttrs.RowAccess) {
+ S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
+ return false;
+ }
+ ResAttrs.RowAccess = true;
+ break;
default:
llvm_unreachable("unhandled resource attribute type");
}
@@ -645,6 +652,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..79e4fa77e001e9 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -8843,8 +8843,13 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
break;
}
case ParsedAttr::AT_HLSLResourceClass:
- case ParsedAttr::AT_HLSLROV: {
- if (state.getSema().HLSL().handleResourceTypeAttr(attr))
+ case ParsedAttr::AT_HLSLROV:
+ case ParsedAttr::AT_HLSLRowAccess: {
+ // Only collect HLSL resource type attributes that are in
+ // decl-specifier-seq; do not collect attributes on declarations or those
+ // that get to slide after declaration name.
+ if (TAL == TAL_DeclSpec &&
+ state.getSema().HLSL().handleResourceTypeAttr(attr))
attr.setUsedAsTypeAttr();
break;
}
diff --git a/clang/test/AST/HLSL/RWBuffer-AST.hlsl b/clang/test/AST/HLSL/RWBuffer-AST.hlsl
index 0e7803ce50a890..10bcf9b70d1121 100644
--- a/clang/test/AST/HLSL/RWBuffer-AST.hlsl
+++ b/clang/test/AST/HLSL/RWBuffer-AST.hlsl
@@ -30,7 +30,7 @@ RWBuffer<float> Buffer;
// CHECK-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit class RWBuffer definition
// CHECK: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
-// CHECK-NEXT: implicit h 'element_type * {{\[\[}}hlsl::resource_class(UAV)]]':'element_type *'
+// CHECK-NEXT: implicit h 'element_type * {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::row_access]]':'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 @@ RWBuffer<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)]]':'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::row_access]]':'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}}
// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'const RWBuffer<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 @@ RWBuffer<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)]]':'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::row_access]]':'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}}
// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'RWBuffer<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 @@ RWBuffer<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)]]':'float *'
+// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit referenced h 'float * {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::row_access]]':'float *'
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer
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..e1a0349d90d146
--- /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;
+
+// expected-warning@+1{{attribute 'row_access' is already applied}}
+__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::row_access]] [[hlsl::row_access]] res4;
|
@llvm/pr-subscribers-clang-modules Author: Helena Kotas (hekota) ChangesThis PR introduces new HLSL resource type attribute This information is necessary in order to properly distinguish between handles for typed buffer types (like Fixes #107907 Full diff: https://github.com/llvm/llvm-project/pull/107954.diff 12 Files Affected:
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..5f741e3124461f 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -593,6 +593,13 @@ bool clang::CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped,
case attr::HLSLROV:
ResAttrs.IsROV = true;
break;
+ case attr::HLSLRowAccess:
+ if (ResAttrs.RowAccess) {
+ S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
+ return false;
+ }
+ ResAttrs.RowAccess = true;
+ break;
default:
llvm_unreachable("unhandled resource attribute type");
}
@@ -645,6 +652,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..79e4fa77e001e9 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -8843,8 +8843,13 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
break;
}
case ParsedAttr::AT_HLSLResourceClass:
- case ParsedAttr::AT_HLSLROV: {
- if (state.getSema().HLSL().handleResourceTypeAttr(attr))
+ case ParsedAttr::AT_HLSLROV:
+ case ParsedAttr::AT_HLSLRowAccess: {
+ // Only collect HLSL resource type attributes that are in
+ // decl-specifier-seq; do not collect attributes on declarations or those
+ // that get to slide after declaration name.
+ if (TAL == TAL_DeclSpec &&
+ state.getSema().HLSL().handleResourceTypeAttr(attr))
attr.setUsedAsTypeAttr();
break;
}
diff --git a/clang/test/AST/HLSL/RWBuffer-AST.hlsl b/clang/test/AST/HLSL/RWBuffer-AST.hlsl
index 0e7803ce50a890..10bcf9b70d1121 100644
--- a/clang/test/AST/HLSL/RWBuffer-AST.hlsl
+++ b/clang/test/AST/HLSL/RWBuffer-AST.hlsl
@@ -30,7 +30,7 @@ RWBuffer<float> Buffer;
// CHECK-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit class RWBuffer definition
// CHECK: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
-// CHECK-NEXT: implicit h 'element_type * {{\[\[}}hlsl::resource_class(UAV)]]':'element_type *'
+// CHECK-NEXT: implicit h 'element_type * {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::row_access]]':'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 @@ RWBuffer<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)]]':'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::row_access]]':'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}}
// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'const RWBuffer<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 @@ RWBuffer<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)]]':'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::row_access]]':'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}}
// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'RWBuffer<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 @@ RWBuffer<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)]]':'float *'
+// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit referenced h 'float * {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::row_access]]':'float *'
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer
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..e1a0349d90d146
--- /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;
+
+// expected-warning@+1{{attribute 'row_access' is already applied}}
+__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::row_access]] [[hlsl::row_access]] res4;
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's been some discussion about the design for this offline that should be resolved before this PR is completed.
[[hlsl::row_access]]
attribute[[hlsl::raw_buffer]]
attribute
✅ With the latest revision this PR passed the C/C++ code formatter. |
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 llvm#107907
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 likeStructuredBuffer
orByteAddressBuffer
and in DXIL it will be translated to target extension typedx.RawBuffer
.Fixes #107907