[clang] [llvm] [HLSL] Add `Increment`/`DecrementCounter` methods to structured buffers (PR #114148)
Tex Riddell via cfe-commits
cfe-commits at lists.llvm.org
Thu Nov 7 16:53:20 PST 2024
================
@@ -343,27 +336,224 @@ struct TemplateParameterListBuilder {
Params.clear();
QualType T = Builder.Template->getInjectedClassNameSpecialization();
- T = S.Context.getInjectedClassNameType(Builder.Record, T);
+ T = AST.getInjectedClassNameType(Builder.Record, T);
return Builder;
}
};
+
+// Builder for methods of builtin types. Allows adding methods to builtin types
+// using the builder pattern like this:
+//
+// BuiltinTypeMethodBuilder(Sema, RecordBuilder, "MethodName", ReturnType)
+// .addParam("param_name", Type, InOutModifier)
+// .callBuiltin("buildin_name", { BuiltinParams })
+// .finalizeMethod();
+//
+// 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 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.
+struct BuiltinTypeMethodBuilder {
+ struct MethodParam {
+ const IdentifierInfo &NameII;
+ QualType Ty;
+ HLSLParamModifierAttr::Spelling Modifier;
+ MethodParam(const IdentifierInfo &NameII, QualType Ty,
+ HLSLParamModifierAttr::Spelling Modifier)
+ : NameII(NameII), Ty(Ty), Modifier(Modifier) {}
+ };
+
+ BuiltinTypeDeclBuilder &DeclBuilder;
+ DeclarationNameInfo NameInfo;
+ QualType ReturnTy;
+ CXXMethodDecl *Method;
+ llvm::SmallVector<MethodParam> Params;
+ llvm::SmallVector<Stmt *> StmtsList;
+
+public:
+ BuiltinTypeMethodBuilder(Sema &S, BuiltinTypeDeclBuilder &DB, StringRef Name,
+ QualType ReturnTy)
+ : DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr) {
+ const IdentifierInfo &II =
+ S.getASTContext().Idents.get(Name, tok::TokenKind::identifier);
+ NameInfo = DeclarationNameInfo(DeclarationName(&II), SourceLocation());
+ }
+
+ BuiltinTypeMethodBuilder &addParam(StringRef Name, QualType Ty,
+ HLSLParamModifierAttr::Spelling Modifier =
+ HLSLParamModifierAttr::Keyword_in) {
+ assert(Method == nullptr && "Cannot add param, method already created");
+
+ const IdentifierInfo &II = DeclBuilder.S.getASTContext().Idents.get(
+ Name, tok::TokenKind::identifier);
+ Params.emplace_back(II, Ty, Modifier);
+ return *this;
+ }
+
+private:
+ void createMethodDecl() {
+ assert(Method == nullptr && "Method already created");
+
+ // create method type
+ ASTContext &AST = DeclBuilder.S.getASTContext();
+ SmallVector<QualType> ParamTypes;
+ for (auto &MP : Params)
+ ParamTypes.emplace_back(MP.Ty);
+ QualType MethodTy = AST.getFunctionType(ReturnTy, ParamTypes,
+ FunctionProtoType::ExtProtoInfo());
+
+ // create method decl
+ auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation());
+ 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>();
+ unsigned i = 0;
+ for (auto &MP : Params) {
+ ParmVarDecl *Parm = ParmVarDecl::Create(
+ AST, Method->getDeclContext(), SourceLocation(), SourceLocation(),
+ &MP.NameII, MP.Ty,
+ AST.getTrivialTypeSourceInfo(MP.Ty, SourceLocation()), SC_None,
+ nullptr);
+ if (MP.Modifier != HLSLParamModifierAttr::Keyword_in) {
+ auto *Mod =
+ HLSLParamModifierAttr::Create(AST, SourceRange(), MP.Modifier);
+ Parm->addAttr(Mod);
+ }
+ ParmDecls.push_back(Parm);
+ FnProtoLoc.setParam(i++, Parm);
+ }
+ Method->setParams({ParmDecls});
+ }
+
+ void addResourceHandleToParms(SmallVector<Expr *> &Parms) {
+ ASTContext &AST = DeclBuilder.S.getASTContext();
+ FieldDecl *HandleField = DeclBuilder.getResourceHandleField();
+ auto *This = CXXThisExpr::Create(
+ AST, SourceLocation(), Method->getFunctionObjectParameterType(), true);
+ Parms.push_back(MemberExpr::CreateImplicit(AST, This, false, HandleField,
+ HandleField->getType(),
+ VK_LValue, OK_Ordinary));
+ }
+
+public:
+ ~BuiltinTypeMethodBuilder() { finalizeMethod(); }
+
+ BuiltinTypeMethodBuilder &
+ callBuiltin(StringRef BuiltinName, ArrayRef<Expr *> CallParms,
+ bool AddResourceHandleAsFirstArg = true) {
+
+ // The first statement added to a method creates the declaration.
+ if (!Method)
+ createMethodDecl();
+
+ ASTContext &AST = DeclBuilder.S.getASTContext();
+ FunctionDecl *FD = lookupBuiltinFunction(DeclBuilder.S, BuiltinName);
+ DeclRefExpr *DRE = DeclRefExpr::Create(
+ AST, NestedNameSpecifierLoc(), SourceLocation(), FD, false,
+ FD->getNameInfo(), FD->getType(), VK_PRValue);
+
+ SmallVector<Expr *> NewCallParms;
+ if (AddResourceHandleAsFirstArg) {
+ addResourceHandleToParms(NewCallParms);
+ for (auto *P : CallParms)
+ NewCallParms.push_back(P);
+ }
+
+ Expr *Call = CallExpr::Create(
+ AST, DRE, AddResourceHandleAsFirstArg ? NewCallParms : CallParms,
+ FD->getReturnType(), VK_PRValue, SourceLocation(), FPOptionsOverride());
+ StmtsList.push_back(Call);
+ return *this;
+ }
+
+ BuiltinTypeDeclBuilder &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?");
+
+ if (!Method->hasBody()) {
+ ASTContext &AST = DeclBuilder.S.getASTContext();
+ if (ReturnTy != AST.VoidTy && !StmtsList.empty()) {
----------------
tex3d wrote:
Shouldn't we assert for this case?
```suggestion
assert(ReturnTy == AST.VoidTy || !StmtsList.empty() &&
"nothing to return from non-void method");
if (ReturnTy != AST.VoidTy && !StmtsList.empty()) {
```
https://github.com/llvm/llvm-project/pull/114148
More information about the cfe-commits
mailing list