https://github.com/hekota created https://github.com/llvm/llvm-project/pull/131384
Updates the `BuiltinTypeMethodBuilder` to support creating constructors and use it to create the default resource constructor. This enables us to have a shared code for implementing both builtin methods and constructors and will come in handy when we add more constructors in the future. >From 47b41c88a60a7f376070b9ff779ec955eebf523a Mon Sep 17 00:00:00 2001 From: Helena Kotas <heko...@microsoft.com> Date: Wed, 12 Mar 2025 17:20:51 -0700 Subject: [PATCH 1/2] [HLSL] Create default resource constructor with BuiltinTypeMethodBuilder --- clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 126 ++++++++++-------- 1 file changed, 72 insertions(+), 54 deletions(-) diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp index db0ed3434d837..a52c6a49264c8 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp @@ -89,21 +89,24 @@ struct TemplateParameterListBuilder { // statement (unless the last statement is already a ReturnStmt). struct BuiltinTypeMethodBuilder { private: - struct MethodParam { + struct Param { const IdentifierInfo &NameII; QualType Ty; HLSLParamModifierAttr::Spelling Modifier; - MethodParam(const IdentifierInfo &NameII, QualType Ty, - HLSLParamModifierAttr::Spelling Modifier) + Param(const IdentifierInfo &NameII, QualType Ty, + HLSLParamModifierAttr::Spelling Modifier) : NameII(NameII), Ty(Ty), Modifier(Modifier) {} }; BuiltinTypeDeclBuilder &DeclBuilder; - DeclarationNameInfo NameInfo; + DeclarationName Name; QualType ReturnTy; + // method or constructor declaration (CXXConstructorDecl derives from + // CXXMethodDecl) CXXMethodDecl *Method; bool IsConst; - llvm::SmallVector<MethodParam> Params; + bool IsConstructor; + llvm::SmallVector<Param> Params; llvm::SmallVector<Stmt *> StmtsList; // Argument placeholders, inspired by std::placeholder. These are the indices @@ -122,12 +125,14 @@ struct BuiltinTypeMethodBuilder { friend BuiltinTypeDeclBuilder; BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, DeclarationName &Name, - QualType ReturnTy, bool IsConst = false) - : DeclBuilder(DB), NameInfo(DeclarationNameInfo(Name, SourceLocation())), - ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst) {} - - BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, StringRef Name, - QualType ReturnTy, bool IsConst = false); + QualType ReturnTy, bool IsConst = false, + bool IsConstructor = false) + : DeclBuilder(DB), Name(Name), ReturnTy(ReturnTy), Method(nullptr), + IsConst(IsConst), IsConstructor(IsConstructor) {} + + BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, StringRef NameStr, + QualType ReturnTy, bool IsConst = false, + bool IsConstructor = false); BuiltinTypeMethodBuilder(const BuiltinTypeMethodBuilder &Other) = delete; ~BuiltinTypeMethodBuilder() { finalizeMethod(); } @@ -148,7 +153,14 @@ struct BuiltinTypeMethodBuilder { Expr *getResourceHandleExpr(); private: - void createMethodDecl(); + void createDecl(); + + // Makes sure the declaration is created; should be called before any + // statement added or when access to 'this' is needed. + void ensureCompleteDecl() { + if (!Method) + createDecl(); + } }; TemplateParameterListBuilder::~TemplateParameterListBuilder() { @@ -323,13 +335,26 @@ Expr *BuiltinTypeMethodBuilder::convertPlaceholder(PlaceHolder PH) { } BuiltinTypeMethodBuilder::BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, - StringRef Name, + StringRef NameStr, QualType ReturnTy, - bool IsConst) - : DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst) { - const IdentifierInfo &II = - DB.SemaRef.getASTContext().Idents.get(Name, tok::TokenKind::identifier); - NameInfo = DeclarationNameInfo(DeclarationName(&II), SourceLocation()); + bool IsConst, + bool IsConstructor) + : DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst), + IsConstructor(IsConstructor) { + + assert((!NameStr.empty() || IsConstructor) && "method needs a name"); + assert(((IsConstructor && !IsConst) || !IsConstructor) && + "constructor cannot be const"); + + ASTContext &AST = DB.SemaRef.getASTContext(); + if (IsConstructor) { + Name = AST.DeclarationNames.getCXXConstructorName( + DB.Record->getTypeForDecl()->getCanonicalTypeUnqualified()); + } else { + const IdentifierInfo &II = + AST.Idents.get(NameStr, tok::TokenKind::identifier); + Name = DeclarationName(&II); + } } BuiltinTypeMethodBuilder & @@ -342,13 +367,13 @@ BuiltinTypeMethodBuilder::addParam(StringRef Name, QualType Ty, return *this; } -void BuiltinTypeMethodBuilder::createMethodDecl() { - assert(Method == nullptr && "Method already created"); +void BuiltinTypeMethodBuilder::createDecl() { + assert(Method == nullptr && "Method or constructor is already created"); - // create method type + // create method or constructor type ASTContext &AST = DeclBuilder.SemaRef.getASTContext(); SmallVector<QualType> ParamTypes; - for (MethodParam &MP : Params) + for (Param &MP : Params) ParamTypes.emplace_back(MP.Ty); FunctionProtoType::ExtProtoInfo ExtInfo; @@ -357,18 +382,26 @@ void BuiltinTypeMethodBuilder::createMethodDecl() { QualType MethodTy = AST.getFunctionType(ReturnTy, ParamTypes, ExtInfo); - // create method decl + // create method or constructor decl auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation()); - Method = CXXMethodDecl::Create( - AST, DeclBuilder.Record, SourceLocation(), NameInfo, MethodTy, TSInfo, - SC_None, false, false, ConstexprSpecKind::Unspecified, SourceLocation()); + DeclarationNameInfo NameInfo = DeclarationNameInfo(Name, SourceLocation()); + if (IsConstructor) + Method = CXXConstructorDecl::Create( + AST, DeclBuilder.Record, SourceLocation(), NameInfo, MethodTy, TSInfo, + ExplicitSpecifier(), false, true, false, + ConstexprSpecKind::Unspecified); + else + Method = + CXXMethodDecl::Create(AST, DeclBuilder.Record, SourceLocation(), + NameInfo, MethodTy, TSInfo, SC_None, false, false, + ConstexprSpecKind::Unspecified, SourceLocation()); // create params & set them to the function prototype SmallVector<ParmVarDecl *> ParmDecls; auto FnProtoLoc = Method->getTypeSourceInfo()->getTypeLoc().getAs<FunctionProtoTypeLoc>(); for (int I = 0, E = Params.size(); I != E; I++) { - MethodParam &MP = Params[I]; + Param &MP = Params[I]; ParmVarDecl *Parm = ParmVarDecl::Create( AST, Method->getDeclContext(), SourceLocation(), SourceLocation(), &MP.NameII, MP.Ty, @@ -386,10 +419,7 @@ void BuiltinTypeMethodBuilder::createMethodDecl() { } Expr *BuiltinTypeMethodBuilder::getResourceHandleExpr() { - // The first statement added to a method or access to 'this' creates the - // declaration. - if (!Method) - createMethodDecl(); + ensureCompleteDecl(); ASTContext &AST = DeclBuilder.SemaRef.getASTContext(); CXXThisExpr *This = CXXThisExpr::Create( @@ -407,10 +437,7 @@ BuiltinTypeMethodBuilder::callBuiltin(StringRef BuiltinName, std::array<Expr *, sizeof...(ArgSpecs)> Args{ convertPlaceholder(std::forward<Ts>(ArgSpecs))...}; - // The first statement added to a method or access to 'this` creates the - // declaration. - if (!Method) - createMethodDecl(); + ensureCompleteDecl(); ASTContext &AST = DeclBuilder.SemaRef.getASTContext(); FunctionDecl *FD = lookupBuiltinFunction(DeclBuilder.SemaRef, BuiltinName); @@ -454,8 +481,8 @@ BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::dereference(T Ptr) { BuiltinTypeDeclBuilder &BuiltinTypeMethodBuilder::finalizeMethod() { assert(!DeclBuilder.Record->isCompleteDefinition() && "record is already complete"); - assert(Method != nullptr && - "method decl not created; are you missing a call to build the body?"); + + ensureCompleteDecl(); if (!Method->hasBody()) { ASTContext &AST = DeclBuilder.SemaRef.getASTContext(); @@ -600,27 +627,18 @@ BuiltinTypeDeclBuilder::addHandleMember(ResourceClass RC, ResourceKind RK, return *this; } +// Adds default constructor to the resource class: +// Resource::Resource() BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDefaultHandleConstructor() { if (Record->isCompleteDefinition()) return *this; - ASTContext &AST = Record->getASTContext(); - QualType ConstructorType = - AST.getFunctionType(AST.VoidTy, {}, FunctionProtoType::ExtProtoInfo()); - - CanQualType CanTy = Record->getTypeForDecl()->getCanonicalTypeUnqualified(); - DeclarationName Name = AST.DeclarationNames.getCXXConstructorName(CanTy); - CXXConstructorDecl *Constructor = CXXConstructorDecl::Create( - AST, Record, SourceLocation(), - DeclarationNameInfo(Name, SourceLocation()), ConstructorType, - AST.getTrivialTypeSourceInfo(ConstructorType, SourceLocation()), - ExplicitSpecifier(), false, true, false, ConstexprSpecKind::Unspecified); - - Constructor->setBody(CompoundStmt::Create( - AST, {}, FPOptionsOverride(), SourceLocation(), SourceLocation())); - Constructor->setAccess(AccessSpecifier::AS_public); - Record->addDecl(Constructor); - return *this; + // FIXME: initialize handle to poison value; this can be added after + // resource constructor from binding is implemented, otherwise the handle + // value will get overwritten. + return BuiltinTypeMethodBuilder(*this, "", SemaRef.getASTContext().VoidTy, + false, true) + .finalizeMethod(); } BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addArraySubscriptOperators() { >From 4301a06b4dc2f96de3ea76e23685fa8b4b99e534 Mon Sep 17 00:00:00 2001 From: Helena Kotas <heko...@microsoft.com> Date: Wed, 12 Mar 2025 17:51:18 -0700 Subject: [PATCH 2/2] rename finalizeMethod to finalize --- clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp index a52c6a49264c8..058525d77d99e 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp @@ -71,22 +71,23 @@ struct TemplateParameterListBuilder { // BuiltinTypeMethodBuilder(RecordBuilder, "MethodName", ReturnType) // .addParam("param_name", Type, InOutModifier) // .callBuiltin("builtin_name", BuiltinParams...) -// .finalizeMethod(); +// .finalize(); // // The builder needs to have all of the method parameters before it can create // a CXXMethodDecl. It collects them in addParam calls and when a first // method that builds the body is called or when access to 'this` is needed it // creates the CXXMethodDecl and ParmVarDecls instances. These can then be // referenced from the body building methods. Destructor or an explicit call to -// finalizeMethod() will complete the method definition. +// finalize() will complete the method definition. // // The callBuiltin helper method accepts constants via `Expr *` or placeholder // value arguments to indicate which function arguments to forward to the // builtin. // // If the method that is being built has a non-void return type the -// finalizeMethod will create a return statent with the value of the last -// statement (unless the last statement is already a ReturnStmt). +// finalize() will create a return statement with the value of the last +// statement (unless the last statement is already a ReturnStmt or the return +// value is void). struct BuiltinTypeMethodBuilder { private: struct Param { @@ -135,7 +136,7 @@ struct BuiltinTypeMethodBuilder { bool IsConstructor = false); BuiltinTypeMethodBuilder(const BuiltinTypeMethodBuilder &Other) = delete; - ~BuiltinTypeMethodBuilder() { finalizeMethod(); } + ~BuiltinTypeMethodBuilder() { finalize(); } BuiltinTypeMethodBuilder & operator=(const BuiltinTypeMethodBuilder &Other) = delete; @@ -149,7 +150,7 @@ struct BuiltinTypeMethodBuilder { template <typename TLHS, typename TRHS> BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS); template <typename T> BuiltinTypeMethodBuilder &dereference(T Ptr); - BuiltinTypeDeclBuilder &finalizeMethod(); + BuiltinTypeDeclBuilder &finalize(); Expr *getResourceHandleExpr(); private: @@ -478,7 +479,7 @@ BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::dereference(T Ptr) { return *this; } -BuiltinTypeDeclBuilder &BuiltinTypeMethodBuilder::finalizeMethod() { +BuiltinTypeDeclBuilder &BuiltinTypeMethodBuilder::finalize() { assert(!DeclBuilder.Record->isCompleteDefinition() && "record is already complete"); @@ -638,7 +639,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDefaultHandleConstructor() { // value will get overwritten. return BuiltinTypeMethodBuilder(*this, "", SemaRef.getASTContext().VoidTy, false, true) - .finalizeMethod(); + .finalize(); } BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addArraySubscriptOperators() { @@ -732,7 +733,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addIncrementCounterMethod() { SemaRef.getASTContext().UnsignedIntTy) .callBuiltin("__builtin_hlsl_buffer_update_counter", QualType(), PH::Handle, getConstantIntExpr(1)) - .finalizeMethod(); + .finalize(); } BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDecrementCounterMethod() { @@ -741,7 +742,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDecrementCounterMethod() { SemaRef.getASTContext().UnsignedIntTy) .callBuiltin("__builtin_hlsl_buffer_update_counter", QualType(), PH::Handle, getConstantIntExpr(-1)) - .finalizeMethod(); + .finalize(); } BuiltinTypeDeclBuilder & @@ -765,7 +766,7 @@ BuiltinTypeDeclBuilder::addHandleAccessFunction(DeclarationName &Name, .callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy, PH::Handle, PH::_0) .dereference(PH::LastStmt) - .finalizeMethod(); + .finalize(); } BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addAppendMethod() { @@ -780,7 +781,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addAppendMethod() { AST.getPointerType(ElemTy), PH::Handle, PH::LastStmt) .dereference(PH::LastStmt) .assign(PH::LastStmt, PH::_0) - .finalizeMethod(); + .finalize(); } BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addConsumeMethod() { @@ -793,7 +794,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addConsumeMethod() { .callBuiltin("__builtin_hlsl_resource_getpointer", AST.getPointerType(ElemTy), PH::Handle, PH::LastStmt) .dereference(PH::LastStmt) - .finalizeMethod(); + .finalize(); } } // namespace hlsl _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits