Skip to content

Commit b0bb86e

Browse files
authored
[HLSL][NFC] Use method builder to create default resource constructor (#131384)
Updates `BuiltinTypeMethodBuilder` helper class to support creation of constructors and updates the code that creates default constructor for resource classes to use it. This enables us to share code when creating builtin methods and constructors and will come in handy when we add more constructors in the future. Depends on #131032.
1 parent bc37fea commit b0bb86e

File tree

1 file changed

+94
-76
lines changed

1 file changed

+94
-76
lines changed

clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp

Lines changed: 94 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -67,45 +67,50 @@ struct TemplateParameterListBuilder {
6767
BuiltinTypeDeclBuilder &finalizeTemplateArgs(ConceptDecl *CD = nullptr);
6868
};
6969

70-
// Builder for methods of builtin types. Allows adding methods to builtin types
71-
// using the builder pattern like this:
70+
// Builder for methods or constructors of builtin types. Allows creating methods
71+
// or constructors of builtin types using the builder pattern like this:
7272
//
7373
// BuiltinTypeMethodBuilder(RecordBuilder, "MethodName", ReturnType)
7474
// .addParam("param_name", Type, InOutModifier)
7575
// .callBuiltin("builtin_name", BuiltinParams...)
76-
// .finalizeMethod();
76+
// .finalize();
7777
//
78-
// The builder needs to have all of the method parameters before it can create
79-
// a CXXMethodDecl. It collects them in addParam calls and when a first
80-
// method that builds the body is called or when access to 'this` is needed it
81-
// creates the CXXMethodDecl and ParmVarDecls instances. These can then be
82-
// referenced from the body building methods. Destructor or an explicit call to
83-
// finalizeMethod() will complete the method definition.
78+
// The builder needs to have all of the parameters before it can create
79+
// a CXXMethodDecl or CXXConstructorDecl. It collects them in addParam calls and
80+
// when a first method that builds the body is called or when access to 'this`
81+
// is needed it creates the CXXMethodDecl/CXXConstructorDecl and ParmVarDecls
82+
// instances. These can then be referenced from the body building methods.
83+
// Destructor or an explicit call to finalize() will complete the method
84+
// definition.
8485
//
8586
// The callBuiltin helper method accepts constants via `Expr *` or placeholder
8687
// value arguments to indicate which function arguments to forward to the
8788
// builtin.
8889
//
8990
// If the method that is being built has a non-void return type the
90-
// finalizeMethod will create a return statent with the value of the last
91-
// statement (unless the last statement is already a ReturnStmt).
91+
// finalize() will create a return statement with the value of the last
92+
// statement (unless the last statement is already a ReturnStmt or the return
93+
// value is void).
9294
struct BuiltinTypeMethodBuilder {
9395
private:
94-
struct MethodParam {
96+
struct Param {
9597
const IdentifierInfo &NameII;
9698
QualType Ty;
9799
HLSLParamModifierAttr::Spelling Modifier;
98-
MethodParam(const IdentifierInfo &NameII, QualType Ty,
99-
HLSLParamModifierAttr::Spelling Modifier)
100+
Param(const IdentifierInfo &NameII, QualType Ty,
101+
HLSLParamModifierAttr::Spelling Modifier)
100102
: NameII(NameII), Ty(Ty), Modifier(Modifier) {}
101103
};
102104

103105
BuiltinTypeDeclBuilder &DeclBuilder;
104-
DeclarationNameInfo NameInfo;
106+
DeclarationName Name;
105107
QualType ReturnTy;
108+
// method or constructor declaration
109+
// (CXXConstructorDecl derives from CXXMethodDecl)
106110
CXXMethodDecl *Method;
107111
bool IsConst;
108-
llvm::SmallVector<MethodParam> Params;
112+
bool IsCtor;
113+
llvm::SmallVector<Param> Params;
109114
llvm::SmallVector<Stmt *> StmtsList;
110115

111116
// Argument placeholders, inspired by std::placeholder. These are the indices
@@ -124,15 +129,17 @@ struct BuiltinTypeMethodBuilder {
124129
friend BuiltinTypeDeclBuilder;
125130

126131
BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, DeclarationName &Name,
127-
QualType ReturnTy, bool IsConst = false)
128-
: DeclBuilder(DB), NameInfo(DeclarationNameInfo(Name, SourceLocation())),
129-
ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst) {}
130-
131-
BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, StringRef Name,
132-
QualType ReturnTy, bool IsConst = false);
132+
QualType ReturnTy, bool IsConst = false,
133+
bool IsCtor = false)
134+
: DeclBuilder(DB), Name(Name), ReturnTy(ReturnTy), Method(nullptr),
135+
IsConst(IsConst), IsCtor(IsCtor) {}
136+
137+
BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, StringRef NameStr,
138+
QualType ReturnTy, bool IsConst = false,
139+
bool IsCtor = false);
133140
BuiltinTypeMethodBuilder(const BuiltinTypeMethodBuilder &Other) = delete;
134141

