Index: llvm/include/llvm/Passes/StandardInstrumentations.h =================================================================== --- llvm/include/llvm/Passes/StandardInstrumentations.h +++ llvm/include/llvm/Passes/StandardInstrumentations.h @@ -124,6 +124,97 @@ void registerCallbacks(PassInstrumentationCallbacks &PIC); }; +// Base class for classes that report changes to the IR. +// It presents an interface for such classes and provides calls +// on various events as the new pass manager transforms the IR. +// It also provides filtering of information based on hidden options +// specifying which functions are interesting. +// Calls are made for the following events/queries: +// 1. The initial IR processed. +// 2. To get the representation of the IR (of type \p T). +// 3. When a pass does not change the IR. +// 4. When a pass changes the IR (given both before and after representations +// of type \p T). +// 5. When an IR is invalidated. +// 6. When a pass is run on an IR that is not interesting (based on options). +// 7. When a pass is ignored (pass manager or adapter pass). +// 8. To compare two IR representations (of type \p T). +template class ChangePrinter { +protected: + ChangePrinter() {} + +public: + virtual ~ChangePrinter(); + + // Determine if this pass/IR is interesting and if so, save the IR + // otherwise it is left on the stack without data. + void saveIRBeforePass(Any IR, StringRef PassID); + // Compare the IR from before the pass after the pass. + void handleIRAfterPass(Any IR, StringRef PassID); + // Handle the situation where a pass is invalidated. + void handleInvalidatedPass(StringRef PassID); + +protected: + // Called on the first IR processed. + virtual void handleInitialIR(Any IR) = 0; + // Called before and after a pass to get the representation of the IR. + virtual void generateIRRepresentation(Any IR, StringRef PassID, + IRUnitT &Output) = 0; + // Called when the pass is not iteresting. + virtual void omitAfter(StringRef PassID, std::string &Name) = 0; + // Called when an interesting IR has changed. + virtual void handleAfter(StringRef PassID, std::string &Name, + const IRUnitT &Before, const IRUnitT &After, + Any) = 0; + // Called when an interesting pass is invalidated. + virtual void handleInvalidated(StringRef PassID) = 0; + // Called when the IR or pass is not interesting. + virtual void handleFiltered(StringRef PassID, std::string &Name) = 0; + // Called when an ignored pass is encountered. + virtual void handleIgnored(StringRef PassID, std::string &Name) = 0; + // Called to compare the before and after representations of the IR. + virtual bool same(const IRUnitT &Before, const IRUnitT &After) = 0; + + // Stack of IRs before passes. + std::vector BeforeStack; + // Is this the first IR seen? + bool InitialIR = true; +}; + +// A change printer based on the string representation of the IR as created +// by unwrapAndPrint. The string representation is stored in a std::string +// to preserve it as the IR changes in each pass. Note that the banner is +// included in this representation but it is massaged before reporting. +class IRChangePrinter : public ChangePrinter { +public: + IRChangePrinter(); + ~IRChangePrinter() override; + void registerCallbacks(PassInstrumentationCallbacks &PIC); + +protected: + // Called on the first IR processed. + void handleInitialIR(Any IR) override; + // Called before and after a pass to get the representation of the IR. + void generateIRRepresentation(Any IR, StringRef PassID, + std::string &Output) override; + // Called when the pass is not iteresting. + void omitAfter(StringRef PassID, std::string &Name) override; + // Called when an interesting IR has changed. + void handleAfter(StringRef PassID, std::string &Name, + const std::string &Before, const std::string &After, + Any) override; + // Called when an interesting pass is invalidated. + void handleInvalidated(StringRef PassID) override; + // Called when the IR or pass is not interesting. + void handleFiltered(StringRef PassID, std::string &Name) override; + // Called when an ignored pass is encountered. + void handleIgnored(StringRef PassID, std::string &Name) override; + // Called to compare the before and after representations of the IR. + bool same(const std::string &Before, const std::string &After) override; + + raw_ostream &Out; +}; + /// This class provides an interface to register all the standard pass /// instrumentations and manages their state (if any). class StandardInstrumentations { @@ -132,6 +223,7 @@ TimePassesHandler TimePasses; OptNoneInstrumentation OptNone; PreservedCFGCheckerInstrumentation PreservedCFGChecker; + IRChangePrinter PrintChangedIR; public: StandardInstrumentations(bool DebugLogging) : PrintPass(DebugLogging) {} Index: llvm/lib/IR/LegacyPassManager.cpp =================================================================== --- llvm/lib/IR/LegacyPassManager.cpp +++ llvm/lib/IR/LegacyPassManager.cpp @@ -87,14 +87,14 @@ static cl::opt PrintModuleScope("print-module-scope", cl::desc("When printing IR for print-[before|after]{-all} " - "always print a module IR"), + "and change reporters, always print a module IR"), cl::init(false), cl::Hidden); static cl::list PrintFuncsList("filter-print-funcs", cl::value_desc("function names"), cl::desc("Only print IR for functions whose name " "match this for all print-[before|after][-all] " - "options"), + "and change reporter options"), cl::CommaSeparated, cl::Hidden); /// This is a helper to determine whether to print IR before or Index: llvm/lib/Passes/StandardInstrumentations.cpp =================================================================== --- llvm/lib/Passes/StandardInstrumentations.cpp +++ llvm/lib/Passes/StandardInstrumentations.cpp @@ -26,6 +26,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/raw_ostream.h" +#include #include using namespace llvm; @@ -51,18 +52,48 @@ cl::desc("Print all pass management debugging information. " "`-debug-pass-manager` must also be specified")); +// An option that prints out the IR after passes, similar to +// -print-after-all except that it only prints the IR after passes that +// change the IR. Those passes that do not make changes to the IR are +// reported as not making any changes. In addition, the initial IR is +// also reported. Other hidden options affect the output from this +// option. -filter-passes will limit the output to the named passes +// that actually change the IR and other passes are reported as filtered out. +// The specified passes will either be reported as making no changes (with +// no IR reported) or the changed IR will be reported. Also, the +// -filter-print-funcs and -print-module-scope options will do similar +// filtering based on function name, reporting changed IRs as functions(or +// modules if -print-module-scope is specified) for a particular function +// or indicating that the IR has been filtered out. The extra options +// can be combined, allowing only changed IRs for certain passes on certain +// functions to be reported in different formats, with the rest being +// reported as filtered out. +static cl::opt PrintChanged("print-changed", + cl::desc("Print changed IRs"), + cl::init(false), cl::Hidden); +// An option that supports the -print-changed option. See +// the description for -print-changed for an explanation of the use +// of this option. Note that this option has no effect without -print-changed. +static cl::list + PrintPassesList("filter-passes", cl::value_desc("pass names"), + cl::desc("Only consider IR changes for passes whose names " + "match for the print-changed option"), + cl::CommaSeparated, cl::Hidden); + namespace { /// Extracting Module out of \p IR unit. Also fills a textual description /// of \p IR for use in header when printing. -Optional> unwrapModule(Any IR) { +Optional> +unwrapModule(Any IR, bool Force = false) { if (any_isa(IR)) return std::make_pair(any_cast(IR), std::string()); if (any_isa(IR)) { const Function *F = any_cast(IR); - if (!llvm::isFunctionInPrintList(F->getName())) + if (!Force && !llvm::isFunctionInPrintList(F->getName())) return None; + const Module *M = F->getParent(); return std::make_pair(M, formatv(" (function: {0})", F->getName()).str()); } @@ -71,18 +102,19 @@ const LazyCallGraph::SCC *C = any_cast(IR); for (const LazyCallGraph::Node &N : *C) { const Function &F = N.getFunction(); - if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) { + if (Force || (!F.isDeclaration() && isFunctionInPrintList(F.getName()))) { const Module *M = F.getParent(); return std::make_pair(M, formatv(" (scc: {0})", C->getName()).str()); } } + assert(!Force && "Expected to have made a pair when forced."); return None; } if (any_isa(IR)) { const Loop *L = any_cast(IR); const Function *F = L->getHeader()->getParent(); - if (!isFunctionInPrintList(F->getName())) + if (!Force && !isFunctionInPrintList(F->getName())) return None; const Module *M = F->getParent(); std::string LoopName; @@ -107,7 +139,8 @@ } void printIR(raw_ostream &OS, const Module *M, StringRef Banner, - StringRef Extra = StringRef(), bool Brief = false) { + StringRef Extra = StringRef(), bool Brief = false, + bool ShouldPreserveUseListOrder = false) { if (Brief) { OS << M->getName() << '\n'; return; @@ -115,7 +148,7 @@ if (llvm::isFunctionInPrintList("*") || llvm::forcePrintModuleIR()) { OS << Banner << Extra << "\n"; - M->print(OS, nullptr, false); + M->print(OS, nullptr, ShouldPreserveUseListOrder); } else { for (const auto &F : M->functions()) { printIR(OS, &F, Banner, Extra); @@ -159,17 +192,19 @@ /// Generic IR-printing helper that unpacks a pointer to IRUnit wrapped into /// llvm::Any and does actual print job. void unwrapAndPrint(raw_ostream &OS, Any IR, StringRef Banner, - bool ForceModule = false, bool Brief = false) { + bool ForceModule = false, bool Brief = false, + bool ShouldPreserveUseListOrder = false) { if (ForceModule) { if (auto UnwrappedModule = unwrapModule(IR)) - printIR(OS, UnwrappedModule->first, Banner, UnwrappedModule->second); + printIR(OS, UnwrappedModule->first, Banner, UnwrappedModule->second, + Brief, ShouldPreserveUseListOrder); return; } if (any_isa(IR)) { const Module *M = any_cast(IR); assert(M && "module should be valid for printing"); - printIR(OS, M, Banner, "", Brief); + printIR(OS, M, Banner, "", Brief, ShouldPreserveUseListOrder); return; } @@ -197,8 +232,196 @@ llvm_unreachable("Unknown wrapped IR type"); } +// Return true when this is a pass for which changes should be ignored +inline bool isIgnored(StringRef PassID) { + return isSpecialPass(PassID, + {"PassManager", "PassAdaptor", "AnalysisManagerProxy"}); +} + +// Return true when this is a defined function for which printing +// of changes is desired. +inline bool isInterestingFunction(const Function &F) { + return llvm::isFunctionInPrintList(F.getName()); +} + +// Return true when this is a pass for which printing of changes is desired. +inline bool isInterestingPass(StringRef PassID) { + if (isIgnored(PassID)) + return false; + + static std::unordered_set PrintPassNames(PrintPassesList.begin(), + PrintPassesList.end()); + return PrintPassNames.empty() || PrintPassNames.count(PassID.str()); +} + +// Return true when this is a pass on IR for which printing +// of changes is desired. +bool isInteresting(Any IR, StringRef PassID) { + if (!isInterestingPass(PassID)) + return false; + if (any_isa(IR)) + return isInterestingFunction(*any_cast(IR)); + return true; +} + } // namespace +template +void ChangePrinter::saveIRBeforePass(Any IR, StringRef PassID) { + // Always need to place something on the stack because invalidated passes + // are not given the IR so it cannot be determined whether the pass was for + // something that was filtered out. + BeforeStack.emplace_back(); + + if (!isInteresting(IR, PassID)) + return; + // Is this the initial IR? + if (InitialIR) { + InitialIR = false; + handleInitialIR(IR); + } + + // Save the IR representation on the stack. + IRUnitT &Data = BeforeStack.back(); + generateIRRepresentation(IR, PassID, Data); +} + +template +void ChangePrinter::handleIRAfterPass(Any IR, StringRef PassID) { + assert(!BeforeStack.empty() && "Unexpected empty stack encountered."); + std::string Name; + + // unwrapModule has inconsistent handling of names for function IRs. + if (any_isa(IR)) { + const Function *F = any_cast(IR); + Name = formatv(" (function: {0})", F->getName()).str(); + } else { + if (auto UM = unwrapModule(IR)) + Name = UM->second; + } + if (Name.empty()) + Name = " (module)"; + + if (isIgnored(PassID)) + handleIgnored(PassID, Name); + else if (!isInteresting(IR, PassID)) + handleFiltered(PassID, Name); + else { + // Get the before rep from the stack + IRUnitT &Before = BeforeStack.back(); + // Create the after rep + IRUnitT After; + generateIRRepresentation(IR, PassID, After); + + // Was there a change in IR? + if (same(Before, After)) + omitAfter(PassID, Name); + else + handleAfter(PassID, Name, Before, After, IR); + } + BeforeStack.pop_back(); +} + +template +void ChangePrinter::handleInvalidatedPass(StringRef PassID) { + assert(!BeforeStack.empty() && "Unexpected empty stack encountered."); + + // Always flag it as invalidated as we cannot determine when + // a pass for a filtered function is invalidated since we do not + // get the IR in the call. Also, the output is just alternate + // forms of the banner anyway. + handleInvalidated(PassID); + BeforeStack.pop_back(); +} + +template ChangePrinter::~ChangePrinter() { + assert(BeforeStack.empty() && "Problem with Change Printer stack."); +} + +IRChangePrinter::IRChangePrinter() : Out(dbgs()) {} + +IRChangePrinter::~IRChangePrinter() {} + +void IRChangePrinter::registerCallbacks(PassInstrumentationCallbacks &PIC) { + if (!PrintChanged) + return; + + PIC.registerBeforePassCallback([this](StringRef P, Any IR) { + saveIRBeforePass(IR, P); + return true; + }); + + PIC.registerAfterPassCallback( + [this](StringRef P, Any IR, const PreservedAnalyses &) { + handleIRAfterPass(IR, P); + }); + PIC.registerAfterPassInvalidatedCallback( + [this](StringRef P, const PreservedAnalyses &) { + handleInvalidatedPass(P); + }); +} + +void IRChangePrinter::handleInitialIR(Any IR) { + // Always print the module. + // Unwrap and print directly to avoid filtering problems in general routines. + auto UnwrappedModule = unwrapModule(IR, /*Force=*/true); + assert(UnwrappedModule && "Expected module to be unwrapped when forced."); + Out << "*** IR Dump At Start: ***" << UnwrappedModule->second << "\n"; + UnwrappedModule->first->print(Out, nullptr, + /*ShouldPreserveUseListOrder=*/true); +} + +void IRChangePrinter::generateIRRepresentation(Any IR, StringRef PassID, + std::string &Output) { + raw_string_ostream OS(Output); + // use the after banner for all cases so it will match + SmallString<20> Banner = formatv("*** IR Dump After {0} ***", PassID); + unwrapAndPrint(OS, IR, Banner, llvm::forcePrintModuleIR(), + /*Brief=*/false, /*ShouldPreserveUseListOrder=*/true); + OS.str(); +} + +void IRChangePrinter::omitAfter(StringRef PassID, std::string &Name) { + Out << formatv("*** IR Dump After {0}{1} omitted because no change ***\n", + PassID, Name); +} + +void IRChangePrinter::handleAfter(StringRef PassID, std::string &Name, + const std::string &Before, + const std::string &After, Any) { + assert(After.find("*** IR Dump") == 0 && "Unexpected banner format."); + StringRef AfterRef = After; + StringRef Banner = + AfterRef.take_until([](char C) -> bool { return C == '\n'; }); + Out << Banner; + + // LazyCallGraph::SCC already has "(scc:..." in banner so only add + // in the name if it isn't already there. + if (Name.substr(0, 6) != " (scc:" && !llvm::forcePrintModuleIR()) + Out << Name; + + Out << After.substr(Banner.size()); +} + +void IRChangePrinter::handleInvalidated(StringRef PassID) { + Out << formatv("*** IR Pass {0} invalidated ***\n", PassID); +} + +void IRChangePrinter::handleFiltered(StringRef PassID, std::string &Name) { + SmallString<20> Banner = + formatv("*** IR Dump After {0}{1} filtered out ***\n", PassID, Name); + Out << Banner; +} + +void IRChangePrinter::handleIgnored(StringRef PassID, std::string &Name) { + Out << formatv("*** IR Pass {0}{1} ignored ***\n", PassID, Name); +} + +bool IRChangePrinter::same(const std::string &Before, + const std::string &After) { + return Before == After; +} + PrintIRInstrumentation::~PrintIRInstrumentation() { assert(ModuleDescStack.empty() && "ModuleDescStack is not empty at exit"); } @@ -508,4 +731,5 @@ TimePasses.registerCallbacks(PIC); OptNone.registerCallbacks(PIC); PreservedCFGChecker.registerCallbacks(PIC); + PrintChangedIR.registerCallbacks(PIC); } Index: llvm/test/Other/change-printer.ll =================================================================== --- /dev/null +++ llvm/test/Other/change-printer.ll @@ -0,0 +1,128 @@ +; Simple checks of -print-changed functionality +; +; Note that (mostly) only the banners are checked. +; +; Simple functionality check. +; RUN: opt -S -print-changed -passes=instsimplify 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-SIMPLE +; +; Check that only the passes that change the IR are printed and that the +; others (including g) are filtered out. +; RUN: opt -S -print-changed -passes=instsimplify -filter-print-funcs=f 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-FUNC-FILTER +; +; Check that the reporting of IRs respects -print-module-scope +; RUN: opt -S -print-changed -passes=instsimplify -print-module-scope 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-PRINT-MOD-SCOPE +; +; Check that the reporting of IRs respects -print-module-scope +; RUN: opt -S -print-changed -passes=instsimplify -filter-print-funcs=f -print-module-scope 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-FUNC-FILTER-MOD-SCOPE +; +; Check that reporting of multiple functions happens +; RUN: opt -S -print-changed -passes=instsimplify -filter-print-funcs="f,g" 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-FILTER-MULT-FUNC +; +; Check that the reporting of IRs respects -filter-passes +; RUN: opt -S -print-changed -passes="instsimplify,no-op-function" -filter-passes="NoOpFunctionPass" 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-FILTER-PASSES +; +; Check that the reporting of IRs respects -filter-passes with multiple passes +; RUN: opt -S -print-changed -passes="instsimplify,no-op-function" -filter-passes="NoOpFunctionPass,InstSimplifyPass" 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-FILTER-MULT-PASSES +; +; Check that the reporting of IRs respects both -filter-passes and -filter-print-funcs +; RUN: opt -S -print-changed -passes="instsimplify,no-op-function" -filter-passes="NoOpFunctionPass,InstSimplifyPass" -filter-print-funcs=f 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-FILTER-FUNC-PASSES +; +; Check that the reporting of IRs respects -filter-passes, -filter-print-funcs and -print-module-scope +; RUN: opt -S -print-changed -passes="instsimplify,no-op-function" -filter-passes="NoOpFunctionPass,InstSimplifyPass" -filter-print-funcs=f -print-module-scope 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-FILTER-FUNC-PASSES-MOD-SCOPE +; +; Check that repeated passes that change the IR are printed and that the +; others (including g) are filtered out. Note that the second time +; instsimplify is run on f, it does not change the IR +; RUN: opt -S -print-changed -passes="instsimplify,instsimplify" -filter-print-funcs=f 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-MULT-PASSES-FILTER-FUNC + +define i32 @g() { +entry: + %a = add i32 2, 3 + ret i32 %a +} + +define i32 @f() { +entry: + %a = add i32 2, 3 + ret i32 %a +} + +; CHECK-SIMPLE: *** IR Dump At Start: *** +; CHECK-SIMPLE-NEXT: ; ModuleID = {{.+}} +; CHECK-SIMPLE: *** IR Dump After VerifierPass (module) omitted because no change *** +; CHECK-SIMPLE: *** IR Dump After InstSimplifyPass *** (function: g) +; CHECK-SIMPLE-NEXT: define i32 @g() +; CHECK-SIMPLE: *** IR Pass PassManager{{.*}} (function: g) ignored *** +; CHECK-SIMPLE: *** IR Dump After InstSimplifyPass *** (function: f) +; CHECK-SIMPLE-NEXT: define i32 @f() +; CHECK-SIMPLE: *** IR Pass PassManager{{.*}} (function: f) ignored *** +; CHECK-SIMPLE: *** IR Pass ModuleToFunctionPassAdaptor<{{.*}}PassManager{{.*}}> (module) ignored *** +; CHECK-SIMPLE: *** IR Dump After VerifierPass (module) omitted because no change *** +; CHECK-SIMPLE: *** IR Dump After PrintModulePass (module) omitted because no change *** +; CHECK-SIMPLE-NOT: *** IR + +; CHECK-FUNC-FILTER: *** IR Dump At Start: *** +; CHECK-FUNC-FILTER-NEXT: ; ModuleID = {{.+}} +; CHECK-FUNC-FILTER: *** IR Dump After InstSimplifyPass (function: g) filtered out *** +; CHECK-FUNC-FILTER: *** IR Dump After InstSimplifyPass *** (function: f) +; CHECK-FUNC-FILTER-NEXT: define i32 @f() + +; CHECK-PRINT-MOD-SCOPE: *** IR Dump At Start: *** +; CHECK-PRINT-MOD-SCOPE-NEXT: ModuleID = {{.+}} +; CHECK-PRINT-MOD-SCOPE: *** IR Dump After InstSimplifyPass *** (function: g) +; CHECK-PRINT-MOD-SCOPE-NEXT: ModuleID = {{.+}} +; CHECK-PRINT-MOD-SCOPE: *** IR Dump After InstSimplifyPass *** (function: f) +; CHECK-PRINT-MOD-SCOPE-NEXT: ModuleID = {{.+}} + +; CHECK-FUNC-FILTER-MOD-SCOPE: *** IR Dump At Start: *** +; CHECK-FUNC-FILTER-MOD-SCOPE-NEXT: ; ModuleID = {{.+}} +; CHECK-FUNC-FILTER-MOD-SCOPE: *** IR Dump After InstSimplifyPass (function: g) filtered out *** +; CHECK-FUNC-FILTER-MOD-SCOPE: *** IR Dump After InstSimplifyPass *** (function: f) +; CHECK-FUNC-FILTER-MOD-SCOPE-NEXT: ModuleID = {{.+}} + +; CHECK-FILTER-MULT-FUNC: *** IR Dump At Start: *** +; CHECK-FILTER-MULT-FUNC-NEXT: ; ModuleID = {{.+}} +; CHECK-FILTER-MULT-FUNC: *** IR Dump After InstSimplifyPass *** (function: g) +; CHECK-FILTER-MULT-FUNC-NEXT: define i32 @g() +; CHECK-FILTER-MULT-FUNC: *** IR Dump After InstSimplifyPass *** (function: f) +; CHECK-FILTER-MULT-FUNC-NEXT: define i32 @f() + +; CHECK-FILTER-PASSES: *** IR Dump After InstSimplifyPass (function: g) filtered out *** +; CHECK-FILTER-PASSES: *** IR Dump At Start: *** (function: g) +; CHECK-FILTER-PASSES-NEXT: ; ModuleID = {{.+}} +; CHECK-FILTER-PASSES: *** IR Dump After NoOpFunctionPass (function: g) omitted because no change *** +; CHECK-FILTER-PASSES: *** IR Dump After InstSimplifyPass (function: f) filtered out *** +; CHECK-FILTER-PASSES: *** IR Dump After NoOpFunctionPass (function: f) omitted because no change *** + +; CHECK-FILTER-MULT-PASSES: *** IR Dump At Start: *** (function: g) +; CHECK-FILTER-MULT-PASSES-NEXT: ; ModuleID = {{.+}} +; CHECK-FILTER-MULT-PASSES: *** IR Dump After InstSimplifyPass *** (function: g) +; CHECK-FILTER-MULT-PASSES-NEXT: define i32 @g() +; CHECK-FILTER-MULT-PASSES: *** IR Dump After NoOpFunctionPass (function: g) omitted because no change *** +; CHECK-FILTER-MULT-PASSES: *** IR Dump After InstSimplifyPass *** (function: f) +; CHECK-FILTER-MULT-PASSES-NEXT: define i32 @f() +; CHECK-FILTER-MULT-PASSES: *** IR Dump After NoOpFunctionPass (function: f) omitted because no change *** + +; CHECK-FILTER-FUNC-PASSES: *** IR Dump After InstSimplifyPass (function: g) filtered out *** +; CHECK-FILTER-FUNC-PASSES: *** IR Dump After NoOpFunctionPass (function: g) filtered out *** +; CHECK-FILTER-FUNC-PASSES: *** IR Dump At Start: *** (function: f) +; CHECK-FILTER-FUNC-PASSES-NEXT: ; ModuleID = {{.+}} +; CHECK-FILTER-FUNC-PASSES: *** IR Dump After InstSimplifyPass *** (function: f) +; CHECK-FILTER-FUNC-PASSES-NEXT: define i32 @f() +; CHECK-FILTER-FUNC-PASSES: *** IR Dump After NoOpFunctionPass (function: f) omitted because no change *** + +; CHECK-FILTER-FUNC-PASSES-MOD-SCOPE: *** IR Dump After InstSimplifyPass (function: g) filtered out *** +; CHECK-FILTER-FUNC-PASSES-MOD-SCOPE: *** IR Dump After NoOpFunctionPass (function: g) filtered out *** +; CHECK-FILTER-FUNC-PASSES-MOD-SCOPE: *** IR Dump At Start: *** (function: f) +; CHECK-FILTER-FUNC-PASSES-MOD-SCOPE-NEXT: ; ModuleID = {{.+}} +; CHECK-FILTER-FUNC-PASSES-MOD-SCOPE: *** IR Dump After InstSimplifyPass *** (function: f) +; CHECK-FILTER-FUNC-PASSES-MOD-SCOPE-NEXT: ModuleID = {{.+}} +; CHECK-FILTER-FUNC-PASSES-MOD-SCOPE: *** IR Dump After NoOpFunctionPass (function: f) omitted because no change *** + +; CHECK-MULT-PASSES-FILTER-FUNC: *** IR Dump At Start: *** +; CHECK-MULT-PASSES-FILTER-FUNC-NEXT: ; ModuleID = {{.+}} +; CHECK-MULT-PASSES-FILTER-FUNC: *** IR Dump After InstSimplifyPass (function: g) filtered out *** +; CHECK-MULT-PASSES-FILTER-FUNC: *** IR Dump After InstSimplifyPass (function: g) filtered out *** +; CHECK-MULT-PASSES-FILTER-FUNC: *** IR Dump After InstSimplifyPass *** (function: f) +; CHECK-MULT-PASSES-FILTER-FUNC-NEXT: define i32 @f() +; CHECK-MULT-PASSES-FILTER-FUNC: *** IR Dump After InstSimplifyPass (function: f) omitted because no change ***