Function Pass Manager

Hi,

I'm writing a function pass which is dynamically loaded by opt and I need some analysis and passes to be run before my pass:

     virtual void getAnalysisUsage(AnalysisUsage &AU) const {
       AU.addRequired<LoopInfo>();
       AU.addPreserved<LoopInfo>();
       AU.addRequiredID(LoopSimplifyID);
       AU.addPreservedID(LoopSimplifyID);
       AU.addRequiredID(LCSSAID);
       AU.addPreservedID(LCSSAID);
       AU.addRequired<ScalarEvolution>();
       AU.addPreserved<ScalarEvolution>();
     }

When I run it with opt -load, I'm getting the following error:

Unable to schedule 'Canonicalize natural loops' required by 'MyPass'
Unable to schedule pass

After looking at the pass manager framework, it seems that passes with lower level than FunctionPass (such as LoopPass in my particular case) cannot be scheduled on-the-fly or must be handled by specific function managers. This is not the case for module passes, i.e. module passes requiring function ones. Is it correct ?

In other words, why is addLowerLevelRequiredPass() not specialized for function managers ?

I think I'm misunderstanding the whole thing, is it possible to chain transformation passes from my pass or do I chain them explicitly from the command line ?

Thanks in advance,

Ivan

Hi again,

I come back to this issue with an example. It's a pass which does nothing but throw the 'Unable to schedule' error.

namespace {
   struct MyPass : public FunctionPass {
     static char ID; // Pass identification, replacement for typeid
     MyPass() : FunctionPass(ID) {
       initializeMyPassPass(*PassRegistry::getPassRegistry());
     }
     virtual void getAnalysisUsage(AnalysisUsage &AU) const {
       AU.addRequiredID(LoopSimplifyID);
       AU.addPreservedID(LoopSimplifyID);
     }
     virtual bool runOnFunction(Function &F);
   };
}

char MyPass::ID = 0;
INITIALIZE_PASS_BEGIN(MyPass, "mypass", "mypass",
                 false, false)
INITIALIZE_PASS_DEPENDENCY(LoopSimplify)
INITIALIZE_PASS_END(MyPass, "mypass", "mypass",
                 false, false)

bool MyPass::runOnFunction(Function &F) {
   return MyPass::ID == 0;
}

FunctionPass *llvm::createMyPassPass() {
   return new MyPass();
}

It's a simple FunctionPass requiring a lower level pass, LoopSimplify. I wrote this pass among the other llvm passes in Transform/Scalar, it's not a dynamic loaded pass.
It's worth to note that if I change this pass to be a ModulePass instead, the required pass LoopSimplify is scheduled on-the-fly without problems.
Is there any reason to not specialize addLowerLevelRequiredPass() for function managers ?

Ivan

Hi,

does anybody have a solution to the problem mentioned by Ivan (see below)?

I am running some custom passes on a given function via a FunctionPassManager and want its loops simplified as a prerequisite.

Thanks,
Ralf

Is LoopSimplifyID an analysis pass or a transform (optimization) pass?

You cannot reliably use the addRequired() method to force a transform pass to run before another pass; there are cases in which the PassManager cannot schedule the required passes. You must simply ensure that LoopSimplify is executed before your pass.

-- John T.

Hi John,

Hi again,

I come back to this issue with an example. It's a pass which does
nothing but throw the 'Unable to schedule' error.

namespace {
     struct MyPass : public FunctionPass {
       static char ID; // Pass identification, replacement for typeid
       MyPass() : FunctionPass(ID) {
         initializeMyPassPass(*PassRegistry::getPassRegistry());
       }
       virtual void getAnalysisUsage(AnalysisUsage&AU) const {
         AU.addRequiredID(LoopSimplifyID);
         AU.addPreservedID(LoopSimplifyID);
       }
       virtual bool runOnFunction(Function&F);
     };
}

Is LoopSimplifyID an analysis pass or a transform (optimization) pass?

It is a transform pass (it can alter the CFG).

You cannot reliably use the addRequired() method to force a transform
pass to run before another pass; there are cases in which the
PassManager cannot schedule the required passes. You must simply ensure
that LoopSimplify is executed before your pass.

I am afraid I do not understand this. What is the purpose of addRequired() if not ensuring that the pass is run before execution of my own pass?

I would be perfectly happy with *any* solution that allows me to ensure that LoopSimplify is executed before my FunctionPass.

Thanks,
Ralf

Hi John,

Hi again,

I come back to this issue with an example. It's a pass which does
nothing but throw the 'Unable to schedule' error.

