Avoid inlining some functions using the func dialect?

I noticed that the FuncInlinerInterface specifies that all call operations can be inlined. How do I override this behavior? Ideally, I would like some functions with a “noinline” attribute to be not inlined even after the inlining pass.

https://mlir.llvm.org/doxygen/FuncOps_8cpp_source.html

I guess one possible way is to define a function op in our custom dialect, like what the SPIR-V dialect does.

We are generally missing a proper cost model for the inliner. Designing and implementing that would be nice. The first step towards that could be proposing an attribute that can be used for any op that implements the inliner interfaces.

Thanks for your reply. That seems like a reasonable approach. Is there anyone has started working on it?

Maybe one of @gysit and @Dinistro, I’ve seen some patches related to inlining from them.

We have been working on the inliner, specifically in the context of inlining LLVM. We currently handle the noinline attribute (among others).

A more general solution would be nice if you are interested in working on this :slightly_smiling_face:
For example, a solution could be adding a bool hasNoInline() method to CallableOpInterface, defaulting to returning false, which func.func and llvm.func can override. There are already attributes for this on llvm.func, but func.func would need an additional (unary?) attribute that can be set. This could then be queried from isLegalToInline in the generic InlinerInterface.

1 Like

If the goal is to develop a cost model for the inliner, it may also be worth considering to put the noinline attribute on the call rather than on the function. Annotating the calls allows a possible cost model to control the inlining based on properties of call site and callable.

A cost model could then be implemented as separate passes that runs before the inlining and annotates all the call sites that should not be inlined.

Can’t this already be done without a new interface method by implementing the existing interface methods?

Yes it can also be done per-dialect in the respective DialectInlinerInterface’s isLegalToInline (this is what we’re doing with LLVM).

Thanks for the helpful information

If I understand it correct, we need to:

  1. Add a hasNoInline method in CallableOpInterface that returns false by default.
  2. Modify DialectInlinerInterface to let it check ops that inherit CallableOpInterface and call hasNoInline()
  3. Remove existing code that checks the noinline attributes to determine if inlining should happen.

The other solution is to modify the func dialect just the same way as you did for the llvm dialect, just checking the noinline attribute in isLegalToInline functions.

Does your dialect implement its own CallOpInterface? In that case, you can just implement the DialectInlinerInterface for your dialect, and implement isLegalInline in whatever way is convenient for you, for example by adding an attribute to the call and/or the callable.

If you are relying on func.call and func.func, you would need to extend the callable (and/or perhaps on the call, as @gysit suggested) with a way to mark this, such as a new attribute, and check it in its DialectInlinerInterface implementation.

1 Like

Yeah, I defined our own func and call ops yesterday…

If you are relying on func.call and func.func, you would need to extend the callable (and/or perhaps on the call, as @gysit suggested) with a way to mark this, such as a new attribute, and check it in its DialectInlinerInterface implementation.

I see, that seems neat. But I think we may not want to use an “attribute” to check if inlining is necessary or not, how about use a pass to analyze all call ops and then set each call op’s noInline property which could be queried using hasNoInline?

I see, that seems neat. But I think we may not want to use an “attribute” to check if inlining is necessary or not, how about use a pass to analyze all call ops and then set each call op’s noInline property which could be queried using hasNoInline ?

How would you store the noInline information? I may be wrong but I believe the isLegalInline function has access to the IR only (but not to an analysis or any other state). An attribute thus seems like a good solution for storing the information in IR?

I see. Yeah, I was thinking about adding an interface function to CallOpInterface, but the interface function still has to access the attribute of the IR.

Right. I think adding a new interface method mainly makes sense if we want to establish a noinline mechanism that works for all dialects. If you add the functionality only to your own dialect, you may be better of by accessing the attribute directly in isLegalToInline as @mehdi_amini pointed out.