[llvm-dev] New Pass Manager and CGSSCPassManager
David Greene via llvm-dev
llvm-dev at lists.llvm.org
Tue Oct 20 07:24:39 PDT 2020
Hi all,
I've run into a sticky situation with CGSSCPassManager. I have a module
pass that needs to run after all inlining has occurred but *before*
loops have been optimized significantly. I'm not sure this is possible
with the way CGSCCPassManager is formulated, at least not without
hackery.
My pass has to be a module pass or a CGSCC pass because it has to add
global variables and function declarations. It does not otherwise modify
global state or the call graph SCC.
Incidentally WRT my pass, this page about pass requirements seems
ambiguous:
http://llvm.org/docs/WritingAnLLVMPass.html
To be explicit, FunctionPass subclasses are not allowed to:
1. Inspect or modify a Function other than the one currently being processed.
2. Add or remove Functions from the current Module.
3. Add or remove global variables from the current Module.
4. Maintain state across invocations of runOnFunction (including global data).
#2 is ambiguous to me. Does "add or remove Functions" mean definitions
only or both definitions and declarations? It might be helpful to
clarify that in this section of the document.
As I understand things, CGSCCPassManager is designed to run things in a
bottom-up manner:
// #1
for scc in scc_list {
inline callees everywhere
do other CG passes
for function in bottom_up(scc) {
run function passes
}
}
Have I got that right? I have some questions below about this general
structure that are only tangentially related to my main issue.
I need to be able to do something like this:
// #2
for scc in scc_list {
inline callees everywhere
run my pass
do other CG passes
for function in bottom_up(scc) {
run function passes
}
}
It doesn't seem possible currently because there's no adaptor to run a
module pass inside CGSCCPassManager. You can run a CGSCCPassManager
inside a ModulePassManager but not the other way around. It kind of
makes sense because a call graph SCC doesn't necessarily contain all of
the Functions in a Module. On the other hand, my pass doesn't really
care that it might not see all Functions in the Module in a single
invocation. It would eventually see them all as CGSCCPassManager
processes additional SCCs.
I suppose I could make my pass a CGSCC pass but that seems like overkill
for my purposes. Indeed, I had no need to do this with the Old Pass
Manager as inlining ran in a ModulePassManager, not a CGSCCPassManager.
When I first looked into this I expected the inliner SCC algorithm to
work something like this:
// #3
for scc in scc_list {
for function in bottom_up(scc) {
inline callees into function
run function passes
}
do other CG passes
}
But it apparently doesn't work that way. If it did I would be in really
bad shape because there would be no way to run my pass after all
inlining has occurred but before loops have been significantly altered.
It is functionally incorrect for my pass to modify a Function B and have
B inlined into the Function A which my pass also modifies.
Another option would be to split the current CGSCC pass pipeline in two,
creating one pipeline for things to run before my pass and another for
things to run after my pass. But upstream is definitely not interested
in my pass so this would be a downstream change and rather burdensome to
maintain.
Now for the additional questions about CGSCCPassManager mentioned above.
>From the pseudocode #1 above, it looks like all inlining happens before
any optimization. This seems sub-optimal to me because transformations
may make Functions good inline candidates when they were not previously.
Is this a know issue with the current setup? I'm kind of glad it works
like #1 (if indeed it does) because it at least makes my goal
theoretically attainable. But another part of me really wants it to
work like pseudocode #3 because it seems better for optimization.
Thanks for all insights and help!
-David
More information about the llvm-dev
mailing list