Bufferization framework replacement?

I’ve got a transformation which looks nearly identical to bufferization. I’ve got a function-like op with some arguments and results which I need to mutate the types and make them all arguments along with all of the invocations of said function-like op. The documentation on bufferization here Bufferization on MLIR - MLIR (llvm.org) describes exactly what I need. It was recently removed but I can’t seem to find a direct replacement.

I’ve seen the “2020-11-19 ODM: Type Conversions the Not-So-Hard Way” presentation, but the bufferization part seems to only cover the new bufferization passes functionality and usage. The second part (which I’ve found helpful) is just about Dialect/Type conversions and doesn’t cover how to implement bufferization patterns. mlir/Transforms/Bufferize.h seems to offer code which is very specific to tensors and memrefs.

Similarly, the DialectConversion API doesn’t seem to know about function-like signature conversions in that it doesn’t have any hooks for dealing with converting the call ops the way the old bufferization framework had (according to the outdated docs). I might be wrong about that – there may be some magic behind the scenes which I missed.

So is there a replacement which’ll handle both the function-like op conversion and the call-like op conversions? If so, could someone point me at some documentation, the C++ API, or an example use?

~John

That functionality was removed because it didn’t make sense to have it coupled with bufferization. The new code that does the equivalent thing (which now happens as a separate step after bufferization, if a user wants it at all, which they usually don’t) is BufferResultsToOutParams (code, test).

In your case, if we need to truly do an atomic type conversion + conversion to out params, then I think what we need is basically a more powerful version of populateFuncOpTypeConversionPattern and populateCallOpTypeConversionPattern that takes the appropriate callbacks (which we probably want to put in a new Transforms/ConvertToOutParams.{h,cpp}). The main one off the top of my head is a callback that lets it know how to “allocate” the out param (analogous to this line used when updating calls in BufferResultsToOutParams). Then we can simply rebase BufferResultsToOutParams on those patterns.

If I might tempt you into a yak shave… it sounds like you are dealing with a non-std.func function-like op… we currently have an issue which is that FunctionLike / CallOpInterface aren’t powerful enough to let us do these sorts of transformations generically (which requires mutating the op generically in certain ways that those interfaces don’t currently expose). It would be amazing to add that functionality and then update these two motivating use cases:

  • change BufferResultsToOutParams to be pattern based as described above, and also make the underlying patterns be generic (to the type conversion being done and to the FunctionLike / CallOpInterface ops involved), so that they can work for your use case as well.
  • rebase DecomposeCallGraphTypes (code, test) on that same infra, which allows moving it out of Standard/Transforms. It’s currently not in lib/Transforms because it is hardcoded to std.func/call (the fact that BufferResultToOutParams is in lib/Transforms can be considered somewhat of a bug as well – it has the same restriction)

Both passes are examples of localized mutations of call graph related ops that needs to be consistent across the entire module.

FYI, I’ll be on vacation for the next two weeks, sorry for dropping off!

Would it make a difference if I could break up the “move result to arg” (in both the function and call op) and the type conversion (also in both places)?

I don’t have time right now to shave a hairless yak! Sorry.

The CIRCT sub-project has all sorts of function-like and callOpInterface ops, if you’re looking for more potential use-cases. I think I’m the first one to do this sort of conversion.

The BufferResultsToOutParams.cpp code helps a lot as an example of what I need to do. I’ll make sure to note the differences and report them back here for a potential future improvement.

You and the rest of the country! I was concerned it was already too late to get a response, so thanks! Have a good time!

I agree that circuits have lots of FunctionLike ops, and I’m happy to help with improvements there. Maybe we can revisit this in the new year.

@jdd here’s an example in CIRCT that is using visitors to replace the types of a module’s arguments and also update its instances. It’s a little different than your use-case, but that pass just uses the helpers on FunctionLike and the visitors in CIRCT.

Coming back to this because I was just writing a pattern identical to FuncOpSignatureConversion, except it worked with a different FunctionLike operation we have in CIRCT. I spent a little time generalizing that pattern to work with any operation that hasTrait<OpTrait::FunctionLike> instead of just FuncOp. Is this generalization something the community would be interested in? I can put together a patch if so and we can discuss further.

Yes, this would be useful!

Ok, I will clean up my local changes and send a patch.

1 Like

FYI, this change has landed, which generalizes the default signature conversion pattern to support not just FuncOp, but any FunctionLike op that uses FunctionType for its signature.

1 Like