[Mlir-commits] [mlir] [mlir][transform] Add an op for replacing values with function calls (PR #78398)

Quinn Dawkins llvmlistbot at llvm.org
Wed Jan 17 06:36:55 PST 2024


================
@@ -26,4 +28,67 @@ def ApplyFuncToLLVMConversionPatternsOp : Op<Transform_Dialect,
   let assemblyFormat = "attr-dict";
 }
 
+def CastAndCallOp : Op<Transform_Dialect,
+    "func.cast_and_call",
+    [DeclareOpInterfaceMethods<TransformOpInterface>,
+     DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
+     AttrSizedOperandSegments,
+     ReportTrackingListenerFailuresOpTrait]
+        # GraphRegionNoTerminator.traits> {
+  let summary = "Casts values to the signature of a function and replaces them "
+                "with a call";
+  let description = [{
+    This transform takes a set of |input| and |output| value handles and
+    attempts to cast them to the function signature of the attached function
+    op, then builds a call to the function and replaces the users of the
+    outputs. It is the responsibility of the user to ensure that the slice of
+    the program replaced by this operation makes sense, i.e. there is no
+    verification that the inputs to this operation have any relation to the
+    outputs outside of basic dominance requirements needed for the replacement.
+
+    The casting materialization functions are specified in the graph region of
+    this op. They must implement the `TypeConversionOpInterface`. The order of
+    ops within the region is irrelevant.
+
+    The target function can be specified by a symbol name or by a handle to the
+    operation.
+
+    This transform only reads the target handles and only replaces the users of
+    the outputs with the results of the call. No handles are consumed and no
+    operations are removed. Users are expected to run cleanup separately if
+    desired.
----------------
qedawkins wrote:

I'm thinking the users are probably not worth invalidating, but I think it probably is worth invalidating the output value handles themselves. (Also `users` there is a typo, it should be `uses`). If I have a handle to some consumer I can't think of a case where I'd want to invalidate that handle because one of its producers changed. That said, the uses (outputs) probably are worth invalidating because at that point those values should have no users, unless they are used by the call itself, i.e.
```
func.func {
  %0 = foo
  %1 = bar %0
}
```
to
```
func.func {
  %0 = foo
  %1 = call @trace(%0)
  %2 = bar %1
}
```
We might not want to invalidate `%0` in this case, but I can't think of a way to "accidentally" do this, so the caller should be aware of the IR structure at this point and can always rematch `%0`. You might still be right; I haven't worked with enough examples of this op to know that I'm getting the handle invalidation rules correct here.

I was also thinking of adding a `cast_and_replace_with_call` op or something like that which takes a slice of the program and does the full replacement, so users might prefer that transform if they care about being precise with handle invalidation.

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


More information about the Mlir-commits mailing list