Skip to content

Commit 996815a

Browse files
committed
[SPIRV][HLSL] Add Sema and CodeGen for implicit typed buffer counters
This commit implements the Sema and CodeGen portions of the typed buffer counter proposal described in the HLSL WG proposal 0023. This change introduces the necessary Sema and CodeGen logic to handle implicit counter variables for typed buffers. This includes: - Extending `HLSLResourceBindingAttr` to store the implicit counter binding order ID. - Introducing the `__builtin_hlsl_resource_counterhandlefromimplicitbinding` builtin. - Updating `SemaHLSL` to correctly initialize global resource declarations and resource arrays with implicit counter buffers. - Adding CodeGen support for the new builtin, which generates a `llvm.spv.resource.counterhandlefromimplicitbinding` intrinsic for the SPIR-V target and aliases the main resource handle for the DXIL target. - Adding and updating tests to verify the new functionality. Fixes #137032
1 parent 9bcc0ee commit 996815a

14 files changed

+462
-124
lines changed

clang/include/clang/AST/HLSLResource.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,19 @@ struct ResourceBindingAttrs {
7474
assert(hasBinding() && !isExplicit() && !hasImplicitOrderID());
7575
RegBinding->setImplicitBindingOrderID(Value);
7676
}
77+
void setCounterImplicitOrderID(unsigned Value) const {
78+
assert(hasBinding() && !hasCounterImplicitOrderID());
79+
RegBinding->setImplicitCounterBindingOrderID(Value);
80+
}
81+
82+
bool hasCounterImplicitOrderID() const {
83+
return RegBinding && RegBinding->hasImplicitCounterBindingOrderID();
84+
}
85+
86+
unsigned getCounterImplicitOrderID() const {
87+
assert(hasCounterImplicitOrderID());
88+
return RegBinding->getImplicitCounterBindingOrderID();
89+
}
7790
};
7891

7992
} // namespace hlsl

clang/include/clang/Basic/Attr.td

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4944,6 +4944,7 @@ def HLSLResourceBinding: InheritableAttr {
49444944
std::optional<unsigned> SlotNumber;
49454945
unsigned SpaceNumber;
49464946
std::optional<unsigned> ImplicitBindingOrderID;
4947+
std::optional<unsigned> ImplicitCounterBindingOrderID;
49474948

49484949
public:
49494950
void setBinding(RegisterType RT, std::optional<unsigned> SlotNum, unsigned SpaceNum) {
@@ -4976,6 +4977,17 @@ def HLSLResourceBinding: InheritableAttr {
49764977
assert(hasImplicitBindingOrderID() && "attribute does not have implicit binding order id");
49774978
return ImplicitBindingOrderID.value();
49784979
}
4980+
void setImplicitCounterBindingOrderID(uint32_t Value) {
4981+
assert(!hasImplicitCounterBindingOrderID() && "attribute already has implicit counter binding order id");
4982+
ImplicitCounterBindingOrderID = Value;
4983+
}
4984+
bool hasImplicitCounterBindingOrderID() const {
4985+
return ImplicitCounterBindingOrderID.has_value();
4986+
}
4987+
uint32_t getImplicitCounterBindingOrderID() const {
4988+
assert(hasImplicitCounterBindingOrderID() && "attribute does not have implicit counter binding order id");
4989+
return ImplicitCounterBindingOrderID.value();
4990+
}
49794991
}];
49804992
}
49814993

clang/include/clang/Basic/Builtins.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4945,6 +4945,12 @@ def HLSLResourceHandleFromImplicitBinding : LangBuiltin<"HLSL_LANG"> {
49454945
let Prototype = "void(...)";
49464946
}
49474947