135-
~BuiltinTypeMethodBuilder() { finalizeMethod(); }
142+
~BuiltinTypeMethodBuilder() { finalize(); }
136143

137144
BuiltinTypeMethodBuilder &
138145
operator=(const BuiltinTypeMethodBuilder &Other) = delete;
@@ -146,11 +153,18 @@ struct BuiltinTypeMethodBuilder {
146153
template <typename TLHS, typename TRHS>
147154
BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS);
148155
template <typename T> BuiltinTypeMethodBuilder &dereference(T Ptr);
149-
BuiltinTypeDeclBuilder &finalizeMethod();
156+
BuiltinTypeDeclBuilder &finalize();
150157
Expr *getResourceHandleExpr();
151158

152159
private:
153-
void createMethodDecl();
160+
void createDecl();
161+
162+
// Makes sure the declaration is created; should be called before any
163+
// statement added to the body or when access to 'this' is needed.
164+
void ensureCompleteDecl() {
165+
if (!Method)
166+
createDecl();
167+
}
154168
};
155169

156170
TemplateParameterListBuilder::~TemplateParameterListBuilder() {
@@ -325,13 +339,24 @@ Expr *BuiltinTypeMethodBuilder::convertPlaceholder(PlaceHolder PH) {
325339
}
326340

327341
BuiltinTypeMethodBuilder::BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB,
328-
StringRef Name,
342+
StringRef NameStr,
329343
QualType ReturnTy,
330-
bool IsConst)
331-
: DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst) {
332-
const IdentifierInfo &II =
333-
DB.SemaRef.getASTContext().Idents.get(Name, tok::TokenKind::identifier);
334-
NameInfo = DeclarationNameInfo(DeclarationName(&II), SourceLocation());
344+
bool IsConst, bool IsCtor)
345+
: DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst),
346+
IsCtor(IsCtor) {
347+
348+
assert((!NameStr.empty() || IsCtor) && "method needs a name");
349+
assert(((IsCtor && !IsConst) || !IsCtor) && "constructor cannot be const");
350+
351+
ASTContext &AST = DB.SemaRef.getASTContext();
352+
if (IsCtor) {
353+
Name = AST.DeclarationNames.getCXXConstructorName(
354+
DB.Record->getTypeForDecl()->getCanonicalTypeUnqualified());
355+
} else {
356+
const IdentifierInfo &II =
357+
AST.Idents.get(NameStr, tok::TokenKind::identifier);
358+
Name = DeclarationName(&II);
359+
}
335360
}
336361

337362
BuiltinTypeMethodBuilder &
@@ -344,33 +369,41 @@ BuiltinTypeMethodBuilder::addParam(StringRef Name, QualType Ty,
344369
return *this;
345370
}
346371

