Understanding on-the-fly passes (Take 2)

Apologies for the earlier aborted e-mail. I hit a keyboard shortcut by
mistake. :slight_smile:

I'm seeing some odd behavior with a ModulePass I'm developing. In order
for it to work with both the legacy and new pass managers, I've
abstracted away the code to get the passes it depends on:

  // Legacy pass.
  bool MyPass::runOnModule(Module &M) override {
    auto DominatorGetter = [this] (Function &F) -> DominatorTree & {
      return this->getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();

    auto PostDominatorGetter = [this] (Function &F) -> PostDominatorTree & {
      return this->

    auto LoopInfoGetter = [this] (Function &F) -> LoopInfo & {
      return this->getAnalysis<LoopInfoWrapperPass>(F).getLoopInfo();

    auto SCEVGetter = [this] (Function &F) -> ScalarEvolution & {
      return this->getAnalysis<ScalarEvolutionWrapperPass>(F).getSE();

    auto AssumptionCacheGetter = [this] (Function &F) ->
      AssumptionCache & {

    auto OREGetter = [this] (Function &F) -> OptimizationRemarkEmitter & {
      return this->


    return false;

  // New pass.
  MyPass::run(Module &M, ModuleAnalysisManager &AM) {
    auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();

    auto DominatorGetter = [&FAM] (Function &F) -> DominatorTree & {
      return FAM.getResult<DominatorTreeAnalysis>(F);

    auto PostDominatorGetter = [&FAM] (Function &F) -> PostDominatorTree & {
      return FAM.getResult<PostDominatorTreeAnalysis>(F);

    auto LoopInfoGetter = [&FAM] (Function &F) -> LoopInfo & {
      return FAM.getResult<LoopAnalysis>(F);

    auto SCEVGetter = [&FAM] (Function &F) -> ScalarEvolution & {
      return FAM.getResult<ScalarEvolutionAnalysis>(F);

    auto AssumptionCacheGetter = [&FAM] (Function &F) -> AssumptionCache & {
      return FAM.getResult<AssumptionAnalysis>(F);

    auto OREGetter = [&FAM] (Function &F) -> OptimizationRemarkEmitter & {
      return FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);


    return PreservedAnalyses::all();

  template<typename D,
           typename P,
           typename L,
           typename S,
           typename A,
           typename O>
  bool doTheWork(Module &M,
                 D &DominatorGetter,
                 P &PostDominatorGetter,
                 L &LoopInfoGetter,
                 S &SCEVGetter,
                 A &AssumptionCacheGetter,
                 O &OREGetter) {
    auto &FirstORE = OREGetter(getFirstDefinedFunction(M));

    // Do some checking to see if doing the work makes sense and emit
    // messages with FirstORE.

    // Ok, everything ok, actually do the work.
    for (auto &F : M) {
      if (!F.isDeclaration()) {
        auto &DT = DominatorGetter(F);
        auto &PDT = PostDominatorGetter(F);
        auto &LI = LoopInfoGetter(F);
        auto &SE = SCEVGetter(F);
        auto &AC = AssumptionCacheGetter(F);
        auto &ORE = OREGetter(F); // BAM! SE is deleted here!

When I use the legacy pass manager, the SE object retrieved by
SCEVGetter is deleted when the OREGetter gets the
OptimizationRemarkEmitter. Bad things ensue. Tracing through with a
debugger shows that on-the-fly passes are created and deleted a bunch of
times, including ScalarEvolution. This is because on-the-fly pass
managers are created and deleted a bunch of times, essentially each time
a *Getter is invoked.

I'm curious why the deletion happens when OREGetter is invoked. Is it
because I called OREGetter once at the top of doTheWork with the same

Is there something special about ScalarEvolution? I see that no IPO
passes use it. SCCP does the same kind of abstracting for getting pass
dependencies so I don't think the abstraction is causing the issue.

What is the proper way to run function analysis passes from a

Thanks for any help!