namespace {
     struct MyPass : public FunctionPass {
       static char ID; // Pass identification, replacement for typeid
       MyPass() : FunctionPass(ID) {
         initializeMyPassPass(*PassRegistry::getPassRegistry());
       }
       virtual void getAnalysisUsage(AnalysisUsage&AU) const {
         AU.addRequiredID(LoopSimplifyID);
         AU.addPreservedID(LoopSimplifyID);
       }
       virtual bool runOnFunction(Function&F);
     };
}

Is LoopSimplifyID an analysis pass or a transform (optimization) pass?

It is a transform pass (it can alter the CFG).

You cannot reliably use the addRequired() method to force a transform
pass to run before another pass; there are cases in which the
PassManager cannot schedule the required passes. You must simply ensure
that LoopSimplify is executed before your pass.

I am afraid I do not understand this. What is the purpose of addRequired() if not ensuring that the pass is run before execution of my own pass?

The addRequired method is designed to tell the PassManager which *analysis* passes to run before your pass. This allows the PassManager to optimize the pass schedule so that analysis passes are only re-run when needed. Analysis passes don't modify the IR so PassManager can always find a way to schedule the passes.

The reason why you can't require a transform pass is because you can get impossible-to-schedule pass schedules (or, at least, schedules that PassManager isn't smart enough to schedule because it assumes that all required passes are analysis passes) . For example, assume Pass C requires Passes A and B. Passes A and B invalidate all other passes because they are transform passes. There's no possible schedule for these passes.

I would be perfectly happy with *any* solution that allows me to ensure that LoopSimplify is executed before my FunctionPass.

Sadly, there isn't such a feature. It is the job of the person (or program) putting together the pass schedule to ensure that transform passes are run in the correct order relative to other transform passes. Only analysis passes are scheduled automatically by PassManager.

What you could do to catch bugs is to write an analysis pass that verifies that the loops have the structure that you need; this pass would assert out if the loops aren't in canonical form. Your pass could require this new analysis pass. If someone forgets to run the pass that puts loops into canonical form, this analysis pass would catch the error.

-- John T.

Hi John,

Hi again,

I come back to this issue with an example. It's a pass which does
nothing but throw the 'Unable to schedule' error.

namespace {
struct MyPass : public FunctionPass {
static char ID; // Pass identification, replacement for typeid
MyPass() : FunctionPass(ID) {
initializeMyPassPass(*PassRegistry::getPassRegistry());
}
virtual void getAnalysisUsage(AnalysisUsage&AU) const {
AU.addRequiredID(LoopSimplifyID);
AU.addPreservedID(LoopSimplifyID);
}
virtual bool runOnFunction(Function&F);
};
}

Is LoopSimplifyID an analysis pass or a transform (optimization) pass?

It is a transform pass (it can alter the CFG).

You cannot reliably use the addRequired() method to force a transform
pass to run before another pass; there are cases in which the
PassManager cannot schedule the required passes. You must simply ensure
that LoopSimplify is executed before your pass.

I am afraid I do not understand this. What is the purpose of
addRequired() if not ensuring that the pass is run before execution of
my own pass?

The addRequired method is designed to tell the PassManager which
*analysis* passes to run before your pass. This allows the PassManager
to optimize the pass schedule so that analysis passes are only re-run
when needed. Analysis passes don't modify the IR so PassManager can
always find a way to schedule the passes.

The reason why you can't require a transform pass is because you can get
impossible-to-schedule pass schedules (or, at least, schedules that
PassManager isn't smart enough to schedule because it assumes that all
required passes are analysis passes) . For example, assume Pass C
requires Passes A and B. Passes A and B invalidate all other passes
because they are transform passes. There's no possible schedule for
these passes.

Ah, that makes a lot more sense to me now. Thanks for the detailed explanation!

I would be perfectly happy with *any* solution that allows me to
ensure that LoopSimplify is executed before my FunctionPass.

Sadly, there isn't such a feature. It is the job of the person (or
program) putting together the pass schedule to ensure that transform
passes are run in the correct order relative to other transform passes.
Only analysis passes are scheduled automatically by PassManager.

What you could do to catch bugs is to write an analysis pass that
verifies that the loops have the structure that you need; this pass
would assert out if the loops aren't in canonical form. Your pass could
require this new analysis pass. If someone forgets to run the pass that
puts loops into canonical form, this analysis pass would catch the error.

This is what I have done to temporarily at least catch this problem. There is loop->isLoopSimplifyForm() which helps greatly.
I assume another possibility could be to run LoopSimplify by hand on all loops of the function, although I am not sure how elegant this will be.

Thanks again,
Ralf

Hi Jhon,

Finally, I've managed to run my pass as LoopPass avoiding this problem.
Thanks for the detailed explanation, I clearly misunderstood the functionality of the pass manager.

Ivan