Skip to content

Commit dfce6ce

Browse files
committed
[HLSL] Add resource constructor with implicit binding for global resources
Adds constructor for resources with implicit binding and applies it to all resources without binding at the global scope. Adds Clang buildin function __builtin_hlsl_resource_handlefromimplicitbinding that it translated to llvm.dx|spv.resource.handlefromimplicitbinding calls. Specific bindings are assigned in DXILResourceImplicitBinding pass. Depends on #138043 Closes #136784
1 parent da838a9 commit dfce6ce

18 files changed

+335
-38
lines changed

clang/include/clang/Basic/Builtins.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4819,6 +4819,12 @@ def HLSLResourceHandleFromBinding : LangBuiltin<"HLSL_LANG"> {
48194819
let Prototype = "void(...)";
48204820
}
48214821

4822+
def HLSLResourceHandleFromImplicitBinding : LangBuiltin<"HLSL_LANG"> {
4823+
let Spellings = ["__builtin_hlsl_resource_handlefromimplicitbinding"];
4824+
let Attributes = [NoThrow];
4825+
let Prototype = "void(...)";
4826+
}
4827+
48224828
def HLSLAll : LangBuiltin<"HLSL_LANG"> {
48234829
let Spellings = ["__builtin_hlsl_all"];
48244830
let Attributes = [NoThrow, Const];

clang/include/clang/Sema/SemaHLSL.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,13 +174,20 @@ class SemaHLSL : public SemaBase {
174174
// buffer which will be created at the end of the translation unit.
175175
llvm::SmallVector<Decl *> DefaultCBufferDecls;
176176

177+
uint32_t ImplicitBindingNextOrderID = 0;
178+
177179
private:
178180
void collectResourceBindingsOnVarDecl(VarDecl *D);
179181
void collectResourceBindingsOnUserRecordDecl(const VarDecl *VD,
180182
const RecordType *RT);
181183
void processExplicitBindingsOnDecl(VarDecl *D);
182184

183185
void diagnoseAvailabilityViolations(TranslationUnitDecl *TU);
186+
187+
bool initGlobalResourceDecl(VarDecl *VD);
188+
uint32_t getNextImplicitBindingOrderID() {
189+
return ImplicitBindingNextOrderID++;
190+
}
184191
};
185192

186193
} // namespace clang

clang/lib/CodeGen/CGHLSLBuiltins.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,21 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
303303
HandleTy, CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic(),
304304
ArrayRef<Value *>{SpaceOp, RegisterOp, RangeOp, IndexOp, NonUniform});
305305
}
306+
case Builtin::BI__builtin_hlsl_resource_handlefromimplicitbinding: {
307+
llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
308+
Value *SpaceOp = EmitScalarExpr(E->getArg(1));
309+
Value *RangeOp = EmitScalarExpr(E->getArg(2));
310+
Value *IndexOp = EmitScalarExpr(E->getArg(3));
311+
Value *OrderID = EmitScalarExpr(E->getArg(4));
312+
// FIXME: NonUniformResourceIndex bit is not yet implemented
313+
// (llvm/llvm-project#135452)
314+
Value *NonUniform =
315+
llvm::ConstantInt::get(llvm::Type::getInt1Ty(getLLVMContext()), false);
316+
return Builder.CreateIntrinsic(
317+
HandleTy,
318+
CGM.getHLSLRuntime().getCreateHandleFromImplicitBindingIntrinsic(),
319+
ArrayRef<Value *>{OrderID, SpaceOp, RangeOp, IndexOp, NonUniform});
320+
}
306321
case Builtin::BI__builtin_hlsl_all: {
307322
Value *Op0 = EmitScalarExpr(E->getArg(0));
308323
return Builder.CreateIntrinsic(

clang/lib/CodeGen/CGHLSLRuntime.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ class CGHLSLRuntime {
119119
resource_getpointer)
120120
GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromBinding,
121121
resource_handlefrombinding)
122+
GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromImplicitBinding,
123+
resource_handlefromimplicitbinding)
122124
GENERATE_HLSL_INTRINSIC_FUNCTION(BufferUpdateCounter, resource_updatecounter)
123125
GENERATE_HLSL_INTRINSIC_FUNCTION(GroupMemoryBarrierWithGroupSync,
124126
group_memory_barrier_with_group_sync)

clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,26 @@ BuiltinTypeDeclBuilder::addHandleConstructorFromBinding() {
668668
.finalize();
669669
}
670670

671+
BuiltinTypeDeclBuilder &
672+
BuiltinTypeDeclBuilder::addHandleConstructorFromImplicitBinding() {
673+
if (Record->isCompleteDefinition())
674+
return *this;
675+
676+
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
677+
ASTContext &AST = SemaRef.getASTContext();
678+
QualType HandleType = getResourceHandleField()->getType();
679+
680+
return BuiltinTypeMethodBuilder(*this, "", AST.VoidTy, false, true)
681+
.addParam("spaceNo", AST.UnsignedIntTy)
682+
.addParam("range", AST.IntTy)
683+
.addParam("index", AST.UnsignedIntTy)
684+
.addParam("order_id", AST.UnsignedIntTy)
685+
.callBuiltin("__builtin_hlsl_resource_handlefromimplicitbinding",
686+
HandleType, PH::Handle, PH::_0, PH::_1, PH::_2, PH::_3)
687+
.assign(PH::Handle, PH::LastStmt)
688+
.finalize();
689+
}
690+
671691
BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addArraySubscriptOperators() {
672692
ASTContext &AST = Record->getASTContext();
673693
DeclarationName Subscript =

clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,10 @@ class BuiltinTypeDeclBuilder {
7676
AccessSpecifier Access = AccessSpecifier::AS_private);
7777
BuiltinTypeDeclBuilder &addArraySubscriptOperators();
7878

79-
// Builtin types methods
79+
// Builtin types constructors
8080
BuiltinTypeDeclBuilder &addDefaultHandleConstructor();
8181
BuiltinTypeDeclBuilder &addHandleConstructorFromBinding();
82+
BuiltinTypeDeclBuilder &addHandleConstructorFromImplicitBinding();
8283

8384
// Builtin types methods
8485
BuiltinTypeDeclBuilder &addLoadMethods();

clang/lib/Sema/HLSLExternalSemaSource.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,8 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
132132
return BuiltinTypeDeclBuilder(S, Decl)
133133
.addHandleMember(RC, IsROV, RawBuffer)
134134
.addDefaultHandleConstructor()
135-
.addHandleConstructorFromBinding();
135+
.addHandleConstructorFromBinding()
136+
.addHandleConstructorFromImplicitBinding();
136137
}
137138

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

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2427,6 +2427,20 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
24272427
TheCall->setType(ResourceTy);
24282428
break;
24292429
}
2430+
case Builtin::BI__builtin_hlsl_resource_handlefromimplicitbinding: {
2431+
ASTContext &AST = SemaRef.getASTContext();
2432+
if (SemaRef.checkArgCount(TheCall, 5) ||
2433+
CheckResourceHandle(&SemaRef, TheCall, 0) ||
2434+
CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) ||
2435+
CheckArgTypeMatches(&SemaRef, TheCall->getArg(2), AST.IntTy) ||
2436+
CheckArgTypeMatches(&SemaRef, TheCall->getArg(3), AST.UnsignedIntTy) ||
2437+
CheckArgTypeMatches(&SemaRef, TheCall->getArg(4), AST.UnsignedIntTy))
2438+
return true;
2439+
// use the type of the handle (arg0) as a return type
2440+
QualType ResourceTy = TheCall->getArg(0)->getType();
2441+
TheCall->setType(ResourceTy);
2442+
break;
2443+
}
24302444
case Builtin::BI__builtin_hlsl_and:
24312445
case Builtin::BI__builtin_hlsl_or: {
24322446
if (SemaRef.checkArgCount(TheCall, 2))
@@ -3258,8 +3272,10 @@ static bool initVarDeclWithCtor(Sema &S, VarDecl *VD,
32583272
VD->getLocation(), SourceLocation(), SourceLocation());
32593273

32603274
InitializationSequence InitSeq(S, Entity, Kind, Args);
3261-
ExprResult Init = InitSeq.Perform(S, Entity, Kind, Args);
3275+
if (InitSeq.Failed())
3276+
return false;
32623277

3278+
ExprResult Init = InitSeq.Perform(S, Entity, Kind, Args);
32633279
if (!Init.get())
32643280
return false;
32653281

@@ -3269,27 +3285,42 @@ static bool initVarDeclWithCtor(Sema &S, VarDecl *VD,
32693285
return true;
32703286
}
32713287

3272-
static bool initGlobalResourceDecl(Sema &S, VarDecl *VD) {
3288+
bool SemaHLSL::initGlobalResourceDecl(VarDecl *VD) {
3289+
std::optional<uint32_t> RegisterSlot;
3290+
uint32_t SpaceNo = 0;
32733291
HLSLResourceBindingAttr *RBA = VD->getAttr<HLSLResourceBindingAttr>();
3274-
if (!RBA || RBA->isImplicit())
3275-
// FIXME: add support for implicit binding (llvm/llvm-project#110722)
3276-
return false;
3292+
if (RBA) {
3293+
if (!RBA->isImplicit())
3294+
RegisterSlot = RBA->getSlotNumber();
3295+
SpaceNo = RBA->getSpaceNumber();
3296+
}
32773297

3278-
ASTContext &AST = S.getASTContext();
3298+
ASTContext &AST = SemaRef.getASTContext();
32793299
uint64_t UIntTySize = AST.getTypeSize(AST.UnsignedIntTy);
32803300
uint64_t IntTySize = AST.getTypeSize(AST.IntTy);
3281-
Expr *Args[] = {
3282-
IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, RBA->getSlotNumber()),
3283-
AST.UnsignedIntTy, SourceLocation()),
3284-
IntegerLiteral::Create(AST,
3285-
llvm::APInt(UIntTySize, RBA->getSpaceNumber()),
3286-
AST.UnsignedIntTy, SourceLocation()),
3287-
IntegerLiteral::Create(AST, llvm::APInt(IntTySize, 1), AST.IntTy,
3288-
SourceLocation()),
3289-
IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, 0), AST.UnsignedIntTy,
3290-
SourceLocation())};
3291-
3292-
return initVarDeclWithCtor(S, VD, Args);
3301+
IntegerLiteral *One = IntegerLiteral::Create(AST, llvm::APInt(IntTySize, 1),
3302+
AST.IntTy, SourceLocation());
3303+
IntegerLiteral *Zero = IntegerLiteral::Create(
3304+
AST, llvm::APInt(UIntTySize, 0), AST.UnsignedIntTy, SourceLocation());
3305+
IntegerLiteral *Space =
3306+
IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, SpaceNo),
3307+
AST.UnsignedIntTy, SourceLocation());
3308+
3309+
// resource with explicit binding
3310+
if (RegisterSlot.has_value()) {
3311+
IntegerLiteral *RegSlot = IntegerLiteral::Create(
3312+
AST, llvm::APInt(UIntTySize, RegisterSlot.value()), AST.UnsignedIntTy,
3313+
SourceLocation());
3314+
Expr *Args[] = {RegSlot, Space, One, Zero};
3315+
return initVarDeclWithCtor(SemaRef, VD, Args);
3316+
}
3317+
3318+
// resource with explicit binding
3319+
IntegerLiteral *OrderId = IntegerLiteral::Create(
3320+
AST, llvm::APInt(UIntTySize, getNextImplicitBindingOrderID()),
3321+
AST.UnsignedIntTy, SourceLocation());
3322+
Expr *Args[] = {Space, One, Zero, OrderId};
3323+
return initVarDeclWithCtor(SemaRef, VD, Args);
32933324
}
32943325

