Skip to content

Commit 5df1b79

Browse files
authored
[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
1 parent 8982f98 commit 5df1b79

File tree

11 files changed

+84
-18
lines changed

11 files changed

+84
-18
lines changed

clang/include/clang/AST/Type.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6168,10 +6168,18 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
61686168
struct Attributes {
61696169
// Data gathered from HLSL resource attributes
61706170
llvm::dxil::ResourceClass ResourceClass;
6171+
6172+
LLVM_PREFERRED_TYPE(bool)
61716173
uint8_t IsROV : 1;
6172-
Attributes(llvm::dxil::ResourceClass ResourceClass, bool IsROV)
6173-
: ResourceClass(ResourceClass), IsROV(IsROV) {}
6174-
Attributes() : ResourceClass(llvm::dxil::ResourceClass::UAV), IsROV(0) {}
6174+
6175+
LLVM_PREFERRED_TYPE(bool)
6176+
uint8_t RawBuffer : 1;
6177+
6178+
Attributes(llvm::dxil::ResourceClass ResourceClass, bool IsROV,
6179+
bool RawBuffer)
6180+
: ResourceClass(ResourceClass), IsROV(IsROV), RawBuffer(RawBuffer) {}
6181+
6182+
Attributes() : Attributes(llvm::dxil::ResourceClass::UAV, false, false) {}
61756183
};
61766184

61776185
private:
@@ -6204,6 +6212,7 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
62046212
ID.AddPointer(Contained.getAsOpaquePtr());
62056213
ID.AddInteger(static_cast<uint32_t>(Attrs.ResourceClass));
62066214
ID.AddBoolean(Attrs.IsROV);
6215+
ID.AddBoolean(Attrs.RawBuffer);
62076216
}
62086217

