Index: llvm/trunk/include/llvm/Transforms/Scalar/SCCP.h =================================================================== --- llvm/trunk/include/llvm/Transforms/Scalar/SCCP.h +++ llvm/trunk/include/llvm/Transforms/Scalar/SCCP.h @@ -39,9 +39,14 @@ PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); }; -bool runIPSCCP( - Module &M, const DataLayout &DL, const TargetLibraryInfo *TLI, - function_ref(Function &)> getPredicateInfo); +/// Helper struct for bundling up the analysis results per function for IPSCCP. +struct AnalysisResultsForFn { + std::unique_ptr PredInfo; + DominatorTree *DT; +}; + +bool runIPSCCP(Module &M, const DataLayout &DL, const TargetLibraryInfo *TLI, + function_ref getAnalysis); } // end namespace llvm #endif // LLVM_TRANSFORMS_SCALAR_SCCP_H Index: llvm/trunk/lib/Transforms/IPO/SCCP.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/SCCP.cpp +++ llvm/trunk/lib/Transforms/IPO/SCCP.cpp @@ -10,16 +10,20 @@ const DataLayout &DL = M.getDataLayout(); auto &TLI = AM.getResult(M); auto &FAM = AM.getResult(M).getManager(); - auto getPredicateInfo = - [&FAM](Function &F) -> std::unique_ptr { - return make_unique(F, - FAM.getResult(F), - FAM.getResult(F)); + auto getAnalysis = [&FAM](Function &F) -> AnalysisResultsForFn { + DominatorTree &DT = FAM.getResult(F); + return { + make_unique(F, DT, FAM.getResult(F)), + &DT}; }; - if (!runIPSCCP(M, DL, &TLI, getPredicateInfo)) + if (!runIPSCCP(M, DL, &TLI, getAnalysis)) return PreservedAnalyses::all(); - return PreservedAnalyses::none(); + + PreservedAnalyses PA; + PA.preserve(); + PA.preserve(); + return PA; } namespace { @@ -44,14 +48,19 @@ const TargetLibraryInfo *TLI = &getAnalysis().getTLI(); - auto getPredicateInfo = - [this](Function &F) -> std::unique_ptr { - return make_unique( - F, this->getAnalysis(F).getDomTree(), - this->getAnalysis().getAssumptionCache(F)); + auto getAnalysis = [this](Function &F) -> AnalysisResultsForFn { + DominatorTree &DT = + this->getAnalysis(F).getDomTree(); + return { + make_unique( + F, DT, + this->getAnalysis().getAssumptionCache( + F)), + nullptr}; // We cannot preserve the DT with the legacy pass manager, + // so so set it to nullptr. }; - return runIPSCCP(M, DL, TLI, getPredicateInfo); + return runIPSCCP(M, DL, TLI, getAnalysis); } void getAnalysisUsage(AnalysisUsage &AU) const override { Index: llvm/trunk/lib/Transforms/Scalar/SCCP.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/SCCP.cpp +++ llvm/trunk/lib/Transforms/Scalar/SCCP.cpp @@ -247,19 +247,25 @@ using Edge = std::pair; DenseSet KnownFeasibleEdges; - DenseMap> PredInfos; + DenseMap AnalysisResults; DenseMap> AdditionalUsers; public: - void addPredInfo(Function &F, std::unique_ptr PI) { - PredInfos[&F] = std::move(PI); + void addAnalysis(Function &F, AnalysisResultsForFn A) { + AnalysisResults.insert({&F, std::move(A)}); } const PredicateBase *getPredicateInfoFor(Instruction *I) { - auto PI = PredInfos.find(I->getFunction()); - if (PI == PredInfos.end()) + auto A = AnalysisResults.find(I->getParent()->getParent()); + if (A == AnalysisResults.end()) return nullptr; - return PI->second->getPredicateInfoFor(I); + return A->second.PredInfo->getPredicateInfoFor(I); + } + + DominatorTree *getDomTree(Function &F) { + auto A = AnalysisResults.find(&F); + assert(A != AnalysisResults.end() && "Need analysis results for function."); + return A->second.DT; } SCCPSolver(const DataLayout &DL, const TargetLibraryInfo *tli) @@ -1927,10 +1933,9 @@ } } - bool llvm::runIPSCCP( Module &M, const DataLayout &DL, const TargetLibraryInfo *TLI, - function_ref(Function &)> getPredicateInfo) { + function_ref getAnalysis) { SCCPSolver Solver(DL, TLI); // Loop over all functions, marking arguments to those with their addresses @@ -1939,7 +1944,8 @@ if (F.isDeclaration()) continue; - Solver.addPredInfo(F, getPredicateInfo(F)); + Solver.addAnalysis(F, getAnalysis(F)); + // Determine if we can track the function's return values. If so, add the // function to the solver's set of return-tracked functions. if (canTrackReturnsInterprocedurally(&F)) @@ -1988,12 +1994,13 @@ // Iterate over all of the instructions in the module, replacing them with // constants if we have found them to be of constant values. - SmallVector BlocksToErase; for (Function &F : M) { if (F.isDeclaration()) continue; + SmallVector BlocksToErase; + if (Solver.isBlockExecutable(&F.front())) for (Function::arg_iterator AI = F.arg_begin(), E = F.arg_end(); AI != E; ++AI) { @@ -2029,23 +2036,27 @@ } } - // Change dead blocks to unreachable. We do it after replacing constants in - // all executable blocks, because changeToUnreachable may remove PHI nodes - // in executable blocks we found values for. The function's entry block is - // not part of BlocksToErase, so we have to handle it separately. - for (BasicBlock *BB : BlocksToErase) + DomTreeUpdater DTU(Solver.getDomTree(F), + DomTreeUpdater::UpdateStrategy::Lazy); + // Change dead blocks to unreachable. We do it after replacing constants + // in all executable blocks, because changeToUnreachable may remove PHI + // nodes in executable blocks we found values for. The function's entry + // block is not part of BlocksToErase, so we have to handle it separately. + for (BasicBlock *BB : BlocksToErase) { NumInstRemoved += - changeToUnreachable(BB->getFirstNonPHI(), /*UseLLVMTrap=*/false); + changeToUnreachable(BB->getFirstNonPHI(), /*UseLLVMTrap=*/false, + /*PreserveLCSSA=*/false, &DTU); + } if (!Solver.isBlockExecutable(&F.front())) NumInstRemoved += changeToUnreachable(F.front().getFirstNonPHI(), - /*UseLLVMTrap=*/false); + /*UseLLVMTrap=*/false, + /*PreserveLCSSA=*/false, &DTU); - // Now that all instructions in the function are constant folded, erase dead - // blocks, because we can now use ConstantFoldTerminator to get rid of - // in-edges. - for (unsigned i = 0, e = BlocksToErase.size(); i != e; ++i) { + // Now that all instructions in the function are constant folded, + // use ConstantFoldTerminator to get rid of in-edges, record DT updates and + // delete dead BBs. + for (BasicBlock *DeadBB : BlocksToErase) { // If there are any PHI nodes in this successor, drop entries for BB now. - BasicBlock *DeadBB = BlocksToErase[i]; for (Value::user_iterator UI = DeadBB->user_begin(), UE = DeadBB->user_end(); UI != UE;) { @@ -2060,16 +2071,16 @@ // If we have forced an edge for an indeterminate value, then force the // terminator to fold to that edge. forceIndeterminateEdge(I, Solver); - bool Folded = ConstantFoldTerminator(I->getParent()); + bool Folded = ConstantFoldTerminator(I->getParent(), + /*DeleteDeadConditions=*/false, + /*TLI=*/nullptr, &DTU); assert(Folded && "Expect TermInst on constantint or blockaddress to be folded"); (void) Folded; } - - // Finally, delete the basic block. - F.getBasicBlockList().erase(DeadBB); + // Mark dead BB for deletion. + DTU.deleteBB(DeadBB); } - BlocksToErase.clear(); for (BasicBlock &BB : F) { for (BasicBlock::iterator BI = BB.begin(), E = BB.end(); BI != E;) { Index: llvm/trunk/test/Transforms/SCCP/ipsccp-preserve-domtree.ll =================================================================== --- llvm/trunk/test/Transforms/SCCP/ipsccp-preserve-domtree.ll +++ llvm/trunk/test/Transforms/SCCP/ipsccp-preserve-domtree.ll @@ -0,0 +1,63 @@ +; Basic test to check that DominatorTreeAnalysis is preserved by IPSCCP and +; the following analysis can re-use it. The test contains two trivial functions +; IPSCCP can simplify, so we can test the case where IPSCCP makes changes. + +; RUN: opt -disable-verify -debug-pass-manager \ +; RUN: -passes='ipsccp,globalopt' -S %s 2>&1 \ +; RUN: | FileCheck -check-prefixes='IR,NEW-PM' %s + +; RUN: opt -passes='ipsccp,function(verify)' -S %s | FileCheck -check-prefixes='IR' %s + +; NEW-PM: Starting llvm::Module pass manager run. +; NEW-PM-NEXT: Running pass: IPSCCPPass +; NEW-PM-DAG: Running analysis: TargetLibraryAnalysis +; NEW-PM-DAG: Running analysis: InnerAnalysisManagerProxy +; NEW-PM-DAG: Running analysis: AssumptionAnalysis on f1 +; NEW-PM-DAG: Running analysis: DominatorTreeAnalysis on f1 +; NEW-PM-DAG: Running analysis: PassInstrumentationAnalysis on f1 +; NEW-PM-DAG: Running analysis: DominatorTreeAnalysis on f2 +; NEW-PM-DAG: Running analysis: AssumptionAnalysis on f2 +; NEW-PM-DAG: Running analysis: PassInstrumentationAnalysis on f2 +; NEW-PM-NEXT: Invalidating all non-preserved analyses for: +; NEW-PM-NEXT: Invalidating all non-preserved analyses for: f1 +; NEW-PM-NEXT: Invalidating all non-preserved analyses for: f2 +; NEW-PM-NEXT: Running pass: GlobalOptPass on +; NEW-PM-DAG: Running analysis: BlockFrequencyAnalysis on f2 +; NEW-PM-DAG: Running analysis: LoopAnalysis on f2 +; NEW-PM-DAG: Running analysis: BranchProbabilityAnalysis on f2 +; NEW-PM-DAG: Running analysis: TargetLibraryAnalysis on f2 +; NEW-PM-NEXT: Running analysis: TargetIRAnalysis on f1 +; NEW-PM-NEXT: Invalidating all non-preserved analyses for: + +; IR-LABEL: @f1 +; IR-LABEL: entry: +; IR-NEXT: br label %bb2 +; IR-LABEL: bb2: +; IR-NEXT: undef + +; IR-LABEL: @f2 +; IR-NOT: icmp +; IR: br label %bbtrue +; IR-LABEL: bbtrue: +; IR-NEXT: ret i32 0 +define internal i32 @f1() readnone { +entry: + br i1 false, label %bb1, label %bb2 +bb1: + ret i32 10 +bb2: + ret i32 10 +} + +define i32 @f2(i32 %n) { + %i = call i32 @f1() + %cmp = icmp eq i32 %i, 10 + br i1 %cmp, label %bbtrue, label %bbfalse + +bbtrue: + ret i32 0 + +bbfalse: + %res = add i32 %n, %i + ret i32 %res +}