32953326
// Returns true if the initialization has been handled.
@@ -3307,8 +3338,9 @@ bool SemaHLSL::ActOnUninitializedVarDecl(VarDecl *VD) {
33073338
// FIXME: We currectly support only simple resources - no arrays of resources
33083339
// or resources in user defined structs.
33093340
// (llvm/llvm-project#133835, llvm/llvm-project#133837)
3310-
if (VD->getType()->isHLSLResourceRecord())
3311-
return initGlobalResourceDecl(SemaRef, VD);
3341+
// Initialize resources at the global scope
3342+
if (VD->hasGlobalStorage() && VD->getType()->isHLSLResourceRecord())
3343+
return initGlobalResourceDecl(VD);
33123344

33133345
return false;
33143346
}

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,5 +78,27 @@ RESOURCE Buffer;
7878
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'index' 'unsigned int'
7979
// CHECK-NEXT: AlwaysInlineAttr
8080

81+
// Constructor from implicit binding
82+
83+
// CHECK: CXXConstructorDecl {{.*}} [[RESOURCE]] 'void (unsigned int, int, unsigned int, unsigned int)' inline
84+
// CHECK-NEXT: ParmVarDecl {{.*}} spaceNo 'unsigned int'
85+
// CHECK-NEXT: ParmVarDecl {{.*}} range 'int'
86+
// CHECK-NEXT: ParmVarDecl {{.*}} index 'unsigned int'
87+
// CHECK-NEXT: ParmVarDecl {{.*}} order_id 'unsigned int'
88+
// CHECK-NEXT: CompoundStmt {{.*}}
89+
// CHECK-NEXT: BinaryOperator {{.*}} '='
90+
// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
91+
// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
92+
// CHECK-NEXT: CallExpr {{.*}} '__hlsl_resource_t
93+
// CHECK-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
94+
// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_handlefromimplicitbinding'
95+
// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
96+
// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
97+
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'spaceNo' 'unsigned int'
98+
// CHECK-NEXT: DeclRefExpr {{.*}} 'int' ParmVar {{.*}} 'range' 'int'
99+
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'index' 'unsigned int'
100+
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'order_id' 'unsigned int'
101+
// CHECK-NEXT: AlwaysInlineAttr
102+
81103
// CHECK-NOSUBSCRIPT-NOT: CXXMethodDecl {{.*}} operator[] 'const element_type &(unsigned int) const'
82104
// CHECK-NOSUBSCRIPT-NOT: CXXMethodDecl {{.*}} operator[] 'element_type &(unsigned int)'

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,28 @@ RESOURCE<float> Buffer;
125125
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'index' 'unsigned int'
126126
// CHECK-NEXT: AlwaysInlineAttr
127127

