AnalysisUsage: addRequired vs. addRequiredTransitive

Hi,

I'm a bit confused about the distinction between addRequired and addRequiredTransitive in AnalysisUsage. From PassAnalysisSupport.h:

"REQUIRES (must be available when the pass runs), REQUIRES TRANSITIVE (must be available throughout the lifetime of the pass)."

The part that's confusing me is "must be available when the pass runs". I don't see how that's any different from "must be available throughout the lifetime of the pass". For example, if a pass is "available" when my pass runs, then I should be able to use it when my pass is running, correct? For instance:

void MyPass::getAnalysisUsage(AnalysisUsage &AU) const {
    AU.addRequired<UnifyFunctionExitNodes>();
}

bool MyPass::runOnFunction(Function &function) {
    UnifyFunctionExitNodes &pass = getAnalysis<UnifyFunctionExitNodes>();
    // ... use the pass ...
}

But if the above is okay, then why would addRequiredTransitive be necessary?

I suspect that the REQUIRES definition is simply not worded well. Perhaps it should say, "(must have run before the pass runs)". Any thoughts?

Trevor

Consider passes like AliasAnalysis or MemoryDependenceAnalysis. These passes has two phases of existence: when their runOnFunction is called, and when later passes (which requested them via their own AnalysisUsage's) call methods on them to query that information.

Some analyses, like Andersen's AA, do all their computation in their runOnFunction(). Therefore, anything they depended on can be destroyed after the runOnFunction() returns. Others, like MemoryDependenceAnalysis, are "lazy." MDA specifically does NOT compute results in its runOnFunction(), instead computing results on-demand when a user queries it. Because MDA depends on AA, we must ensure that, as long as MDA is alive and responding to queries, AA is alive as well.

That is what addRequiredTransitive does.

--Owen

Some analyses, like Andersen's AA, do all their computation in their runOnFunction(). Therefore, anything they depended on can be destroyed after the runOnFunction() returns.

What about AA itself? Would addRequired<AliasAnalysis> keep AliasAnalysis alive (but allow AliasAnalysis's dependencies to die)?

Others, like MemoryDependenceAnalysis, are "lazy." MDA specifically does NOT compute results in its runOnFunction(), instead computing results on-demand when a user queries it.
Because MDA depends on AA, we must ensure that, as long as MDA is alive and responding to queries, AA is alive as well. That is what addRequiredTransitive does.

I'm not sure if I follow this. So let's say I'm writing a pass Foo, and Foo depends on MDA. You're saying that Foo's getAnalysisUsage must call addRequiredTransitive< MemoryDependenceAnalysis>, not addRequired<MemoryDependenceAnalysis>, because otherwise the dependencies of Foo's dependencies might be destroyed. Do I have that right? Thanks,

Trevor

Nope. If Foo depends on MDA, then Foo does addRequired<MDA>(). But when
Foo uses MDA, MDA itself needs AA. So MDA does
addRequiredTransitive<AA>() as AA does not only need to be around within
MDA's runOnFunction but also within each runOnFunction of a pass
depending on MDA.

So if MDA does addRequired<AA>, AA is only guaranteed to be alive for
MDA's runOnFunction. If MDA does addRequiredTransitive<AA> instead, AA
is not only alive for MDA's runOnFunction, but also for all
runOnFunction-s of passes requiring MDA.

Clear as mud?

I get it now; thanks.

By the way, how can I help put this MDA/AA example into the LLVM documentation? There are a lot of explanations like this that should be preserved in the docs someplace, but I don't know what the usual procedure is for getting them there.

Trevor