4948+
def HLSLResourceCounterHandleFromImplicitBinding : LangBuiltin<"HLSL_LANG"> {
4949+
let Spellings = ["__builtin_hlsl_resource_counterhandlefromimplicitbinding"];
4950+
let Attributes = [NoThrow, CustomTypeChecking];
4951+
let Prototype = "void(...)";
4952+
}
4953+
49484954
def HLSLResourceNonUniformIndex : LangBuiltin<"HLSL_LANG"> {
49494955
let Spellings = ["__builtin_hlsl_resource_nonuniformindex"];
49504956
let Attributes = [NoThrow];

clang/lib/CodeGen/CGHLSLBuiltins.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,19 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
352352
SmallVector<Value *> Args{OrderID, SpaceOp, RangeOp, IndexOp, Name};
353353
return Builder.CreateIntrinsic(HandleTy, IntrinsicID, Args);
354354
}
355+
case Builtin::BI__builtin_hlsl_resource_counterhandlefromimplicitbinding: {
356+
llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
357+
Value *MainHandle = EmitScalarExpr(E->getArg(0));
358+
if (CGM.getTriple().isSPIRV()) {
359+
Value *OrderID = EmitScalarExpr(E->getArg(1));
360+
Value *SpaceOp = EmitScalarExpr(E->getArg(2));
361+
llvm::Intrinsic::ID IntrinsicID =
362+
llvm::Intrinsic::spv_resource_counterhandlefromimplicitbinding;
363+
SmallVector<Value *> Args{MainHandle, OrderID, SpaceOp};
364+
return Builder.CreateIntrinsic(HandleTy, IntrinsicID, Args);
365+
}
366+
return MainHandle;
367+
}
355368
case Builtin::BI__builtin_hlsl_resource_nonuniformindex: {
356369
Value *IndexOp = EmitScalarExpr(E->getArg(0));
357370
llvm::Type *RetTy = ConvertType(E->getType());

clang/lib/CodeGen/CGHLSLRuntime.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,19 +145,34 @@ static CXXMethodDecl *lookupResourceInitMethodAndSetupArgs(
145145
// explicit binding
146146
auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, Binding.getSlot());
147147
Args.add(RValue::get(RegSlot), AST.UnsignedIntTy);
148-
CreateMethod = lookupMethod(ResourceDecl, "__createFromBinding", SC_Static);
148+
if (Binding.hasCounterImplicitOrderID())
149+
CreateMethod = lookupMethod(
150+
ResourceDecl, "__createFromBindingWithImplicitCounter", SC_Static);
151+
else
152+
CreateMethod =
153+
lookupMethod(ResourceDecl, "__createFromBinding", SC_Static);
149154
} else {
150155
// implicit binding
151156
auto *OrderID =
152157
llvm::ConstantInt::get(CGM.IntTy, Binding.getImplicitOrderID());
153158
Args.add(RValue::get(OrderID), AST.UnsignedIntTy);
154-
CreateMethod =
155-
lookupMethod(ResourceDecl, "__createFromImplicitBinding", SC_Static);
159+
if (Binding.hasCounterImplicitOrderID())
160+
CreateMethod = lookupMethod(
161+
ResourceDecl, "__createFromImplicitBindingWithImplicitCounter",
162+
SC_Static);
163+
else
164+
CreateMethod =
165+
lookupMethod(ResourceDecl, "__createFromImplicitBinding", SC_Static);
156166
}
157167
Args.add(RValue::get(Space), AST.UnsignedIntTy);
158168
Args.add(RValue::get(Range), AST.IntTy);
159169
Args.add(RValue::get(Index), AST.UnsignedIntTy);
160170
Args.add(RValue::get(NameStr), AST.getPointerType(AST.CharTy.withConst()));
171+
if (Binding.hasCounterImplicitOrderID()) {
172+
uint32_t CounterBinding = Binding.getCounterImplicitOrderID();
173+
auto *CounterOrderID = llvm::ConstantInt::get(CGM.IntTy, CounterBinding);
174+
Args.add(RValue::get(CounterOrderID), AST.UnsignedIntTy);
175+
}
161176

162177
return CreateMethod;
163178
}

clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp

