Ok, I've been struggling with this for two days and hopefully someone
can help me out.
I have a set of passes, analysis passes A, B, C, D and transformation
passes E and F.
Pass C depends on pass A and pass D depends on pass B. Pass E depends
on C and D and does not preserve any analysis pass. Pass F depeds on
pass A and pass C. Pass F runs after pass E.
Graphically the dependency graph looks something like this:
A B
^ ^
/ | |
C D
^ ^
>\ |
> \ |
\ | \ |
F E
The arrows represent direct use of analysis pass data. So even though C
is built upon information from A, F directly accesses information from
both C and A.
I have tried all kinds of combinations of addRequired and
addRequiredTransitive but no matter what, pass C gets rerun before pass
F as expected but pass A does not. This leads to a situation where pass
F uses up to date information from pass C and out of date information
from pass A, leading to an analysis inconsistency and a compiler abort.
Note that even though pass C runs again, because pass A is out of date
the information it computes is wrong. So while it's up to date in the
sense that the pass ran again, it computed wrong information.
Currently I have done this:
C addRequiredTransitive<A>();
D addRequiredTransitive<B>();
E addRequired<C>();
E addRequired<D>();
F addRequired<C>();
F addRequired<A>();
I've tried having E and F addRequired<A>() or addRequiredTransitive<A>()
and lots of other things but nothing fixes the problem.
I guess I don't correctly understand addRequired()
vs. addRequiredTransitive(). Can someone explain how to use these
dependency specifiers to correctly describe the above dependencies?
Thanks!
-David
I'm no expert on the PassManager, but I happen to be going through it fairly
carefully right now. You didn't state which passes were Module Passes and
which were Function Passes (or other types). A print of the
-debug-pass=Structure would be useful.
One thing I have noticed is that addPreserved() doesn't seem to really do
anything. I would have thought it would be used in helping determine the
last users of a pass, but that doesn't appear to be the case. It seems to
mess with a structure called InheritedAnalysis, but that in turn is never
really used for anything.
I've noticed that if you have a Module Pass (e.g., GlobalsModRef) that is
used by a function pass, as long as other function passes require
AliasAnalysis, it will stick around, even if one of those passes says it
doesn't preserve AliasAnalysis.
As I said, I'm working through the PassManager (LegacyPasssManager.cpp
specifically) now, so my understanding may be a little off. But there does
seem to be some odd behavior of the PassManager that I've noticed.
Daniel
<dag@cray.com> writes:
Graphically the dependency graph looks something like this:
A B
^ ^
/ | |
> C D
> ^ ^
> >\ |
> > \ |
\ | \ |
F E
The arrows represent direct use of analysis pass data. So even though C
is built upon information from A, F directly accesses information from
both C and A.
Opps, that's not quite right. F does not access information directly
from A but because A doesn't get re-run before C is re-run, C computes
wrong information and F gets a compiler abort.
The general problem is still the same, I was just inaccurate about how
the passes get used.
-David
"Daniel Stewart" <stewartd@codeaurora.org> writes:
I'm no expert on the PassManager, but I happen to be going through it
fairly carefully right now. You didn't state which passes were Module
Passes and which were Function Passes (or other types).
Sorry, I did mean to include that. They are all FunctionPasses.
One thing I have noticed is that addPreserved() doesn't seem to really
do anything. I would have thought it would be used in helping
determine the last users of a pass, but that doesn't appear to be the
case. It seems to mess with a structure called InheritedAnalysis, but
that in turn is never really used for anything.
I've also noticed that addPreserved doesn't seem to do anything. Even
if I say a pass preserves another pass, the other pass gets run again.
I've noticed that if you have a Module Pass (e.g., GlobalsModRef) that
is used by a function pass, as long as other function passes require
AliasAnalysis, it will stick around, even if one of those passes says
it doesn't preserve AliasAnalysis.
Hmm...that might be related. The situation here is that an analysis
pass depended on by another analysis pass isn't re-run even though it's
not preserved by any pass. It sounds like a similar situation.
As I said, I'm working through the PassManager (LegacyPasssManager.cpp
specifically) now, so my understanding may be a little off. But there
does seem to be some odd behavior of the PassManager that I've
noticed.
As far as I know there is no way to force a re-run of a pass. Is that
right?
-David
You haven't mentioned if your passes are implementers of an interface (like
AliasAnalysis).
What seems to matter as far as having a pass free'd from memory are the
LastUsers. The LastUsers are set by required passes. So if a pass says it
requires another pass, the required pass sticks around. The last user is the
last pass that required some other particular pass. It appears in your case
that F requires A and C. The PassManager will indicate that F is the last
user of A. The fact that C doesn't preserve A is seemingly meaningless.
Therefore A will be run, followed by C, followed by F.
This brings up a question I had about the meaning of "preserve". Some places
I read (here on the mailing list + the docs) seem to indicate that
preserving is about keeping something around because you may want to use it
again. While other places seem to indicate that it is about whether a pass
is invalidated. These are very two different things, and, as far as I can
tell, the code seems to implement neither of these ideas.
To solve your issue, can you use a barrier pass? This might force the passes
to re-run when you need them.
Daniel
"Daniel Stewart" <stewartd@codeaurora.org> writes:
You haven't mentioned if your passes are implementers of an interface
(like AliasAnalysis).
No, they're just regular FunctionPasses.
What seems to matter as far as having a pass free'd from memory are
the LastUsers. The LastUsers are set by required passes. So if a pass
says it requires another pass, the required pass sticks around. The
last user is the last pass that required some other particular pass.
It appears in your case that F requires A and C. The PassManager will
indicate that F is the last user of A. The fact that C doesn't
preserve A is seemingly meaningless. Therefore A will be run,
followed by C, followed by F.
That's just broken. But I had come to a similar conclusion over the
weekend. The obvious question is, if I remove the dependency from F how
do I guarantee the information is available when it runs?
This brings up a question I had about the meaning of "preserve". Some
places I read (here on the mailing list + the docs) seem to indicate
that preserving is about keeping something around because you may want
to use it again. While other places seem to indicate that it is about
whether a pass is invalidated. These are very two different things,
and, as far as I can tell, the code seems to implement neither of
these ideas.
Spot on.
To solve your issue, can you use a barrier pass? This might force the
passes to re-run when you need them.
What's a barrier pass?
-David
<dag@cray.com> writes:
To solve your issue, can you use a barrier pass? This might force the
passes to re-run when you need them.
What's a barrier pass?
Ah. We haven't upgraded to that version of LLVM yet (but it's in the
works!).
For the record and mailing-list posterity, I was able to fix the problem
by removing setPreservesCFG from pass E. That's just a huge ugly kludge
but it's good enough for this case.
-David
To solve your issue, can you use a barrier pass? This might force the
passes to re-run when you need them.
What's a barrier pass?
/lib/Transforms/IPO/BarrierNoopPass.cpp
From: dag@cray.com
To: llvmdev@cs.uiuc.edu
Sent: Monday, April 21, 2014 12:08:22 PM
Subject: Re: [LLVMdev] PassManager Woes
<dag@cray.com> writes:
>> To solve your issue, can you use a barrier pass? This might force
>> the
>> passes to re-run when you need them.
>
> What's a barrier pass?
Ah. We haven't upgraded to that version of LLVM yet (but it's in the
works!).
If you need, backporting the barrier pass should be trivial. It does not really do anything special, just its existence forces later passes to "break out" from any preceding CGSCC pass manager.
-Hal