Skip to content

Commit 67c000e

Browse files
authored
[HLSL] [SPIR-V] Add counter member for typed buffer (#161414)
This is part 1 of implementing the typed buffer counters proposal: https://github.com/llvm/wg-hlsl/blob/main/proposals/0023-typed-buffer-counters.md This patch adds the initial plumbing for supporting counter variables associated with structured buffers for the SPIR-V backend. It introduces an `IsCounter` attribute to `HLSLAttributedResourceType` and threads it through the AST, type printing, and mangling. It also adds a `__counter_handle` member to the relevant buffer types in `HLSLBuiltinTypeDeclBuilder`. Contributes to #137032
1 parent 0b7129a commit 67c000e

17 files changed

+238
-74
lines changed

clang/include/clang/AST/TypeBase.h

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6702,15 +6702,21 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
67026702
LLVM_PREFERRED_TYPE(bool)
67036703
uint8_t RawBuffer : 1;
67046704

6705+
LLVM_PREFERRED_TYPE(bool)
6706+
uint8_t IsCounter : 1;
6707+
67056708
Attributes(llvm::dxil::ResourceClass ResourceClass, bool IsROV = false,
6706-
bool RawBuffer = false)
6707-
: ResourceClass(ResourceClass), IsROV(IsROV), RawBuffer(RawBuffer) {}
6709+
bool RawBuffer = false, bool IsCounter = false)
6710+
: ResourceClass(ResourceClass), IsROV(IsROV), RawBuffer(RawBuffer),
6711+
IsCounter(IsCounter) {}
67086712

6709-
Attributes() : Attributes(llvm::dxil::ResourceClass::UAV, false, false) {}
6713+
Attributes()
6714+
: Attributes(llvm::dxil::ResourceClass::UAV, false, false, false) {}
67106715

67116716
friend bool operator==(const Attributes &LHS, const Attributes &RHS) {
6712-
return std::tie(LHS.ResourceClass, LHS.IsROV, LHS.RawBuffer) ==
6713-
std::tie(RHS.ResourceClass, RHS.IsROV, RHS.RawBuffer);
6717+
return std::tie(LHS.ResourceClass, LHS.IsROV, LHS.RawBuffer,
6718+
LHS.IsCounter) == std::tie(RHS.ResourceClass, RHS.IsROV,
6719+
RHS.RawBuffer, RHS.IsCounter);
67146720
}
67156721
friend bool operator!=(const Attributes &LHS, const Attributes &RHS) {
67166722
return !(LHS == RHS);
@@ -6751,6 +6757,7 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
67516757
ID.AddInteger(static_cast<uint32_t>(Attrs.ResourceClass));
67526758
ID.AddBoolean(Attrs.IsROV);
67536759
ID.AddBoolean(Attrs.RawBuffer);
6760+
ID.AddBoolean(Attrs.IsCounter);
67546761
}
67556762

67566763
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
@@ -662,14 +662,17 @@ let Class = HLSLAttributedResourceType in {
662662
def : Property<"rawBuffer", Bool> {
663663
let Read = [{ node->getAttrs().RawBuffer }];
664664
}
665+
def : Property<"isCounter", Bool> {
666+
let Read = [{ node->getAttrs().IsCounter }];
667+
}
665668
def : Property<"wrappedTy", QualType> {
666669
let Read = [{ node->getWrappedType() }];
667670
}
668671
def : Property<"containedTy", QualType> {
669672
let Read = [{ node->getContainedType() }];
670673
}
671674
def : Creator<[{
672-
HLSLAttributedResourceType::Attributes attrs(static_cast<llvm::dxil::ResourceClass>(resClass), isROV, rawBuffer);
675+
HLSLAttributedResourceType::Attributes attrs(static_cast<llvm::dxil::ResourceClass>(resClass), isROV, rawBuffer, isCounter);
673676
return ctx.getHLSLAttributedResourceType(wrappedTy, containedTy, attrs);
674677
}]>;
675678
}

clang/include/clang/Basic/Attr.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5074,6 +5074,12 @@ def HLSLRawBuffer : TypeAttr {
50745074
let Documentation = [InternalOnly];
50755075
}
50765076