Lines changed: 107 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ struct BuiltinTypeMethodBuilder {
144144
_2,
145145
_3,
146146
_4,
147+
_5,
147148
Handle = 128,
148149
CounterHandle,
149150
LastStmt
@@ -190,6 +191,9 @@ struct BuiltinTypeMethodBuilder {
190191
template <typename T>
191192
BuiltinTypeMethodBuilder &
192193
accessCounterHandleFieldOnResource(T ResourceRecord);
194+
template <typename ResourceT, typename ValueT>
195+
BuiltinTypeMethodBuilder &
196+
setCounterHandleFieldOnResource(ResourceT ResourceRecord, ValueT HandleValue);
193197
template <typename T> BuiltinTypeMethodBuilder &returnValue(T ReturnValue);
194198
BuiltinTypeMethodBuilder &returnThis();
195199
BuiltinTypeDeclBuilder &finalize();
@@ -205,6 +209,11 @@ struct BuiltinTypeMethodBuilder {
205209
if (!Method)
206210
createDecl();
207211
}
212+
213+
template <typename ResourceT, typename ValueT>
214+
BuiltinTypeMethodBuilder &setFieldOnResource(ResourceT ResourceRecord,
215+
ValueT HandleValue,
216+
FieldDecl *HandleField);
208217
};
209218

210219
TemplateParameterListBuilder::~TemplateParameterListBuilder() {
@@ -592,13 +601,27 @@ template <typename ResourceT, typename ValueT>
592601
BuiltinTypeMethodBuilder &
593602
BuiltinTypeMethodBuilder::setHandleFieldOnResource(ResourceT ResourceRecord,
594603
ValueT HandleValue) {
604+
return setFieldOnResource(ResourceRecord, HandleValue,
605+
DeclBuilder.getResourceHandleField());
606+
}
607+
608+
template <typename ResourceT, typename ValueT>
609+
BuiltinTypeMethodBuilder &
610+
BuiltinTypeMethodBuilder::setCounterHandleFieldOnResource(
611+
ResourceT ResourceRecord, ValueT HandleValue) {
612+
return setFieldOnResource(ResourceRecord, HandleValue,
613+
DeclBuilder.getResourceCounterHandleField());
614+
}
615+
616+
template <typename ResourceT, typename ValueT>
617+
BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::setFieldOnResource(
618+
ResourceT ResourceRecord, ValueT HandleValue, FieldDecl *HandleField) {
595619
ensureCompleteDecl();
596620

597621
Expr *ResourceExpr = convertPlaceholder(ResourceRecord);
598622
Expr *HandleValueExpr = convertPlaceholder(HandleValue);
599623

600624
ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
601-
FieldDecl *HandleField = DeclBuilder.getResourceHandleField();
602625
MemberExpr *HandleMemberExpr = MemberExpr::CreateImplicit(
603626
AST, ResourceExpr, false, HandleField, HandleField->getType(), VK_LValue,
604627
OK_Ordinary);
@@ -829,6 +852,18 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDefaultHandleConstructor() {
829852
.finalize();
830853
}
831854

855+
BuiltinTypeDeclBuilder &
856+
BuiltinTypeDeclBuilder::addStaticInitializationFunctions(bool HasCounter) {
857+
if (HasCounter) {
858+
addCreateFromBindingWithImplicitCounter();
859+
addCreateFromImplicitBindingWithImplicitCounter();
860+
} else {
861+
addCreateFromBinding();
862+
addCreateFromImplicitBinding();
863+
}
864+
return *this;
865+
}
866+
832867
// Adds static method that initializes resource from binding:
833868
//
834869
// static Resource<T> __createFromBinding(unsigned registerNo,
@@ -903,6 +938,73 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCreateFromImplicitBinding() {
903938
.finalize();
904939
}
905940

941+
BuiltinTypeDeclBuilder &
942+
BuiltinTypeDeclBuilder::addCreateFromBindingWithImplicitCounter() {
943+
if (Record->isCompleteDefinition())
944+
return *this;
945+
946+
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
947+
ASTContext &AST = SemaRef.getASTContext();
948+
QualType HandleType = getResourceHandleField()->getType();
949+
QualType RecordType = AST.getTypeDeclType(cast<TypeDecl>(Record));
950+
BuiltinTypeMethodBuilder::LocalVar TmpVar("tmp", RecordType);
951+
952+
return BuiltinTypeMethodBuilder(*this,
953+
"__createFromBindingWithImplicitCounter",
954+
RecordType, false, false, SC_Static)
955+
.addParam("registerNo", AST.UnsignedIntTy)
956+
.addParam("spaceNo", AST.UnsignedIntTy)
957+
.addParam("range", AST.IntTy)
958+
.addParam("index", AST.UnsignedIntTy)
959+
.addParam("name", AST.getPointerType(AST.CharTy.withConst()))
960+
.addParam("counterOrderId", AST.UnsignedIntTy)
961+
.declareLocalVar(TmpVar)
962+
.accessHandleFieldOnResource(TmpVar)
963+
.callBuiltin("__builtin_hlsl_resource_handlefrombinding", HandleType,
964+
PH::LastStmt, PH::_0, PH::_1, PH::_2, PH::_3, PH::_4)
965+
.setHandleFieldOnResource(TmpVar, PH::LastStmt)
966+
.accessHandleFieldOnResource(TmpVar)
967+
.callBuiltin("__builtin_hlsl_resource_counterhandlefromimplicitbinding",
968+
HandleType, PH::LastStmt, PH::_5, PH::_1)
969+
.setCounterHandleFieldOnResource(TmpVar, PH::LastStmt)
970+
.returnValue(TmpVar)
971+
.finalize();
972+
}
973+
974+
BuiltinTypeDeclBuilder &
975+
BuiltinTypeDeclBuilder::addCreateFromImplicitBindingWithImplicitCounter() {
976+
if (Record->isCompleteDefinition())
977+
return *this;
978+
979+
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
980+
ASTContext &AST = SemaRef.getASTContext();
981+
QualType HandleType = getResourceHandleField()->getType();
982+
QualType RecordType = AST.getTypeDeclType(cast<TypeDecl>(Record));
983+
BuiltinTypeMethodBuilder::LocalVar TmpVar("tmp", RecordType);
984+
985+
return BuiltinTypeMethodBuilder(
986+
*this, "__createFromImplicitBindingWithImplicitCounter",
987+
RecordType, false, false, SC_Static)
988+
.addParam("orderId", AST.UnsignedIntTy)
989+
.addParam("spaceNo", AST.UnsignedIntTy)
990+
.addParam("range", AST.IntTy)
991+
.addParam("index", AST.UnsignedIntTy)
992+
.addParam("name", AST.getPointerType(AST.CharTy.withConst()))
993+
.addParam("counterOrderId", AST.UnsignedIntTy)
994+
.declareLocalVar(TmpVar)
995+
.accessHandleFieldOnResource(TmpVar)
996+
.callBuiltin("__builtin_hlsl_resource_handlefromimplicitbinding",
997+
HandleType, PH::LastStmt, PH::_0, PH::_1, PH::_2, PH::_3,
998+
PH::_4)
999+
.setHandleFieldOnResource(TmpVar, PH::LastStmt)
1000+
.accessHandleFieldOnResource(TmpVar)
1001+
.callBuiltin("__builtin_hlsl_resource_counterhandlefromimplicitbinding",
1002+
HandleType, PH::LastStmt, PH::_5, PH::_1)
1003+
.setCounterHandleFieldOnResource(TmpVar, PH::LastStmt)
1004+
.returnValue(TmpVar)
1005+
.finalize();
1006+
}
1007+
9061008
BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCopyConstructor() {
9071009
assert(!Record->isCompleteDefinition() && "record is already complete");
9081010

@@ -1048,7 +1150,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addIncrementCounterMethod() {
10481150
return BuiltinTypeMethodBuilder(*this, "IncrementCounter",
10491151
SemaRef.getASTContext().UnsignedIntTy)
10501152
.callBuiltin("__builtin_hlsl_buffer_update_counter", QualType(),
1051-
PH::Handle, getConstantIntExpr(1))
1153+
PH::CounterHandle, getConstantIntExpr(1))
10521154
.finalize();
10531155
}
10541156

@@ -1057,7 +1159,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDecrementCounterMethod() {
10571159
return BuiltinTypeMethodBuilder(*this, "DecrementCounter",
10581160
SemaRef.getASTContext().UnsignedIntTy)
10591161
.callBuiltin("__builtin_hlsl_buffer_update_counter", QualType(),
1060-
PH::Handle, getConstantIntExpr(-1))
1162+
PH::CounterHandle, getConstantIntExpr(-1))
10611163
.finalize();
10621164
}
10631165

@@ -1102,7 +1204,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addAppendMethod() {
11021204
return BuiltinTypeMethodBuilder(*this, "Append", AST.VoidTy)
11031205
.addParam("value", ElemTy)
11041206
.callBuiltin("__builtin_hlsl_buffer_update_counter", AST.UnsignedIntTy,
1105-
PH::Handle, getConstantIntExpr(1))
1207+
PH::CounterHandle, getConstantIntExpr(1))
11061208
.callBuiltin("__builtin_hlsl_resource_getpointer",
11071209
AST.getPointerType(AddrSpaceElemTy), PH::Handle,
11081210
PH::LastStmt)
@@ -1119,7 +1221,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addConsumeMethod() {
11191221
AST.getAddrSpaceQualType(ElemTy, LangAS::hlsl_device);
11201222
return BuiltinTypeMethodBuilder(*this, "Consume", ElemTy)
11211223
.callBuiltin("__builtin_hlsl_buffer_update_counter", AST.UnsignedIntTy,
1122-
PH::Handle, getConstantIntExpr(-1))
1224+
PH::CounterHandle, getConstantIntExpr(-1))
11231225
.callBuiltin("__builtin_hlsl_resource_getpointer",
11241226
AST.getPointerType(AddrSpaceElemTy), PH::Handle,
11251227
PH::LastStmt)

clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,7 @@ class BuiltinTypeDeclBuilder {
8383
BuiltinTypeDeclBuilder &addCopyAssignmentOperator();
8484

8585
// Static create methods
86-
BuiltinTypeDeclBuilder &addCreateFromBinding();
87-
BuiltinTypeDeclBuilder &addCreateFromImplicitBinding();
86+
BuiltinTypeDeclBuilder &addStaticInitializationFunctions(bool HasCounter);
8887

8988
// Builtin types methods
9089
BuiltinTypeDeclBuilder &addLoadMethods();
@@ -96,6 +95,10 @@ class BuiltinTypeDeclBuilder {
9695
BuiltinTypeDeclBuilder &addConsumeMethod();
9796

9897
private:
98+
BuiltinTypeDeclBuilder &addCreateFromBinding();
99+
BuiltinTypeDeclBuilder &addCreateFromImplicitBinding();
100+
BuiltinTypeDeclBuilder &addCreateFromBindingWithImplicitCounter();
101+
BuiltinTypeDeclBuilder &addCreateFromImplicitBindingWithImplicitCounter();
99102
BuiltinTypeDeclBuilder &addResourceMember(StringRef MemberName,
100103
ResourceClass RC, bool IsROV,
101104
bool RawBuffer, bool IsCounter,

clang/lib/Sema/HLSLExternalSemaSource.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,7 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
236236
.addDefaultHandleConstructor()
237237
.addCopyConstructor()
238238
.addCopyAssignmentOperator()
239-
.addCreateFromBinding()
240-
.addCreateFromImplicitBinding();
239+
.addStaticInitializationFunctions(HasCounter);
241240
}
242241

243242
// This function is responsible for constructing the constraint expression for

0 commit comments

Comments
 (0)