[clang] [llvm] [HLSL] Add `Increment`/`DecrementCounter` methods to structured buffers (PR #114148)

Helena Kotas via cfe-commits cfe-commits at lists.llvm.org
Wed Nov 13 23:59:27 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.
----------------
hekota wrote:

I am trying to keep the same builder pattern for the interface as we already have in the `BuiltinTypeDeclBuilder`. I did have more than just one use case in mind I designed it, but at this moment I can only add building methods that can be tested as part of task llvm/llvm-project#113513. We are going to add more building methods as needed as we implement the rest of the HLSL methods.

For example this is how the `Append(T value)` method on the `AppendStructuredBuffer` would look like:

```
BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addIncrementCounterMethod() {
  ASTContext &AST = S.getASTContext();
  Expr *One = IntegerLiteral::Create(...);
  return BuiltinTypeMethodBuilder(S, *this, "Append", AST.VoidTy)
      .addParam("value", getFirstTemplateTypeParam())
      .callBuiltin("__builtin_hlsl_buffer_update_counter", {One})
      .callBuiltinForwardParams("__builtin_hlsl_buffer_load") 
      .finalizeMethod();
}
```
The `callBuiltinForwardParams` passes in the resource handle as the first argument of the builtin (unless that is not desired and the method takes a bool to disable that) and then it adds/forwards all of the Append method params to the builtin call (in this the case the `value`). I believe `callBuiltinForwardParams` will probably be the most commonly used case when we implement other HLSL methods.

Without the implicit behavior it might look like this:
```
BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addAppendMethod() {
  ASTContext &AST = S.getASTContext();
  Expr *One = IntegerLiteral::Create(...);
  BuiltinTypeMethodBuilder MB =
      BuiltinTypeMethodBuilder(S, *this, "Append", AST.UnsignedIntTy);
  return MB
      .addParam("value", getFirstTemplateTypeParam())
      .addStmt(callBuiltin(S, "__builtin_hlsl_buffer_update_counter",
                           {MB.getResourceHandleExpr(), One}))
      .returnExpr(callBuiltin(S, "__builtin_hlsl_buffer_load",
                              {MB.getResourceHandleExpr(), MB.getMethodArg(0)}))
}
```
I think the first case looks much simpler. As long as the implicit behavior is well documented and used often enough, I would prefer to keep it like that. I will add more comments pointing out the implicit behavior.

https://github.com/llvm/llvm-project/pull/114148


More information about the cfe-commits mailing list