347-
void BuiltinTypeMethodBuilder::createMethodDecl() {
348-
assert(Method == nullptr && "Method already created");
372+
void BuiltinTypeMethodBuilder::createDecl() {
373+
assert(Method == nullptr && "Method or constructor is already created");
349374

350-
// create method type
375+
// create method or constructor type
351376
ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
352377
SmallVector<QualType> ParamTypes;
353-
for (MethodParam &MP : Params)
378+
for (Param &MP : Params)
354379
ParamTypes.emplace_back(MP.Ty);
355380

356381
FunctionProtoType::ExtProtoInfo ExtInfo;
357382
if (IsConst)
358383
ExtInfo.TypeQuals.addConst();
359384

360-
QualType MethodTy = AST.getFunctionType(ReturnTy, ParamTypes, ExtInfo);
361-
362-
// create method decl
363-
auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation());
364-
Method = CXXMethodDecl::Create(
365-
AST, DeclBuilder.Record, SourceLocation(), NameInfo, MethodTy, TSInfo,
366-
SC_None, false, false, ConstexprSpecKind::Unspecified, SourceLocation());
385+
QualType FuncTy = AST.getFunctionType(ReturnTy, ParamTypes, ExtInfo);
386+
387+
// create method or constructor decl
388+
auto *TSInfo = AST.getTrivialTypeSourceInfo(FuncTy, SourceLocation());
389+
DeclarationNameInfo NameInfo = DeclarationNameInfo(Name, SourceLocation());
390+
if (IsCtor)
391+
Method = CXXConstructorDecl::Create(
392+
AST, DeclBuilder.Record, SourceLocation(), NameInfo, FuncTy, TSInfo,
393+
ExplicitSpecifier(), false, true, false,
394+
ConstexprSpecKind::Unspecified);
395+
else
396+
Method =
397+
CXXMethodDecl::Create(AST, DeclBuilder.Record, SourceLocation(),
398+
NameInfo, FuncTy, TSInfo, SC_None, false, false,
399+
ConstexprSpecKind::Unspecified, SourceLocation());
367400

368401
// create params & set them to the function prototype
369402
SmallVector<ParmVarDecl *> ParmDecls;
370403
auto FnProtoLoc =
371404
Method->getTypeSourceInfo()->getTypeLoc().getAs<FunctionProtoTypeLoc>();
372405
for (int I = 0, E = Params.size(); I != E; I++) {
373-
MethodParam &MP = Params[I];
406+
Param &MP = Params[I];
374407
ParmVarDecl *Parm = ParmVarDecl::Create(
375408
AST, Method->getDeclContext(), SourceLocation(), SourceLocation(),
376409
&MP.NameII, MP.Ty,
@@ -388,10 +421,7 @@ void BuiltinTypeMethodBuilder::createMethodDecl() {
388421
}
389422

390423
Expr *BuiltinTypeMethodBuilder::getResourceHandleExpr() {
391-
// The first statement added to a method or access to 'this' creates the
392-
// declaration.
393-
if (!Method)
394-
createMethodDecl();
424+
ensureCompleteDecl();
395425

396426
ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
397427
CXXThisExpr *This = CXXThisExpr::Create(
@@ -409,10 +439,7 @@ BuiltinTypeMethodBuilder::callBuiltin(StringRef BuiltinName,
409439
std::array<Expr *, sizeof...(ArgSpecs)> Args{
410440
convertPlaceholder(std::forward<Ts>(ArgSpecs))...};
411441

412-
// The first statement added to a method or access to 'this` creates the
413-
// declaration.
414-
if (!Method)
415-
createMethodDecl();
442+
ensureCompleteDecl();
416443

417444
ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
418445
FunctionDecl *FD = lookupBuiltinFunction(DeclBuilder.SemaRef, BuiltinName);
@@ -453,11 +480,11 @@ BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::dereference(T Ptr) {
453480
return *this;
454481
}
455482

456-
BuiltinTypeDeclBuilder &BuiltinTypeMethodBuilder::finalizeMethod() {
483+
BuiltinTypeDeclBuilder &BuiltinTypeMethodBuilder::finalize() {
457484
assert(!DeclBuilder.Record->isCompleteDefinition() &&
458485
"record is already complete");
459-
assert(Method != nullptr &&
460-
"method decl not created; are you missing a call to build the body?");
486+
487+
ensureCompleteDecl();
461488

462489
if (!Method->hasBody()) {
463490
ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
@@ -599,27 +626,18 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addHandleMember(
599626
return *this;
600627
}
601628

629+
// Adds default constructor to the resource class:
630+
// Resource::Resource()
602631
BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDefaultHandleConstructor() {
603632
if (Record->isCompleteDefinition())
604633
return *this;
605-
ASTContext &AST = Record->getASTContext();
606634

607-
QualType ConstructorType =
608-
AST.getFunctionType(AST.VoidTy, {}, FunctionProtoType::ExtProtoInfo());
609-
610-
CanQualType CanTy = Record->getTypeForDecl()->getCanonicalTypeUnqualified();
611-
DeclarationName Name = AST.DeclarationNames.getCXXConstructorName(CanTy);
612-
CXXConstructorDecl *Constructor = CXXConstructorDecl::Create(
613-
AST, Record, SourceLocation(),
614-
DeclarationNameInfo(Name, SourceLocation()), ConstructorType,
615-
AST.getTrivialTypeSourceInfo(ConstructorType, SourceLocation()),
616-
ExplicitSpecifier(), false, true, false, ConstexprSpecKind::Unspecified);
617-
618-
Constructor->setBody(CompoundStmt::Create(
619-
AST, {}, FPOptionsOverride(), SourceLocation(), SourceLocation()));
620-
Constructor->setAccess(AccessSpecifier::AS_public);
621-
Record->addDecl(Constructor);
622-
return *this;
635+
// FIXME: initialize handle to poison value; this can be added after
636+
// resource constructor from binding is implemented, otherwise the handle
637+
// value will get overwritten.
638+
return BuiltinTypeMethodBuilder(*this, "", SemaRef.getASTContext().VoidTy,
639+
false, true)
640+
.finalize();
623641
}
624642

625643
BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addArraySubscriptOperators() {
@@ -713,7 +731,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addIncrementCounterMethod() {
713731
SemaRef.getASTContext().UnsignedIntTy)
714732
.callBuiltin("__builtin_hlsl_buffer_update_counter", QualType(),
715733
PH::Handle, getConstantIntExpr(1))
716-
.finalizeMethod();
734+
.finalize();
717735
}
718736

719737
BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDecrementCounterMethod() {
@@ -722,7 +740,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDecrementCounterMethod() {
722740
SemaRef.getASTContext().UnsignedIntTy)
723741
.callBuiltin("__builtin_hlsl_buffer_update_counter", QualType(),
724742
PH::Handle, getConstantIntExpr(-1))
725-
.finalizeMethod();
743+
.finalize();
726744
}
727745

728746
BuiltinTypeDeclBuilder &
@@ -746,7 +764,7 @@ BuiltinTypeDeclBuilder::addHandleAccessFunction(DeclarationName &Name,
746764
.callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy, PH::Handle,
747765
PH::_0)
748766
.dereference(PH::LastStmt)
749-
.finalizeMethod();
767+
.finalize();
750768
}
751769

752770
BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addAppendMethod() {
@@ -761,7 +779,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addAppendMethod() {
761779
AST.getPointerType(ElemTy), PH::Handle, PH::LastStmt)
762780
.dereference(PH::LastStmt)
763781
.assign(PH::LastStmt, PH::_0)
764-
.finalizeMethod();
782+
.finalize();
765783
}
766784

767785
BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addConsumeMethod() {
@@ -774,7 +792,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addConsumeMethod() {
774792
.callBuiltin("__builtin_hlsl_resource_getpointer",
775793
AST.getPointerType(ElemTy), PH::Handle, PH::LastStmt)
776794
.dereference(PH::LastStmt)
777-
.finalizeMethod();
795+
.finalize();
778796
}
779797

780798
} // namespace hlsl

0 commit comments

Comments
 (0)