Index: include/llvm/Analysis/CGSCCPassManager.h =================================================================== --- include/llvm/Analysis/CGSCCPassManager.h +++ include/llvm/Analysis/CGSCCPassManager.h @@ -441,7 +441,10 @@ PreservedAnalyses PassPA = Pass.run(*C, CGAM, CG, UR); - PI.runAfterPass(Pass, *C); + if (UR.InvalidatedSCCs.count(C)) + PI.runAfterPassInvalidated(Pass); + else + PI.runAfterPass(Pass, *C); // Update the SCC and RefSCC if necessary. C = UR.UpdatedC ? UR.UpdatedC : C; @@ -762,7 +765,10 @@ PreservedAnalyses PassPA = Pass.run(*C, AM, CG, UR); - PI.runAfterPass(Pass, *C); + if (UR.InvalidatedSCCs.count(C)) + PI.runAfterPassInvalidated(Pass); + else + PI.runAfterPass(Pass, *C); // If the SCC structure has changed, bail immediately and let the outer // CGSCC layer handle any iteration to reflect the refined structure. Index: include/llvm/IR/PassInstrumentation.h =================================================================== --- include/llvm/IR/PassInstrumentation.h +++ include/llvm/IR/PassInstrumentation.h @@ -68,10 +68,13 @@ /// PassInstrumentation to pass control to the registered callbacks. class PassInstrumentationCallbacks { public: - // Before/After callbacks accept IRUnits, so they need to take them - // as pointers, wrapped with llvm::Any + // Before/After callbacks accept IRUnits whenever appropriate, so they need + // to take them as constant pointers, wrapped with llvm::Any. + // For the case when IRUnit has been invalidated there is a different + // callback to use - AfterPassInvalidated. using BeforePassFunc = bool(StringRef, Any); using AfterPassFunc = void(StringRef, Any); + using AfterPassInvalidatedFunc = void(StringRef); using BeforeAnalysisFunc = void(StringRef, Any); using AfterAnalysisFunc = void(StringRef, Any); @@ -90,6 +93,11 @@ AfterPassCallbacks.emplace_back(std::move(C)); } + template + void registerAfterPassInvalidatedCallback(CallableT C) { + AfterPassInvalidatedCallbacks.emplace_back(std::move(C)); + } + template void registerBeforeAnalysisCallback(CallableT C) { BeforeAnalysisCallbacks.emplace_back(std::move(C)); @@ -105,6 +113,8 @@ SmallVector, 4> BeforePassCallbacks; SmallVector, 4> AfterPassCallbacks; + SmallVector, 4> + AfterPassInvalidatedCallbacks; SmallVector, 4> BeforeAnalysisCallbacks; SmallVector, 4> @@ -139,7 +149,7 @@ } /// AfterPass instrumentation point - takes \p Pass instance that has - /// just been executed and constant reference to IR it operates on. + /// just been executed and constant reference to \p IR it operates on. template void runAfterPass(const PassT &Pass, const IRUnitT &IR) const { if (Callbacks) @@ -147,6 +157,16 @@ C(Pass.name(), llvm::Any(&IR)); } + /// AfterPassInvalidated instrumentation point - takes \p Pass instance + /// that has just been executed. For use when IR has been invalidated + /// by \p Pass execution. + template + void runAfterPassInvalidated(const PassT &Pass) const { + if (Callbacks) + for (auto &C : Callbacks->AfterPassInvalidatedCallbacks) + C(Pass.name()); + } + /// BeforeAnalysis instrumentation point - takes \p Analysis instance /// to be executed and constant reference to IR it operates on. template Index: include/llvm/IR/PassTimingInfo.h =================================================================== --- include/llvm/IR/PassTimingInfo.h +++ include/llvm/IR/PassTimingInfo.h @@ -99,8 +99,8 @@ void stopTimer(StringRef PassID); // Implementation of pass instrumentation callbacks. - bool runBeforePass(StringRef PassID, Any IR); - void runAfterPass(StringRef PassID, Any IR); + bool runBeforePass(StringRef PassID); + void runAfterPass(StringRef PassID); }; } // namespace llvm Index: include/llvm/Transforms/Scalar/LoopPassManager.h =================================================================== --- include/llvm/Transforms/Scalar/LoopPassManager.h +++ include/llvm/Transforms/Scalar/LoopPassManager.h @@ -352,7 +352,11 @@ continue; PreservedAnalyses PassPA = Pass.run(*L, LAM, LAR, Updater); - PI.runAfterPass(Pass, *L); + // Do not pass deleted Loop into the instrumentation. + if (Updater.skipCurrentLoop()) + PI.runAfterPassInvalidated(Pass); + else + PI.runAfterPass(Pass, *L); // FIXME: We should verify the set of analyses relevant to Loop passes // are preserved. Index: lib/Analysis/CGSCCPassManager.cpp =================================================================== --- lib/Analysis/CGSCCPassManager.cpp +++ lib/Analysis/CGSCCPassManager.cpp @@ -79,7 +79,10 @@ PreservedAnalyses PassPA = Pass->run(*C, AM, G, UR); - PI.runAfterPass(*Pass, *C); + if (UR.InvalidatedSCCs.count(C)) + PI.runAfterPassInvalidated(*Pass); + else + PI.runAfterPass(*Pass, *C); // Update the SCC if necessary. C = UR.UpdatedC ? UR.UpdatedC : C; Index: lib/IR/PassTimingInfo.cpp =================================================================== --- lib/IR/PassTimingInfo.cpp +++ lib/IR/PassTimingInfo.cpp @@ -226,7 +226,7 @@ Prefix.endswith("AnalysisManagerProxy"); } -bool TimePassesHandler::runBeforePass(StringRef PassID, Any IR) { +bool TimePassesHandler::runBeforePass(StringRef PassID) { if (matchPassManager(PassID)) return true; @@ -239,7 +239,7 @@ return true; } -void TimePassesHandler::runAfterPass(StringRef PassID, Any IR) { +void TimePassesHandler::runAfterPass(StringRef PassID) { if (matchPassManager(PassID)) return; @@ -254,13 +254,15 @@ return; PIC.registerBeforePassCallback( - [this](StringRef P, Any IR) { return this->runBeforePass(P, IR); }); + [this](StringRef P, Any) { return this->runBeforePass(P); }); PIC.registerAfterPassCallback( - [this](StringRef P, Any IR) { this->runAfterPass(P, IR); }); + [this](StringRef P, Any) { this->runAfterPass(P); }); + PIC.registerAfterPassInvalidatedCallback( + [this](StringRef P) { this->runAfterPass(P); }); PIC.registerBeforeAnalysisCallback( - [this](StringRef P, Any IR) { this->runBeforePass(P, IR); }); + [this](StringRef P, Any) { this->runBeforePass(P); }); PIC.registerAfterAnalysisCallback( - [this](StringRef P, Any IR) { this->runAfterPass(P, IR); }); + [this](StringRef P, Any) { this->runAfterPass(P); }); } } // namespace llvm Index: lib/Passes/StandardInstrumentations.cpp =================================================================== --- lib/Passes/StandardInstrumentations.cpp +++ lib/Passes/StandardInstrumentations.cpp @@ -41,8 +41,10 @@ const Module *M = nullptr; if (any_isa(IR)) { M = any_cast(IR); + assert(M && "module should be valid for printing"); } else if (any_isa(IR)) { const Function *F = any_cast(IR); + assert(F && "function should be valid for printing"); if (!llvm::isFunctionInPrintList(F->getName())) return; if (!llvm::forcePrintModuleIR()) { @@ -53,7 +55,9 @@ Extra = formatv(" (function: {0})\n", F->getName()); } else if (any_isa(IR)) { const LazyCallGraph::SCC *C = any_cast(IR); - assert(C); + // We get nullptr here when current SCC gets invalidated by the pass. + if (C == nullptr) + return; if (!llvm::forcePrintModuleIR()) { Extra = formatv(" (scc: {0})\n", C->getName()); bool BannerPrinted = false; @@ -81,6 +85,11 @@ Extra = formatv(" (for scc: {0})\n", C->getName()); } else if (any_isa(IR)) { const Loop *L = any_cast(IR); + // Current loop might have been invalidated by the pass, + // then we will get nullptr here. + if (L == nullptr) + return; + const Function *F = L->getHeader()->getParent(); if (!isFunctionInPrintList(F->getName())) return; @@ -124,6 +133,8 @@ return; SmallString<20> Banner = formatv("*** IR Dump After {0} ***", PassID); + // TODO: handle cases when IR is nullptr (i.e. has been invalidated) + // but we still need to print the module due to forcePrintModuleIR. unwrapAndPrint(Banner, IR); return; } Index: lib/Transforms/Scalar/LoopPassManager.cpp =================================================================== --- lib/Transforms/Scalar/LoopPassManager.cpp +++ lib/Transforms/Scalar/LoopPassManager.cpp @@ -44,7 +44,11 @@ PreservedAnalyses PassPA = Pass->run(L, AM, AR, U); - PI.runAfterPass(*Pass, L); + // do not pass deleted Loop into the instrumentation + if (U.skipCurrentLoop()) + PI.runAfterPassInvalidated(*Pass); + else + PI.runAfterPass(*Pass, L); // If the loop was deleted, abort the run and return to the outer walk. if (U.skipCurrentLoop()) { Index: test/Other/loop-deletion-printer.ll =================================================================== --- /dev/null +++ test/Other/loop-deletion-printer.ll @@ -0,0 +1,24 @@ +; Make sure that Loop which was invalidated by loop-deletion +; does not lead to problems for -print-after-all and is just skipped. +; +; RUN: opt < %s -disable-output \ +; RUN: -passes=loop-instsimplify -print-after-all 2>&1 | FileCheck %s -check-prefix=SIMPLIFY +; RUN: opt < %s -disable-output \ +; RUN: -passes=loop-deletion,loop-instsimplify -print-after-all 2>&1 | FileCheck %s -check-prefix=DELETED +; +; SIMPLIFY: IR Dump {{.*}} LoopInstSimplifyPass +; DELETED-NOT: IR Dump {{.*}}LoopInstSimplifyPass +; DELETED-NOT: IR Dump {{.*}}LoopDeletionPass + +define void @deleteme() { +entry: + br label %loop +loop: + %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] + %iv.next = add i32 %iv, 1 + %check = icmp ult i32 %iv.next, 3 + br i1 %check, label %loop, label %exit +exit: + ret void +} + Index: test/Other/scc-deleted-printer.ll =================================================================== --- /dev/null +++ test/Other/scc-deleted-printer.ll @@ -0,0 +1,25 @@ +; RUN: opt < %s 2>&1 -disable-output \ +; RUN: -passes=inline -print-before-all -print-after-all | FileCheck %s -check-prefix=INL +; RUN: opt < %s 2>&1 -disable-output \ +; RUN: -passes=inline -print-before-all -print-after-all -print-module-scope | FileCheck %s -check-prefix=INL-MOD + +; INL: IR Dump Before {{InlinerPass .*scc: .tester, foo}} +; INL-NOT: IR Dump After {{InlinerPass}} +; INL: IR Dump Before {{InlinerPass .*scc: .tester}} +; INL: IR Dump After {{InlinerPass .*scc: .tester}} + +; INL-MOD: IR Dump Before {{InlinerPass .*scc: .tester, foo}} +; INL-MOD-NOT: IR Dump After {{InlinerPass}} +; INL-MOD: IR Dump Before {{InlinerPass .*scc: .tester}} +; INL-MOD: IR Dump After {{InlinerPass .*scc: .tester}} + + +define void @tester() noinline { + call void @foo() + ret void +} + +define internal void @foo() alwaysinline { + call void @tester() + ret void +}