This is an archive of the discontinued LLVM Phabricator instance.

Enable inlining of recursive functions.
AbandonedPublic

Authored by pbarrio on Jan 15 2015, 4:07 AM.

Details

Summary

Add functionality to be able to inline recursive functions. Both direct and indirect (mutual) recursion are considered for inlining. The default behavior is still not to inline, but this can be changed by setting flag -max-recursion-inline to a value higher than 0.

This is intended as a previous step to optimized recursion inlining. Therefore, the heuristics are not tuned up for performance, and recursion inlining is not part of -Ox optimizations.

The patch slightly changes -O3 behavior. Inlining recursive functions into functions external to their SCC is allowed even if recursion inlining is not turned on (see regression test 2 below). Before, it was considered part of the recursion and therefore was marked as "never" inline. This change has been tested for correctness and performance with several benchmarks (LLVM test-suite included) and on two platforms, one aarch64 and one x86.

SUMMARY OF CHANGES:

"IsRecursiveCall" checks are removed in the inline cost calculator. The only inline recursion checks are now done in the Inliner with the help of function InlineHistoryIncludes(). That function now allows skipping part of the inline history (the recursion levels) to allow functions to be inlined into themselves or into members of their SCC.

Regression tests for recursion inlining:

  1. Add checks for a function that calls itself (direct recursion) and for a SCC of size 2 (indirect recursion).
  1. Removed a test checking that, if A is recursive and called by B, A is never inlined into B. Note that B is not necessarily part of A's SCC. Now, the calls to A from callers external to A's SCC are treated as any other function call.
  1. Removed triple from a previous unit test, and added comments.

Diff Detail

Event Timeline

pbarrio updated this revision to Diff 18218.Jan 15 2015, 4:07 AM
pbarrio retitled this revision from to Enable inlining of recursive functions..
pbarrio updated this object.
pbarrio edited the test plan for this revision. (Show Details)
pbarrio added reviewers: chandlerc, Jiangning.
pbarrio added a subscriber: Unknown Object (MLST).
pbarrio updated this object.Jan 15 2015, 4:44 AM
pbarrio added a subscriber: jmolloy.
jmolloy requested changes to this revision.Jan 15 2015, 5:05 AM
jmolloy added a reviewer: jmolloy.

Hi Pablo,

Thanks for working on this! I have comments inline. But in general, it looks like this patch just allows recursive functions to be inlined, it doesn't change the heuristic calculation for them.

My impression from previous threads (Chandler will vociferiously declaim me if I misremember, I'm sure) is that Chandler expressed a wish that recursive inlining be treated heuristically more like loop unrolling, as they are somewhat equivalent. Do you have a comment on that?

Cheers,

James

lib/Analysis/IPA/InlineCost.cpp
912–913

The continuation line can now fit on one line.

1139–1140

Remove line break

lib/Transforms/IPO/Inliner.cpp
64

Could you please be more explicit about what exactly this knob does?

  • What does "levels" mean? for example: B -> C -> B -> C - is that 2 levels or 4 levels?
  • Explicitly put the default in the description message
  • I assume this doesn't alter heuristics at all?
445

What exactly are you trying to do here? You haven't modified the doc comment with the intention.

What does "allowAtLeast" do? it has "at least" in it but it appears to slurp the first N entries regardless. Also there are coding style violations:

  • Don't need (and please don't put) brackets around comparison expressions. !=/== binds tighter than &&.
  • Please don't use iHungarianNotation. "I" or "Skip" would do.
  • Variables should be UpperCamelCase.
560

Won't this only affect direct recursion? if A -> B -> A, Callee will never equal Caller, right?

This revision now requires changes to proceed.Jan 15 2015, 5:05 AM
aadg added a subscriber: aadg.Jan 15 2015, 5:42 AM
pbarrio updated this revision to Diff 18235.Jan 15 2015, 9:58 AM
pbarrio edited edge metadata.

James, thank you for the review,

I uploaded the required changes to the patch with some verbose inlined comments. I could not find more succinct explanations, sorry about that. Also, forcing me to find an explanation about the inline levels made me realize that I was inlining one more time than expected (3 times for a maximum level of 2). Code and regression test fixed.

About treating recursion inlining as loop unrolling, it makes sense. Here I deliberately stayed away from the InlineCost analysis, so the heuristics have not been changed at all. However, it is certainly something that we want to model in the cost analysis.

yinma added a subscriber: yinma.Jan 19 2015, 10:19 AM

I looked your code, you removed the check in call analyzer and MaxRecursionInl is about inlining history. I would like to know if you set MaxRecursionInl is 0, the inliner will behave exactly like the before without your code?

And MaxRecursionInl is to control the number of history skipped. A different name may be more suitable?

pbarrio added a comment.EditedJan 21 2015, 10:41 AM

Hello Yin, thank you very much for looking at the code.

When MaxRecursionInl is 0, the code behaves differently at -O3, as stated in paragraph 3 of the Summary. I have benchmarked the patch and it does show some performance improvements/regressions, but overall the change is beneficial. The compile time does not seem to be affected and the code size is only slightly affected.

Also, I chose the name of MaxRecursionInl because it maps directly to the amount of recursion inline that is allowed. Now it is implemented as skipping part of the inline history, but it could be implemented in another way and the same flag should be valid.

lib/Transforms/IPO/Inliner.cpp
445

I have added a comment about what "allowAtLeast" (now called SkipFirst) does. The real explanation why I do this is in lines 558-560 of the new patch. This is only a helper function.

560

Correct. All other cases are handled by InlineHistoryIncludes(). This function cannot handle the case of direct recursion disabled because, in the first level of recursion inlining, the inline history is empty. Therefore, InlineHistoryIncludes() would not encounter any previous inline of the callee and the first level would be inlined.

jmolloy added inline comments.Jan 27 2015, 4:15 AM
lib/Transforms/IPO/Inliner.cpp
64

This comment does give the information needed, but is fairly difficult to parse. Could you please make it better formatted and elaborate?

For example, I didn't understand what "A1", "A2" etc were until my third reading.

pbarrio updated this revision to Diff 18884.EditedJan 28 2015, 3:24 AM
pbarrio edited edge metadata.
pbarrio set the repository for this revision to rL LLVM.

Thank you James,

Comment about MaxRecursionInl changed. I hope that this one makes a better explanation.

chandlerc requested changes to this revision.Mar 29 2015, 2:26 PM
chandlerc edited edge metadata.

Marking this as needing changes still based on the new direction we discussed of eliminating recursion to expose the desired optimizations.

This revision now requires changes to proceed.Mar 29 2015, 2:26 PM
pbarrio abandoned this revision.Mar 10 2016, 10:33 AM

Work discontinued.