128+
// Constructor from implicit binding
129+
130+
// CHECK: CXXConstructorDecl {{.*}} [[RESOURCE]]<element_type> 'void (unsigned int, int, unsigned int, unsigned int)' inline
131+
// CHECK-NEXT: ParmVarDecl {{.*}} spaceNo 'unsigned int'
132+
// CHECK-NEXT: ParmVarDecl {{.*}} range 'int'
133+
// CHECK-NEXT: ParmVarDecl {{.*}} index 'unsigned int'
134+
// CHECK-NEXT: ParmVarDecl {{.*}} order_id 'unsigned int'
135+
// CHECK-NEXT: CompoundStmt {{.*}}
136+
// CHECK-NEXT: BinaryOperator {{.*}} '='
137+
// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
138+
// CHECK-NEXT: CXXThisExpr {{.*}} '[[RESOURCE]]<element_type>' lvalue implicit this
139+
// CHECK-NEXT: CallExpr {{.*}} '__hlsl_resource_t
140+
// CHECK-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
141+
// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_handlefromimplicitbinding'
142+
// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
143+
// CHECK-NEXT: CXXThisExpr {{.*}} '[[RESOURCE]]<element_type>' lvalue implicit this
144+
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'spaceNo' 'unsigned int'
145+
// CHECK-NEXT: DeclRefExpr {{.*}} 'int' ParmVar {{.*}} 'range' 'int'
146+
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'index' 'unsigned int'
147+
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'order_id' 'unsigned int'
148+
// CHECK-NEXT: AlwaysInlineAttr
149+
128150
// Subscript operators
129151

130152
// CHECK-SUBSCRIPT: CXXMethodDecl {{.*}} operator[] 'const hlsl_device element_type &(unsigned int) const'

0 commit comments

Comments
 (0)