[llvm] 71124a9 - Reland No.3: Add new hidden option -print-changed which only reports changes to IR

Anh Tuyen Tran via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 1 10:39:36 PDT 2020


Author: Jamie Schmeiser
Date: 2020-10-01T17:39:13Z
New Revision: 71124a9dbdcc76cd5efec8c148001a3f808bd769

URL: https://github.com/llvm/llvm-project/commit/71124a9dbdcc76cd5efec8c148001a3f808bd769
DIFF: https://github.com/llvm/llvm-project/commit/71124a9dbdcc76cd5efec8c148001a3f808bd769.diff

LOG: Reland No.3: Add new hidden option -print-changed which only reports changes to IR

A new hidden option -print-changed is added along with code to support
printing the IR as it passes through the opt pipeline in the new pass
manager. Only those passes that change the IR are reported, with others
only having the banner reported, indicating that they did not change the
IR, were filtered out or ignored. Filtering of output via the
-filter-print-funcs is supported and a new supporting hidden option
-filter-passes is added. The latter takes a comma separated list of pass
names and filters the output to only show those passes in the list that
change the IR. The output can also be modified via the -print-module-scope
function.

The code introduces an abstract template base class that generalizes the
comparison of IRs that takes an IR representation as template parameter.
Derived classes provide overrides that provide an event based API
for generalized reporting of IRs as they are changed in the opt pipeline
through the new pass manager.

The first of several instantiations is provided that prints the IR
in a form similar to that produced by -print-after-all with the above
mentioned filtering capabilities. This version, and the others to
follow will be introduced at the upcoming developer's conference.

Reviewed By: aeubanks (Arthur Eubanks), yrouban (Yevgeny Rouban), ychen (Yuanfang Chen), MaskRay (Fangrui Song)

Differential Revision: https://reviews.llvm.org/D86360

Added: 
    llvm/test/Other/change-printer.ll

Modified: 
    llvm/include/llvm/Passes/StandardInstrumentations.h
    llvm/lib/IR/LegacyPassManager.cpp
    llvm/lib/Passes/StandardInstrumentations.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Passes/StandardInstrumentations.h b/llvm/include/llvm/Passes/StandardInstrumentations.h
index 52850898c6b8..9d03aeb6cec4 100644
--- a/llvm/include/llvm/Passes/StandardInstrumentations.h
+++ b/llvm/include/llvm/Passes/StandardInstrumentations.h
@@ -122,6 +122,97 @@ class PreservedCFGCheckerInstrumentation {
   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 <typename IRUnitT> 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<IRUnitT> 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<std::string> {
+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 {
@@ -130,6 +221,7 @@ class StandardInstrumentations {
   TimePassesHandler TimePasses;
   OptNoneInstrumentation OptNone;
   PreservedCFGCheckerInstrumentation PreservedCFGChecker;
+  IRChangePrinter PrintChangedIR;
 
 public:
   StandardInstrumentations(bool DebugLogging) : PrintPass(DebugLogging) {}

diff  --git a/llvm/lib/IR/LegacyPassManager.cpp b/llvm/lib/IR/LegacyPassManager.cpp
index 8d9ed917bb61..7f94d42d6ecd 100644
--- a/llvm/lib/IR/LegacyPassManager.cpp
+++ b/llvm/lib/IR/LegacyPassManager.cpp
@@ -87,14 +87,14 @@ static cl::opt<bool> PrintAfterAll("print-after-all",
 static cl::opt<bool>
     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<std::string>
     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

diff  --git a/llvm/lib/Passes/StandardInstrumentations.cpp b/llvm/lib/Passes/StandardInstrumentations.cpp
index 2ee373b912be..d2ef2cd4ed61 100644
--- a/llvm/lib/Passes/StandardInstrumentations.cpp
+++ b/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 <unordered_set>
 #include <vector>
 
 using namespace llvm;
@@ -51,18 +52,48 @@ static cl::opt<bool>
                    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 
diff erent formats, with the rest being
+// reported as filtered out.
+static cl::opt<bool> 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<std::string>
+    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<std::pair<const Module *, std::string>> unwrapModule(Any IR) {
+Optional<std::pair<const Module *, std::string>>
+unwrapModule(Any IR, bool Force = false) {
   if (any_isa<const Module *>(IR))
     return std::make_pair(any_cast<const Module *>(IR), std::string());
 
   if (any_isa<const Function *>(IR)) {
     const Function *F = any_cast<const Function *>(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 @@ Optional<std::pair<const Module *, std::string>> unwrapModule(Any IR) {
     const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(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<const Loop *>(IR)) {
     const Loop *L = any_cast<const Loop *>(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 Function *F, StringRef Banner,
 }
 
 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 @@ void printIR(raw_ostream &OS, const Module *M, StringRef Banner,
 
   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 @@ void printIR(raw_ostream &OS, const Loop *L, StringRef Banner,
 /// 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<const Module *>(IR)) {
     const Module *M = any_cast<const Module *>(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 @@ void unwrapAndPrint(raw_ostream &OS, Any IR, StringRef Banner,
   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<std::string> 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<const Function *>(IR))
+    return isInterestingFunction(*any_cast<const Function *>(IR));
+  return true;
+}
+
 } // namespace
 
+template <typename IRUnitT>
+void ChangePrinter<IRUnitT>::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 <typename IRUnitT>
+void ChangePrinter<IRUnitT>::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<const Function *>(IR)) {
+    const Function *F = any_cast<const Function *>(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 <typename IRUnitT>
+void ChangePrinter<IRUnitT>::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 <typename IRUnitT> ChangePrinter<IRUnitT>::~ChangePrinter<IRUnitT>() {
+  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 @@ void StandardInstrumentations::registerCallbacks(
   TimePasses.registerCallbacks(PIC);
   OptNone.registerCallbacks(PIC);
   PreservedCFGChecker.registerCallbacks(PIC);
+  PrintChangedIR.registerCallbacks(PIC);
 }

diff  --git a/llvm/test/Other/change-printer.ll b/llvm/test/Other/change-printer.ll
new file mode 100644
index 000000000000..7e3f0046ef79
--- /dev/null
+++ b/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 ***


        


More information about the llvm-commits mailing list