Patch: PassManager should call add() instead of addLowerLevelRequiredPass()

Hello,

LLVM asserts in the following scenario. Say there are three passes:
A, B, C. C requires A and B; B requires A; and B does not preserve A.
A valid pass ordering would be A B A C. However, opt gives the
following assertion:

$ opt -load libPassTest.so foo.bc -f -o /dev/null -c -debug-pass=Structure
opt: /u/loc/kevin/llvm/llvm/lib/VMCore/PassManager.cpp:1424: virtual
void llvm::MPPassManager::addLowerLevelRequiredPass(llvm::Pass*,
llvm::Pass*): Assertion `(P->getPotentialPassManagerType() <
RequiredPass->getPotentialPassManagerType()) && "Unable to handle Pass
that requires lower level Analysis pass"' failed.

even though all passes are ModulePasses and do not require lower level passes.

The attached patch modifies PMDataManager::add() to check if the
required pass is actually a lower level pass before calling
addLowerLevelRequiredPass(); if not, it calls add() instead. Not sure
if this is the best fix, but it works for me.

I also attached a test case with the three passes A, B, C described above.

Kevin

passmanager.diff (696 Bytes)

PassTest1.cpp (1.1 KB)

Hi Kevin,

Hello,

LLVM asserts in the following scenario. Say there are three passes:
A, B, C. C requires A and B; B requires A; and B does not preserve A.
A valid pass ordering would be A B A C. However, opt gives the
following assertion:

$ opt -load libPassTest.so foo.bc -f -o /dev/null -c -debug-pass=Structure
opt: /u/loc/kevin/llvm/llvm/lib/VMCore/PassManager.cpp:1424: virtual
void llvm::MPPassManager::addLowerLevelRequiredPass(llvm::Pass*,
llvm::Pass*): Assertion `(P->getPotentialPassManagerType() <
RequiredPass->getPotentialPassManagerType()) && "Unable to handle Pass
that requires lower level Analysis pass"' failed.

even though all passes are ModulePasses and do not require lower level passes.

The attached patch modifies PMDataManager::add() to check if the
required pass is actually a lower level pass before calling
addLowerLevelRequiredPass(); if not, it calls add() instead. Not sure
if this is the best fix, but it works for me.

I also attached a test case with the three passes A, B, C described above.

Kevin
<passmanager.diff><PassTest1.cpp>

This patch is not appropriate. At this point, the pass manager expects that all required passes at the same level (module pass, requiring module pass) are handled.

The pass manager uses simplistic approach and does not handle cases where required passes cancels each other. And that's what happens in your example. Pass B cancels, already schedule Pass A.

You've two alternatives:

1) Require pass B before requiring pass A. In other words,

replace

     virtual void getAnalysisUsage(AnalysisUsage &use) const {
       use.addRequired<A>();
       use.addRequired<B>();
     }

with

     virtual void getAnalysisUsage(AnalysisUsage &use) const {
       use.addRequired<B>();
       use.addRequired<A>();
     }

2) do

$ opt -load libPassTest.so foo.bc -f -o /dev/null -b -c -debug-pass=Structure