Skip to content

Commit 0d40450

Browse files
authored
[HLSL] Add static methods for resource initialization (#155866)
Adds static methods `__createFromBinding` and `__createFromImplicitBinding` to resource classes. These methods will be used for resource initialization instead of resource constructors that take binding information. Updated proposal: llvm/wg-hlsl#336
1 parent a879be8 commit 0d40450

File tree

6 files changed

+351
-28
lines changed

6 files changed

+351
-28
lines changed

clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp

Lines changed: 175 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "clang/AST/Expr.h"
2020
#include "clang/AST/Type.h"
2121
#include "clang/Basic/SourceLocation.h"
22+
#include "clang/Basic/Specifiers.h"
2223
#include "clang/Sema/Lookup.h"
2324
#include "clang/Sema/Sema.h"
2425
#include "clang/Sema/SemaHLSL.h"
@@ -102,6 +103,13 @@ struct BuiltinTypeMethodBuilder {
102103
: NameII(NameII), Ty(Ty), Modifier(Modifier) {}
103104
};
104105

106+
struct LocalVar {
107+
StringRef Name;
108+
QualType Ty;
109+
VarDecl *Decl;
110+
LocalVar(StringRef Name, QualType Ty) : Name(Name), Ty(Ty), Decl(nullptr) {}
111+
};
112+
105113
BuiltinTypeDeclBuilder &DeclBuilder;
106114
DeclarationName Name;
107115
QualType ReturnTy;
@@ -110,6 +118,7 @@ struct BuiltinTypeMethodBuilder {
110118
CXXMethodDecl *Method;
111119
bool IsConst;
112120
bool IsCtor;
121+
StorageClass SC;
113122
llvm::SmallVector<Param> Params;
114123
llvm::SmallVector<Stmt *> StmtsList;
115124

@@ -123,20 +132,21 @@ struct BuiltinTypeMethodBuilder {
123132
enum class PlaceHolder { _0, _1, _2, _3, _4, Handle = 128, LastStmt };
124133

125134
Expr *convertPlaceholder(PlaceHolder PH);
135+
Expr *convertPlaceholder(LocalVar &Var);
126136
Expr *convertPlaceholder(Expr *E) { return E; }
127137

128138
public:
129139
friend BuiltinTypeDeclBuilder;
130140

131141
BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, DeclarationName &Name,
132142
QualType ReturnTy, bool IsConst = false,
133-
bool IsCtor = false)
143+
bool IsCtor = false, StorageClass SC = SC_None)
134144
: DeclBuilder(DB), Name(Name), ReturnTy(ReturnTy), Method(nullptr),
135-
IsConst(IsConst), IsCtor(IsCtor) {}
145+
IsConst(IsConst), IsCtor(IsCtor), SC(SC) {}
136146

137147
BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, StringRef NameStr,
138148
QualType ReturnTy, bool IsConst = false,
139-
bool IsCtor = false);
149+
bool IsCtor = false, StorageClass SC = SC_None);
140150
BuiltinTypeMethodBuilder(const BuiltinTypeMethodBuilder &Other) = delete;
141151

142152
~BuiltinTypeMethodBuilder() { finalize(); }
@@ -147,18 +157,22 @@ struct BuiltinTypeMethodBuilder {
147157
BuiltinTypeMethodBuilder &addParam(StringRef Name, QualType Ty,
148158
HLSLParamModifierAttr::Spelling Modifier =
149159
HLSLParamModifierAttr::Keyword_in);
160+
BuiltinTypeMethodBuilder &declareLocalVar(LocalVar &Var);
150161
template <typename... Ts>
151162
BuiltinTypeMethodBuilder &callBuiltin(StringRef BuiltinName,
152163
QualType ReturnType, Ts... ArgSpecs);
153164
template <typename TLHS, typename TRHS>
154165
BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS);
155166
template <typename T> BuiltinTypeMethodBuilder &dereference(T Ptr);
156-
BuiltinTypeDeclBuilder &finalize();
157-
Expr *getResourceHandleExpr();
158-
159167
template <typename T>
160-
BuiltinTypeMethodBuilder &getResourceHandle(T ResourceRecord);
168+
BuiltinTypeMethodBuilder &accessHandleFieldOnResource(T ResourceRecord);
169+
template <typename ResourceT, typename ValueT>
170+
BuiltinTypeMethodBuilder &setHandleFieldOnResource(ResourceT ResourceRecord,
171+
ValueT HandleValue);
172+
template <typename T> BuiltinTypeMethodBuilder &returnValue(T ReturnValue);
161173
BuiltinTypeMethodBuilder &returnThis();
174+
BuiltinTypeDeclBuilder &finalize();
175+
Expr *getResourceHandleExpr();
162176

163177
private:
164178
void createDecl();
@@ -339,12 +353,22 @@ Expr *BuiltinTypeMethodBuilder::convertPlaceholder(PlaceHolder PH) {
339353
ParamDecl->getType().getNonReferenceType(), VK_PRValue);
340354
}
341355

356+
Expr *BuiltinTypeMethodBuilder::convertPlaceholder(LocalVar &Var) {
357+
VarDecl *VD = Var.Decl;
358+
assert(VD && "local variable is not declared");
359+
return DeclRefExpr::Create(
360+
VD->getASTContext(), NestedNameSpecifierLoc(), SourceLocation(), VD,
361+
false, DeclarationNameInfo(VD->getDeclName(), SourceLocation()),
362+
VD->getType(), VK_LValue);
363+
}
364+
342365
BuiltinTypeMethodBuilder::BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB,
343366
StringRef NameStr,
344367
QualType ReturnTy,
345-
bool IsConst, bool IsCtor)
368+
bool IsConst, bool IsCtor,
369+
StorageClass SC)
346370
: DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst),
347-
IsCtor(IsCtor) {
371+
IsCtor(IsCtor), SC(SC) {
348372

349373
assert((!NameStr.empty() || IsCtor) && "method needs a name");
350374
assert(((IsCtor && !IsConst) || !IsCtor) && "constructor cannot be const");
@@ -394,10 +418,9 @@ void BuiltinTypeMethodBuilder::createDecl() {
394418
ExplicitSpecifier(), false, true, false,
395419
ConstexprSpecKind::Unspecified);
396420
else
397-
Method =
398-
CXXMethodDecl::Create(AST, DeclBuilder.Record, SourceLocation(),
399-
NameInfo, FuncTy, TSInfo, SC_None, false, false,
400-
ConstexprSpecKind::Unspecified, SourceLocation());
421+
Method = CXXMethodDecl::Create(
422+
AST, DeclBuilder.Record, SourceLocation(), NameInfo, FuncTy, TSInfo, SC,
423+
false, false, ConstexprSpecKind::Unspecified, SourceLocation());
401424

402425
// create params & set them to the function prototype
403426
SmallVector<ParmVarDecl *> ParmDecls;
@@ -435,19 +458,20 @@ Expr *BuiltinTypeMethodBuilder::getResourceHandleExpr() {
435458
OK_Ordinary);
436459
}
437460

438-
template <typename T>
439461
BuiltinTypeMethodBuilder &
440-
BuiltinTypeMethodBuilder::getResourceHandle(T ResourceRecord) {
462+
BuiltinTypeMethodBuilder::declareLocalVar(LocalVar &Var) {
441463
ensureCompleteDecl();
442464

443-
Expr *ResourceExpr = convertPlaceholder(ResourceRecord);
465+
assert(Var.Decl == nullptr && "local variable is already declared");
444466

445467
ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
446-
FieldDecl *HandleField = DeclBuilder.getResourceHandleField();
447-
MemberExpr *HandleExpr = MemberExpr::CreateImplicit(
448-
AST, ResourceExpr, /*IsArrow=*/false, HandleField, HandleField->getType(),
449-
VK_LValue, OK_Ordinary);
450-
StmtsList.push_back(HandleExpr);
468+
Var.Decl = VarDecl::Create(
469+
AST, Method, SourceLocation(), SourceLocation(),
470+
&AST.Idents.get(Var.Name, tok::TokenKind::identifier), Var.Ty,
471+
AST.getTrivialTypeSourceInfo(Var.Ty, SourceLocation()), SC_None);
472+
DeclStmt *DS = new (AST) clang::DeclStmt(DeclGroupRef(Var.Decl),
473+
SourceLocation(), SourceLocation());
474+
StmtsList.push_back(DS);
451475
return *this;
452476
}
453477

@@ -464,11 +488,11 @@ template <typename... Ts>
464488
BuiltinTypeMethodBuilder &
465489
BuiltinTypeMethodBuilder::callBuiltin(StringRef BuiltinName,
466490
QualType ReturnType, Ts... ArgSpecs) {
491+
ensureCompleteDecl();
492+
467493
std::array<Expr *, sizeof...(ArgSpecs)> Args{
468494
convertPlaceholder(std::forward<Ts>(ArgSpecs))...};
469495

470-
ensureCompleteDecl();
471-
472496
ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
473497
FunctionDecl *FD = lookupBuiltinFunction(DeclBuilder.SemaRef, BuiltinName);
474498
DeclRefExpr *DRE = DeclRefExpr::Create(
@@ -512,6 +536,55 @@ BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::dereference(T Ptr) {
512536
return *this;
513537
}
514538

539+
template <typename T>
540+
BuiltinTypeMethodBuilder &
541+
BuiltinTypeMethodBuilder::accessHandleFieldOnResource(T ResourceRecord) {
542+
ensureCompleteDecl();
543+
544+
Expr *ResourceExpr = convertPlaceholder(ResourceRecord);
545+
546+
ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
547+
FieldDecl *HandleField = DeclBuilder.getResourceHandleField();
548+
MemberExpr *HandleExpr = MemberExpr::CreateImplicit(
549+
AST, ResourceExpr, false, HandleField, HandleField->getType(), VK_LValue,
550+
OK_Ordinary);
551+
StmtsList.push_back(HandleExpr);
552+
return *this;
553+
}
554+
555+
template <typename ResourceT, typename ValueT>
556+
BuiltinTypeMethodBuilder &
557+
BuiltinTypeMethodBuilder::setHandleFieldOnResource(ResourceT ResourceRecord,
558+
ValueT HandleValue) {
559+
ensureCompleteDecl();
560+
561+
Expr *ResourceExpr = convertPlaceholder(ResourceRecord);
562+
Expr *HandleValueExpr = convertPlaceholder(HandleValue);
563+
564+
ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
565+
FieldDecl *HandleField = DeclBuilder.getResourceHandleField();
566+
MemberExpr *HandleMemberExpr = MemberExpr::CreateImplicit(
567+
AST, ResourceExpr, false, HandleField, HandleField->getType(), VK_LValue,
568+
OK_Ordinary);
569+
Stmt *AssignStmt = BinaryOperator::Create(
570+
DeclBuilder.SemaRef.getASTContext(), HandleMemberExpr, HandleValueExpr,
571+
BO_Assign, HandleMemberExpr->getType(), ExprValueKind::VK_PRValue,
572+
ExprObjectKind::OK_Ordinary, SourceLocation(), FPOptionsOverride());
573+
StmtsList.push_back(AssignStmt);
574+
return *this;
575+
}
576+
577+
template <typename T>
578+
BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::returnValue(T ReturnValue) {
579+
ensureCompleteDecl();
580+
581+
Expr *ReturnValueExpr = convertPlaceholder(ReturnValue);
582+
ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
583+
StmtsList.push_back(
584+
ReturnStmt::Create(AST, SourceLocation(), ReturnValueExpr, nullptr));
585+
return *this;
586+
}
587+
515588
BuiltinTypeDeclBuilder &BuiltinTypeMethodBuilder::finalize() {
516589
assert(!DeclBuilder.Record->isCompleteDefinition() &&
517590
"record is already complete");
@@ -539,7 +612,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeMethodBuilder::finalize() {
539612
Method->setBody(CompoundStmt::Create(AST, StmtsList, FPOptionsOverride(),
540613
SourceLocation(), SourceLocation()));
541614
Method->setLexicalDeclContext(DeclBuilder.Record);
542-
Method->setAccess(AccessSpecifier::AS_public);
615+
Method->setAccess(AS_public);
543616
Method->addAttr(AlwaysInlineAttr::CreateImplicit(
544617
AST, SourceRange(), AlwaysInlineAttr::CXX11_clang_always_inline));
545618
DeclBuilder.Record->addDecl(Method);
@@ -705,6 +778,82 @@ BuiltinTypeDeclBuilder::addHandleConstructorFromImplicitBinding() {
705778
.finalize();
706779
}
707780

781+
// Adds static method that initializes resource from binding:
782+
//
783+
// static Resource<T> __createFromBinding(unsigned registerNo,
784+
// unsigned spaceNo, int range,
785+
// unsigned index, const char *name) {
786+
// Resource<T> tmp;
787+
// tmp.__handle = __builtin_hlsl_resource_handlefrombinding(
788+
// tmp.__handle, registerNo, spaceNo,
789+
// range, index, name);
790+
// return tmp;
791+
// }
792+
BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCreateFromBinding() {
793+
if (Record->isCompleteDefinition())
794+
return *this;
795+
796+
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
797+
ASTContext &AST = SemaRef.getASTContext();
798+
QualType HandleType = getResourceHandleField()->getType();
799+
QualType RecordType = AST.getTypeDeclType(cast<TypeDecl>(Record));
800+
BuiltinTypeMethodBuilder::LocalVar TmpVar("tmp", RecordType);
801+
802+
return BuiltinTypeMethodBuilder(*this, "__createFromBinding", RecordType,
803+
false, false, SC_Static)
804+
.addParam("registerNo", AST.UnsignedIntTy)
805+
.addParam("spaceNo", AST.UnsignedIntTy)
806+
.addParam("range", AST.IntTy)
807+
.addParam("index", AST.UnsignedIntTy)
808+
.addParam("name", AST.getPointerType(AST.CharTy.withConst()))
809+
.declareLocalVar(TmpVar)
810+
.accessHandleFieldOnResource(TmpVar)
811+
.callBuiltin("__builtin_hlsl_resource_handlefrombinding", HandleType,
812+
PH::LastStmt, PH::_0, PH::_1, PH::_2, PH::_3, PH::_4)
813+
.setHandleFieldOnResource(TmpVar, PH::LastStmt)
814+
.returnValue(TmpVar)
815+
.finalize();
816+
}
817+
818+
// Adds static method that initializes resource from binding:
819+
//
820+
// static Resource<T> __createFromImplicitBinding(unsigned orderId,
821+
// unsigned spaceNo, int range,
822+
// unsigned index,
823+
// const char *name) {
824+
// Resource<T> tmp;
825+
// tmp.__handle = __builtin_hlsl_resource_handlefromimplicitbinding(
826+
// tmp.__handle, spaceNo,
827+
// range, index, orderId, name);
828+
// return tmp;
829+
// }
830+
BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCreateFromImplicitBinding() {
831+
if (Record->isCompleteDefinition())
832+
return *this;
833+
834+
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
835+
ASTContext &AST = SemaRef.getASTContext();
836+
QualType HandleType = getResourceHandleField()->getType();
837+
QualType RecordType = AST.getTypeDeclType(cast<TypeDecl>(Record));
838+
BuiltinTypeMethodBuilder::LocalVar TmpVar("tmp", RecordType);
839+
840+
return BuiltinTypeMethodBuilder(*this, "__createFromImplicitBinding",
841+
RecordType, false, false, SC_Static)
842+
.addParam("orderId", AST.UnsignedIntTy)
843+
.addParam("spaceNo", AST.UnsignedIntTy)
844+
.addParam("range", AST.IntTy)
845+
.addParam("index", AST.UnsignedIntTy)
846+
.addParam("name", AST.getPointerType(AST.CharTy.withConst()))
847+
.declareLocalVar(TmpVar)
848+
.accessHandleFieldOnResource(TmpVar)
849+
.callBuiltin("__builtin_hlsl_resource_handlefromimplicitbinding",
850+
HandleType, PH::LastStmt, PH::_0, PH::_1, PH::_2, PH::_3,
851+
PH::_4)
852+
.setHandleFieldOnResource(TmpVar, PH::LastStmt)
853+
.returnValue(TmpVar)
854+
.finalize();
855+
}
856+
708857
BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCopyConstructor() {
709858
if (Record->isCompleteDefinition())
710859
return *this;
@@ -719,7 +868,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCopyConstructor() {
719868
return BuiltinTypeMethodBuilder(*this, /*Name=*/"", AST.VoidTy,
720869
/*IsConst=*/false, /*IsCtor=*/true)
721870
.addParam("other", ConstRecordRefType)
722-
.getResourceHandle(PH::_0)
871+
.accessHandleFieldOnResource(PH::_0)
723872
.assign(PH::Handle, PH::LastStmt)
724873
.finalize();
725874
}
@@ -738,7 +887,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCopyAssignmentOperator() {
738887
DeclarationName Name = AST.DeclarationNames.getCXXOperatorName(OO_Equal);
739888
return BuiltinTypeMethodBuilder(*this, Name, RecordRefType)
740889
.addParam("other", ConstRecordRefType)
741-
.getResourceHandle(PH::_0)
890+
.accessHandleFieldOnResource(PH::_0)
742891
.assign(PH::Handle, PH::LastStmt)
743892
.returnThis()
744893
.finalize();

clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ class BuiltinTypeDeclBuilder {
8383
BuiltinTypeDeclBuilder &addCopyConstructor();
8484
BuiltinTypeDeclBuilder &addCopyAssignmentOperator();
8585

86+
// Static create methods
87+
BuiltinTypeDeclBuilder &addCreateFromBinding();
88+
BuiltinTypeDeclBuilder &addCreateFromImplicitBinding();
89+
8690
// Builtin types methods
8791
BuiltinTypeDeclBuilder &addLoadMethods();
8892
BuiltinTypeDeclBuilder &addIncrementCounterMethod();

clang/lib/Sema/HLSLExternalSemaSource.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
134134
.addDefaultHandleConstructor()
135135
.addCopyConstructor()
136136
.addCopyAssignmentOperator()
137+
.addCreateFromBinding()
138+
.addCreateFromImplicitBinding()
137139
.addHandleConstructorFromBinding()
138140
.addHandleConstructorFromImplicitBinding();
139141
}

0 commit comments

Comments
 (0)