David Greene via llvm-dev
2019-Mar-26 20:48 UTC
[llvm-dev] Understanding on-the-fly passes (Take 2)
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