62096218
static bool classof(const Type *T) {

clang/include/clang/AST/TypeProperties.td

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -697,14 +697,17 @@ let Class = HLSLAttributedResourceType in {
697697
def : Property<"isROV", Bool> {
698698
let Read = [{ node->getAttrs().IsROV }];
699699
}
700+
def : Property<"rawBuffer", Bool> {
701+
let Read = [{ node->getAttrs().RawBuffer }];
702+
}
700703
def : Property<"wrappedTy", QualType> {
701704
let Read = [{ node->getWrappedType() }];
702705
}
703706
def : Property<"containedTy", QualType> {
704707
let Read = [{ node->getContainedType() }];
705708
}
706709
def : Creator<[{
707-
HLSLAttributedResourceType::Attributes attrs(static_cast<llvm::dxil::ResourceClass>(resClass), isROV);
710+
HLSLAttributedResourceType::Attributes attrs(static_cast<llvm::dxil::ResourceClass>(resClass), isROV, rawBuffer);
708711
return ctx.getHLSLAttributedResourceType(wrappedTy, containedTy, attrs);
709712
}]>;
710713
}

clang/include/clang/Basic/Attr.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4674,6 +4674,12 @@ def HLSLContainedType : TypeAttr {
46744674
let Documentation = [InternalOnly];
46754675
}
46764676

4677+
def HLSLRawBuffer : TypeAttr {
4678+
let Spellings = [CXX11<"hlsl", "raw_buffer">];
4679+
let LangOpts = [HLSL];
4680+
let Documentation = [InternalOnly];
4681+
}
4682+
46774683
def HLSLGroupSharedAddressSpace : TypeAttr {
46784684
let Spellings = [CustomKeyword<"groupshared">];
46794685
let Subjects = SubjectList<[Var]>;

clang/lib/AST/ASTStructuralEquivalence.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -808,8 +808,8 @@ static bool
808808
IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
809809
const HLSLAttributedResourceType::Attributes &Attrs1,
810810
const HLSLAttributedResourceType::Attributes &Attrs2) {
811-
return std::tie(Attrs1.ResourceClass, Attrs1.IsROV) ==
812-
std::tie(Attrs2.ResourceClass, Attrs2.IsROV);
811+
return std::tie(Attrs1.ResourceClass, Attrs1.IsROV, Attrs1.RawBuffer) ==
812+
std::tie(Attrs2.ResourceClass, Attrs2.IsROV, Attrs2.RawBuffer);
813813
}
814814

815815
/// Determine structural equivalence of two types.

clang/lib/AST/TypePrinter.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1945,6 +1945,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
19451945

19461946
case attr::HLSLResourceClass:
19471947
case attr::HLSLROV:
1948+
case attr::HLSLRawBuffer:
19481949
case attr::HLSLContainedType:
19491950
llvm_unreachable("HLSL resource type attributes handled separately");
19501951

@@ -2079,6 +2080,8 @@ void TypePrinter::printHLSLAttributedResourceAfter(
20792080
<< ")]]";
20802081
if (Attrs.IsROV)
20812082
OS << " [[hlsl::is_rov]]";
2083+
if (Attrs.RawBuffer)
2084+
OS << " [[hlsl::raw_buffer]]";
20822085

20832086
QualType ContainedTy = T->getContainedType();
20842087
if (!ContainedTy.isNull()) {

clang/lib/Sema/HLSLExternalSemaSource.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ struct BuiltinTypeDeclBuilder {
112112

113113
BuiltinTypeDeclBuilder &
114114
addHandleMember(Sema &S, ResourceClass RC, ResourceKind RK, bool IsROV,
115+
bool RawBuffer,
115116
AccessSpecifier Access = AccessSpecifier::AS_private) {
116117
if (Record->isCompleteDefinition())
117118
return *this;
@@ -135,10 +136,11 @@ struct BuiltinTypeDeclBuilder {
135136
SmallVector<const Attr *> Attrs = {
136137
HLSLResourceClassAttr::CreateImplicit(Record->getASTContext(), RC),
137138
IsROV ? HLSLROVAttr::CreateImplicit(Record->getASTContext()) : nullptr,
139+
RawBuffer ? HLSLRawBufferAttr::CreateImplicit(Record->getASTContext())
140+
: nullptr,
138141
ElementTypeInfo ? HLSLContainedTypeAttr::CreateImplicit(
139142
Record->getASTContext(), ElementTypeInfo)
140-
: nullptr,
141-
};
143+
: nullptr};
142144
Attr *ResourceAttr =
143145
HLSLResourceAttr::CreateImplicit(Record->getASTContext(), RK);
144146
if (CreateHLSLAttributedResourceType(S, Ty, Attrs, AttributedResTy))
@@ -507,9 +509,9 @@ void HLSLExternalSemaSource::defineTrivialHLSLTypes() {
507509
/// Set up common members and attributes for buffer types
508510
static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
509511
ResourceClass RC, ResourceKind RK,
510-
bool IsROV) {
512+
bool IsROV, bool RawBuffer) {
511513
return BuiltinTypeDeclBuilder(Decl)
512-
.addHandleMember(S, RC, RK, IsROV)
514+
.addHandleMember(S, RC, RK, IsROV, RawBuffer)
513515
.addDefaultHandleConstructor(S, RC);
514516
}
515517

@@ -522,7 +524,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
522524
onCompletion(Decl, [this](CXXRecordDecl *Decl) {
523525
setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
524526
ResourceKind::TypedBuffer,
525-
/*IsROV=*/false)
527+
/*IsROV=*/false, /*RawBuffer=*/false)
526528
.addArraySubscriptOperators()
527529
.completeDefinition();
528530
});
@@ -533,7 +535,8 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
533535
.Record;
534536
onCompletion(Decl, [this](CXXRecordDecl *Decl) {
535537
setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
536-
ResourceKind::TypedBuffer, /*IsROV=*/true)
538+
ResourceKind::TypedBuffer, /*IsROV=*/true,
539+
/*RawBuffer=*/false)
537540
.addArraySubscriptOperators()
538541
.completeDefinition();
539542
});
@@ -543,7 +546,8 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
543546
.Record;
544547
onCompletion(Decl, [this](CXXRecordDecl *Decl) {
545548
setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
546-
ResourceKind::TypedBuffer, /*IsROV=*/false)
549+
ResourceKind::TypedBuffer, /*IsROV=*/false,
550+
/*RawBuffer=*/true)
547551
.addArraySubscriptOperators()
548552
.completeDefinition();
549553
});

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,7 @@ bool clang::CreateHLSLAttributedResourceType(
577577
SourceLocation LocBegin = AttrList[0]->getRange().getBegin();
578578
SourceLocation LocEnd = AttrList[0]->getRange().getEnd();
579579

580-
HLSLAttributedResourceType::Attributes ResAttrs = {};
580+
HLSLAttributedResourceType::Attributes ResAttrs;
581581

582582
bool HasResourceClass = false;
583583
for (const Attr *A : AttrList) {
@@ -606,6 +606,13 @@ bool clang::CreateHLSLAttributedResourceType(
606606
}
607607
ResAttrs.IsROV = true;
608608
break;
609+
case attr::HLSLRawBuffer:
610+
if (ResAttrs.RawBuffer) {
611+
S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
612+
return false;
613+
}
614+
ResAttrs.RawBuffer = true;
615+
break;
609616
case attr::HLSLContainedType: {
610617
const HLSLContainedTypeAttr *CTAttr = cast<HLSLContainedTypeAttr>(A);
611618
QualType Ty = CTAttr->getType();
@@ -679,6 +686,10 @@ bool SemaHLSL::handleResourceTypeAttr(const ParsedAttr &AL) {
679686
A = HLSLROVAttr::Create(getASTContext(), AL.getLoc());
680687
break;
681688

689+
case ParsedAttr::AT_HLSLRawBuffer:
690+
A = HLSLRawBufferAttr::Create(getASTContext(), AL.getLoc());
691+
break;
692+
682693
case ParsedAttr::AT_HLSLContainedType: {
683694
if (AL.getNumArgs() != 1 && !AL.hasParsedType()) {
684695
Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;

clang/lib/Sema/SemaType.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8846,6 +8846,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
88468846
}
88478847
case ParsedAttr::AT_HLSLResourceClass:
88488848
case ParsedAttr::AT_HLSLROV:
8849+
case ParsedAttr::AT_HLSLRawBuffer:
88498850
case ParsedAttr::AT_HLSLContainedType: {
88508851
// Only collect HLSL resource type attributes that are in
88518852
// decl-specifier-seq; do not collect attributes on declarations or those

clang/test/AST/HLSL/StructuredBuffer-AST.hlsl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,15 @@ StructuredBuffer<float> Buffer;
3030
// CHECK-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit class StructuredBuffer definition
3131

3232
// CHECK: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
33-
// 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 *'
33+
// 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 *'
3434
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer
3535

3636
// CHECK: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'element_type &const (unsigned int) const'
3737
// CHECK-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Idx 'unsigned int'
3838
// CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
3939
// CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
4040
// CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue
41-
// 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]+}}
41+
// 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]+}}
4242
// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'const StructuredBuffer<element_type>' lvalue implicit this
4343
// CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Idx' 'unsigned int'
4444
// CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline
@@ -48,7 +48,7 @@ StructuredBuffer<float> Buffer;
4848
// CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
4949
// CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
5050
// CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue
51-
// 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]+}}
51+
// 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]+}}
5252
// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'StructuredBuffer<element_type>' lvalue implicit this
5353
// CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Idx' 'unsigned int'
5454
// CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline
@@ -58,5 +58,5 @@ StructuredBuffer<float> Buffer;
5858
// CHECK: TemplateArgument type 'float'
5959
// CHECK-NEXT: BuiltinType 0x{{[0-9A-Fa-f]+}} 'float'
6060
// CHECK-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
61-
// 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 *'
61+
// 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 *'
6262
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -o - %s | FileCheck %s
2+
3+
// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} struct MyBuffer definition
4+
// 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'
5+
struct MyBuffer {
6+
__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::raw_buffer]] h1;
7+
};
8+
9+
// 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'
10+
__hlsl_resource_t [[hlsl::raw_buffer]] [[hlsl::resource_class(SRV)]] h2;
11+
12+
// CHECK: FunctionDecl 0x{{[0-9a-f]+}} <line:14:1, line:16:1> line:14:6 f 'void ()
13+
// 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'
14+
void f() {
15+
__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::raw_buffer]] h3;
16+
}

0 commit comments

Comments
 (0)