[llvm-dev] Understanding on-the-fly passes (Take 2)

David Greene via llvm-dev llvm-dev at lists.llvm.org
Tue Mar 26 13:48:41 PDT 2019


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

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->
      getAnalysis<PostDominatorTreeWrapperPass>(F).getPostDomTree();
    };

    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 & {
      return
      this->getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
    };

    auto OREGetter = [this] (Function &F) -> OptimizationRemarkEmitter & {
      return this->
      getAnalysis<OptimizationRemarkEmitterWrapperPass>(F).getORE();
    };

    doTheWork(M,
              DominatorGetter,
              PostDominatorGetter,
              LoopInfoGetter,
              SCEVGetter,
              AssumptionCacheGetter,
              OREGetter);

    return false;
  }

  // New pass.
  PreservedAnalyses
  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);
    };

    doTheWork(M,
              DominatorGetter,
              PostDominatorGetter,
              LoopInfoGetter,
              SCEVGetter,
              AssumptionCacheGetter,
              OREGetter);

    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!
        reallyDoTheWork(M,
                        F,
                        API,
                        DT,
                        PDT,
                        LI,
                        SE,
                        AC,
                        ORE);
      }
    }
  }

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
Function?

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
ModulePass?

Thanks for any help!

                         -David


More information about the llvm-dev mailing list