5077+
def HLSLIsCounter : TypeAttr {
5078+
let Spellings = [CXX11<"hlsl", "is_counter">];
5079+
let LangOpts = [HLSL];
5080+
let Documentation = [InternalOnly];
5081+
}
5082+
50775083
def HLSLGroupSharedAddressSpace : TypeAttr {
50785084
let Spellings = [CustomKeyword<"groupshared">];
50795085
let Subjects = SubjectList<[Var]>;

clang/lib/AST/ItaniumMangle.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4624,6 +4624,8 @@ void CXXNameMangler::mangleType(const HLSLAttributedResourceType *T) {
46244624
Str += "_ROV";
46254625
if (Attrs.RawBuffer)
46264626
Str += "_Raw";
4627+
if (Attrs.IsCounter)
4628+
Str += "_Counter";
46274629
if (T->hasContainedType())
46284630
Str += "_CT";
46294631
mangleVendorQualifier(Str);

clang/lib/AST/TypePrinter.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2062,6 +2062,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
20622062
case attr::HLSLROV:
20632063
case attr::HLSLRawBuffer:
20642064
case attr::HLSLContainedType:
2065+
case attr::HLSLIsCounter:
20652066
llvm_unreachable("HLSL resource type attributes handled separately");
20662067

20672068
case attr::OpenCLPrivateAddressSpace:
@@ -2210,6 +2211,8 @@ void TypePrinter::printHLSLAttributedResourceAfter(
22102211
OS << " [[hlsl::is_rov]]";
22112212
if (Attrs.RawBuffer)
22122213
OS << " [[hlsl::raw_buffer]]";
2214+
if (Attrs.IsCounter)
2215+
OS << " [[hlsl::is_counter]]";
22132216

22142217
QualType ContainedTy = T->getContainedType();
22152218
if (!ContainedTy.isNull()) {

clang/lib/CodeGen/Targets/SPIR.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,12 @@ llvm::Type *CommonSPIRTargetCodeGenInfo::getHLSLType(
486486
return getSPIRVImageTypeFromHLSLResource(ResAttrs, ContainedTy, CGM);
487487
}
488488

489+
if (ResAttrs.IsCounter) {
490+
llvm::Type *ElemType = llvm::Type::getInt32Ty(Ctx);
491+
uint32_t StorageClass = /* StorageBuffer storage class */ 12;
492+
return llvm::TargetExtType::get(Ctx, "spirv.VulkanBuffer", {ElemType},
493+
{StorageClass, true});
494+
}
489495
llvm::Type *ElemType = CGM.getTypes().ConvertTypeForMem(ContainedTy);
490496
llvm::ArrayType *RuntimeArrayType = llvm::ArrayType::get(ElemType, 0);
491497
uint32_t StorageClass = /* StorageBuffer storage class */ 12;

clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp

Lines changed: 98 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,16 @@ struct BuiltinTypeMethodBuilder {
138138
// LastStmt - refers to the last statement in the method body; referencing
139139
// LastStmt will remove the statement from the method body since
140140
// it will be linked from the new expression being constructed.
141-
enum class PlaceHolder { _0, _1, _2, _3, _4, Handle = 128, LastStmt };
141+
enum class PlaceHolder {
142+
_0,
143+
_1,
144+
_2,
145+
_3,
146+
_4,
147+
Handle = 128,
148+
CounterHandle,
149+
LastStmt
150+
};
142151

143152
Expr *convertPlaceholder(PlaceHolder PH);
144153
Expr *convertPlaceholder(LocalVar &Var);
@@ -178,10 +187,14 @@ struct BuiltinTypeMethodBuilder {
178187
template <typename ResourceT, typename ValueT>
179188
BuiltinTypeMethodBuilder &setHandleFieldOnResource(ResourceT ResourceRecord,
180189
ValueT HandleValue);
190+
template <typename T>
191+
BuiltinTypeMethodBuilder &
192+
accessCounterHandleFieldOnResource(T ResourceRecord);
181193
template <typename T> BuiltinTypeMethodBuilder &returnValue(T ReturnValue);
182194
BuiltinTypeMethodBuilder &returnThis();
183195
BuiltinTypeDeclBuilder &finalize();
184196
Expr *getResourceHandleExpr();
197+
Expr *getResourceCounterHandleExpr();
185198

186199
private:
187200
void createDecl();
@@ -346,6 +359,8 @@ TemplateParameterListBuilder::finalizeTemplateArgs(ConceptDecl *CD) {
346359
Expr *BuiltinTypeMethodBuilder::convertPlaceholder(PlaceHolder PH) {
347360
if (PH == PlaceHolder::Handle)
348361
return getResourceHandleExpr();
362+
if (PH == PlaceHolder::CounterHandle)
363+
return getResourceCounterHandleExpr();
349364

350365
if (PH == PlaceHolder::LastStmt) {
351366
assert(!StmtsList.empty() && "no statements in the list");
@@ -467,6 +482,18 @@ Expr *BuiltinTypeMethodBuilder::getResourceHandleExpr() {
467482
OK_Ordinary);
468483
}
469484

485+
Expr *BuiltinTypeMethodBuilder::getResourceCounterHandleExpr() {
486+
ensureCompleteDecl();
487+
488+
ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
489+
CXXThisExpr *This = CXXThisExpr::Create(
490+
AST, SourceLocation(), Method->getFunctionObjectParameterType(), true);
491+
FieldDecl *HandleField = DeclBuilder.getResourceCounterHandleField();
492+
return MemberExpr::CreateImplicit(AST, This, false, HandleField,
493+
HandleField->getType(), VK_LValue,
494+
OK_Ordinary);
495+
}
496+
470497
BuiltinTypeMethodBuilder &
471498
BuiltinTypeMethodBuilder::declareLocalVar(LocalVar &Var) {
472499
ensureCompleteDecl();
@@ -583,6 +610,22 @@ BuiltinTypeMethodBuilder::setHandleFieldOnResource(ResourceT ResourceRecord,
583610
return *this;
584611
}
585612

613+
template <typename T>
614+
BuiltinTypeMethodBuilder &
615+
BuiltinTypeMethodBuilder::accessCounterHandleFieldOnResource(T ResourceRecord) {
616+
ensureCompleteDecl();
617+
618+
Expr *ResourceExpr = convertPlaceholder(ResourceRecord);
619+
620+
ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
621+
FieldDecl *HandleField = DeclBuilder.getResourceCounterHandleField();
622+
MemberExpr *HandleExpr = MemberExpr::CreateImplicit(
623+
AST, ResourceExpr, false, HandleField, HandleField->getType(), VK_LValue,
624+
OK_Ordinary);
625+
StmtsList.push_back(HandleExpr);
626+
return *this;
627+
}
628+
586629
template <typename T>
587630
BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::returnValue(T ReturnValue) {
588631
ensureCompleteDecl();
@@ -722,8 +765,31 @@ BuiltinTypeDeclBuilder::addMemberVariable(StringRef Name, QualType Type,
722765
return *this;
723766
}
724767

768+
BuiltinTypeDeclBuilder &
769+
BuiltinTypeDeclBuilder::addBufferHandles(ResourceClass RC, bool IsROV,
770+
bool RawBuffer, bool HasCounter,
771+
AccessSpecifier Access) {
772+
addHandleMember(RC, IsROV, RawBuffer, Access);
773+
if (HasCounter)
774+
addCounterHandleMember(RC, IsROV, RawBuffer, Access);
775+
return *this;
776+
}
777+
725778
BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addHandleMember(
726779
ResourceClass RC, bool IsROV, bool RawBuffer, AccessSpecifier Access) {
780+
return addResourceMember("__handle", RC, IsROV, RawBuffer,
781+
/*IsCounter=*/false, Access);
782+
}
783+
784+
BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCounterHandleMember(
785+
ResourceClass RC, bool IsROV, bool RawBuffer, AccessSpecifier Access) {
786+
return addResourceMember("__counter_handle", RC, IsROV, RawBuffer,
787+
/*IsCounter=*/true, Access);
788+
}
789+
790+
BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addResourceMember(
791+
StringRef MemberName, ResourceClass RC, bool IsROV, bool RawBuffer,
792+
bool IsCounter, AccessSpecifier Access) {
727793
assert(!Record->isCompleteDefinition() && "record is already complete");
728794

729795
ASTContext &Ctx = SemaRef.getASTContext();
@@ -739,9 +805,12 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addHandleMember(
739805
ElementTypeInfo
740806
? HLSLContainedTypeAttr::CreateImplicit(Ctx, ElementTypeInfo)
741807
: nullptr};
808+
if (IsCounter)
809+
Attrs.push_back(HLSLIsCounterAttr::CreateImplicit(Ctx));
810+
742811
if (CreateHLSLAttributedResourceType(SemaRef, Ctx.HLSLResourceTy, Attrs,
743812
AttributedResTy))
744-
addMemberVariable("__handle", AttributedResTy, {}, Access);
813+
addMemberVariable(MemberName, AttributedResTy, {}, Access);
745814
return *this;
746815
}
747816

@@ -844,12 +913,17 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCopyConstructor() {
844913

845914
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
846915

847-
return BuiltinTypeMethodBuilder(*this, /*Name=*/"", AST.VoidTy,
848-
/*IsConst=*/false, /*IsCtor=*/true)
849-
.addParam("other", ConstRecordRefType)
916+
BuiltinTypeMethodBuilder MMB(*this, /*Name=*/"", AST.VoidTy,
917+
/*IsConst=*/false, /*IsCtor=*/true);
918+
MMB.addParam("other", ConstRecordRefType)
850919
.accessHandleFieldOnResource(PH::_0)
851-
.assign(PH::Handle, PH::LastStmt)
852-
.finalize();
920+
.assign(PH::Handle, PH::LastStmt);
921+
922+
if (getResourceCounterHandleField())
923+
MMB.accessCounterHandleFieldOnResource(PH::_0).assign(PH::CounterHandle,
924+
PH::LastStmt);
925+
926+
return MMB.finalize();
853927
}
854928

855929
BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCopyAssignmentOperator() {
@@ -863,12 +937,16 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCopyAssignmentOperator() {
863937

864938
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
865939
DeclarationName Name = AST.DeclarationNames.getCXXOperatorName(OO_Equal);
866-
return BuiltinTypeMethodBuilder(*this, Name, RecordRefType)
867-
.addParam("other", ConstRecordRefType)
940+
BuiltinTypeMethodBuilder MMB(*this, Name, RecordRefType);
941+
MMB.addParam("other", ConstRecordRefType)
868942
.accessHandleFieldOnResource(PH::_0)
869-
.assign(PH::Handle, PH::LastStmt)
870-
.returnThis()
871-
.finalize();
943+
.assign(PH::Handle, PH::LastStmt);
944+
945+
if (getResourceCounterHandleField())
946+
MMB.accessCounterHandleFieldOnResource(PH::_0).assign(PH::CounterHandle,
947+
PH::LastStmt);
948+
949+
return MMB.returnThis().finalize();
872950
}
873951

874952
BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addArraySubscriptOperators() {
@@ -903,6 +981,14 @@ FieldDecl *BuiltinTypeDeclBuilder::getResourceHandleField() const {
903981
return I->second;
904982
}
905983

984+
FieldDecl *BuiltinTypeDeclBuilder::getResourceCounterHandleField() const {
985+
auto I = Fields.find("__counter_handle");
986+
if (I == Fields.end() ||
987+
!I->second->getType()->isHLSLAttributedResourceType())
988+
return nullptr;
989+
return I->second;
990+
}
991+
906992
QualType BuiltinTypeDeclBuilder::getFirstTemplateTypeParam() {
907993
assert(Template && "record it not a template");
908994
if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>(

clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,9 @@ class BuiltinTypeDeclBuilder {
7272
AccessSpecifier Access = AccessSpecifier::AS_private);
7373

7474
BuiltinTypeDeclBuilder &
75-
addHandleMember(ResourceClass RC, bool IsROV, bool RawBuffer,
76-
AccessSpecifier Access = AccessSpecifier::AS_private);
75+
addBufferHandles(ResourceClass RC, bool IsROV, bool RawBuffer,
76+
bool HasCounter,
77+
AccessSpecifier Access = AccessSpecifier::AS_private);
7778
BuiltinTypeDeclBuilder &addArraySubscriptOperators();
7879

7980
// Builtin types constructors
@@ -95,7 +96,18 @@ class BuiltinTypeDeclBuilder {
9596
BuiltinTypeDeclBuilder &addConsumeMethod();
9697

9798
private:
99+
BuiltinTypeDeclBuilder &addResourceMember(StringRef MemberName,
100+
ResourceClass RC, bool IsROV,
101+
bool RawBuffer, bool IsCounter,
102+
AccessSpecifier Access);
103+
BuiltinTypeDeclBuilder &
104+
addHandleMember(ResourceClass RC, bool IsROV, bool RawBuffer,
105+
AccessSpecifier Access = AccessSpecifier::AS_private);
106+
BuiltinTypeDeclBuilder &
107+
addCounterHandleMember(ResourceClass RC, bool IsROV, bool RawBuffer,
108+
AccessSpecifier Access = AccessSpecifier::AS_private);
98109
FieldDecl *getResourceHandleField() const;
110+
FieldDecl *getResourceCounterHandleField() const;
99111
QualType getFirstTemplateTypeParam();
100112
QualType getHandleElementType();
101113
Expr *getConstantIntExpr(int value);

0 commit comments

Comments
 (0)