[llvm] 7bc9924 - 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 Sep 3 08:52:48 PDT 2020


Author: Jamie Schmeiser
Date: 2020-09-03T15:52:35Z
New Revision: 7bc9924cb2fbd9f3ae53577607822ace267a04e6

URL: https://github.com/llvm/llvm-project/commit/7bc9924cb2fbd9f3ae53577607822ace267a04e6
DIFF: https://github.com/llvm/llvm-project/commit/7bc9924cb2fbd9f3ae53577607822ace267a04e6.diff

LOG: 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 a template base class that generalizes the comparison
of IRs that takes an IR representation as template parameter. The
constructor takes a series of lambdas 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.
See https://hotcrp.llvm.org/usllvm2020/paper/29 for more information.

Reviewed By: yrouban (Yevgeny Rouban)

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 795e2770bbe1..5a93c51ad18b 100644
--- a/llvm/include/llvm/Passes/StandardInstrumentations.h
+++ b/llvm/include/llvm/Passes/StandardInstrumentations.h
@@ -25,6 +25,7 @@
 
 namespace llvm {
 
+class Function;
 class Module;
 
 /// Instrumentation to print IR before/after passes.
@@ -73,6 +74,98 @@ class PrintPassInstrumentation {
   bool DebugLogging;
 };
 
+// Base class for classes that report changes to the IR.
+// It presents an interface for such classes and provides callbacks
+// 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.
+// Callbacks 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 T> class ChangePrinter {
+protected:
+  ChangePrinter(
+      std::function<void(Any IR)> HandleInitialIRFunc,
+      std::function<void(Any IR, StringRef PassID, T &Output)>
+          GenerateIRRepresentationFunc,
+      std::function<void(StringRef PassID, std::string &Name)> OmitAfterFunc,
+      std::function<void(StringRef PassID, std::string &Name, const T &Before,
+                         const T &After, Any IR)>
+          HandleAfterFunc,
+      std::function<void(StringRef PassID)> HandleInvalidatedFunc,
+      std::function<void(StringRef PassID, std::string &Name)>
+          HandleFilteredFunc,
+      std::function<void(StringRef PassID, std::string &Name)>
+          HandleIgnoredFunc,
+      std::function<bool(const T &Before, const T &After)> SameFunc)
+      : HandleInitialIR(HandleInitialIRFunc),
+        GenerateIRRepresentation(GenerateIRRepresentationFunc),
+        OmitAfter(OmitAfterFunc), HandleAfter(HandleAfterFunc),
+        HandleInvalidated(HandleInvalidatedFunc),
+        HandleFiltered(HandleFilteredFunc), HandleIgnored(HandleIgnoredFunc),
+        Same(SameFunc), InitialIR(true) {}
+
+public:
+  // Not virtual as classes are expected to be referenced as derived classes.
+  ~ChangePrinter() {
+    assert(BeforeStack.empty() && "Problem with Change Printer stack.");
+  }
+
+  // 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);
+
+private:
+  // callback on the first IR processed
+  std::function<void(Any IR)> HandleInitialIR;
+  // callback before and after a pass to get the representation of the IR
+  std::function<void(Any IR, StringRef PassID, T &Output)>
+      GenerateIRRepresentation;
+  // callback when the pass is not iteresting
+  std::function<void(StringRef PassID, std::string &Name)> OmitAfter;
+  // callback when interesting IR has changed
+  std::function<void(StringRef PassID, std::string &Name, const T &Before,
+                     const T &After, Any)>
+      HandleAfter;
+  // callback when an interesting pass is invalidated
+  std::function<void(StringRef PassID)> HandleInvalidated;
+  // callback when the IR or pass is not interesting
+  std::function<void(StringRef PassID, std::string &Name)> HandleFiltered;
+  // callback when an ignored pass is encountered
+  std::function<void(StringRef PassID, std::string &Name)> HandleIgnored;
+  // callback to compare the before and after representations of the IR
+  std::function<bool(const T &Before, const T &After)> Same;
+
+  // stack of IRs before passes
+  std::vector<T> BeforeStack;
+  // Is this the first IR seen?
+  bool InitialIR;
+};
+
+// 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();
+  void registerCallbacks(PassInstrumentationCallbacks &PIC);
+
+protected:
+  raw_ostream &Out;
+};
+
 /// This class provides an interface to register all the standard pass
 /// instrumentations and manages their state (if any).
 class StandardInstrumentations {
@@ -80,6 +173,7 @@ class StandardInstrumentations {
   PrintPassInstrumentation PrintPass;
   TimePassesHandler TimePasses;
   OptNoneInstrumentation OptNone;
+  IRChangePrinter PrintChangedIR;
 
 public:
   StandardInstrumentations(bool DebugLogging) : PrintPass(DebugLogging) {}

diff  --git a/llvm/lib/IR/LegacyPassManager.cpp b/llvm/lib/IR/LegacyPassManager.cpp
index 8d9ed917bb61..63886f486170 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 da58fa57bdae..d36bfd87f8a6 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;
@@ -43,6 +44,34 @@ static cl::opt<bool>
                    cl::desc("Print all pass management debugging information. "
                             "`-debug-pass-manager` must also be specified"));
 
+// A hidden 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);
+// A hidden 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
@@ -189,8 +218,197 @@ void unwrapAndPrint(raw_ostream &OS, Any IR, StringRef Banner,
   llvm_unreachable("Unknown wrapped IR type");
 }
 
+// Return true when this is a pass for which printing of changes is desired.
+inline bool isIgnored(StringRef PassID) {
+  return PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<");
+}
+
+// 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 T>
+void ChangePrinter<T>::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.
+  auto &Data = BeforeStack.back();
+  GenerateIRRepresentation(IR, PassID, Data);
+}
+
+template <typename T>
+void ChangePrinter<T>::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 == "")
+    Name = " (module)";
+
+  if (isIgnored(PassID))
+    HandleIgnored(PassID, Name);
+  else if (!isInteresting(IR, PassID))
+    HandleFiltered(PassID, Name);
+  else {
+    // Get the before rep from the stack
+    T &Before = BeforeStack.back();
+    // Create the after rep
+    T 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 T>
+void ChangePrinter<T>::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 callback.  Also, the output is just alternate
+  // forms of the banner anyway.
+  HandleInvalidated(PassID);
+  BeforeStack.pop_back();
+}
+
+void handleInitialIR(Any IR, raw_ostream &Out) {
+  StringRef Banner("*** IR Dump At Start: ***");
+  unwrapAndPrint(Out, IR, Banner, true);
+}
+
+void generateOutput(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());
+  OS.str();
+}
+
+void omitAfter(StringRef PassID, std::string &Name, raw_ostream &Out) {
+  Out << formatv("*** IR Dump After {0}{1} omitted because no change ***\n",
+                 PassID, Name);
+}
+
+void handleAfter(const StringRef After, std::string &Name, raw_ostream &Out) {
+  assert(After.find("*** IR Dump") == 0 && "Unexpected banner format.");
+  StringRef Banner = After.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).compare(" (scc:") != 0 && !llvm::forcePrintModuleIR())
+    Out << Name;
+
+  Out << After.substr(Banner.size());
+}
+
+void handleInvalidated(StringRef PassID, raw_ostream &Out) {
+  Out << formatv("*** IR Pass {0} invalidated ***\n", PassID);
+}
+
+void handleFiltered(StringRef PassID, std::string &Name, raw_ostream &Out) {
+  SmallString<20> Banner =
+      formatv("*** IR Dump After {0}{1} filtered out ***\n", PassID, Name);
+  Out << Banner;
+}
+
+void handleIgnored(StringRef PassID, std::string &Name, raw_ostream &Out) {
+  Out << formatv("*** IR Pass {0}{1} ignored ***\n", PassID, Name);
+}
+
+bool sameIR(const std::string &S1, const std::string &S2) {
+  return S1.compare(S2) == 0;
+}
+
+IRChangePrinter::IRChangePrinter()
+    : ChangePrinter<std::string>(
+          [this](Any IR) -> void { ::handleInitialIR(IR, Out); },
+          ::generateOutput,
+          [this](StringRef PassID, std::string &Name) -> void {
+            ::omitAfter(PassID, Name, Out);
+          },
+          [this](StringRef PassID, std::string &Name, const std::string &Before,
+                 const std::string &After,
+                 Any IR) -> void { ::handleAfter(After, Name, Out); },
+          [this](StringRef PassID) -> void {
+            ::handleInvalidated(PassID, Out);
+          },
+          [this](StringRef PassID, std::string &Name) -> void {
+            ::handleFiltered(PassID, Name, Out);
+          },
+          [this](StringRef PassID, std::string &Name) -> void {
+            ::handleIgnored(PassID, Name, Out);
+          },
+          ::sameIR),
+      Out(dbgs()) {}
+
+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);
+      });
+}
+
 PrintIRInstrumentation::~PrintIRInstrumentation() {
   assert(ModuleDescStack.empty() && "ModuleDescStack is not empty at exit");
 }
@@ -344,4 +562,5 @@ void StandardInstrumentations::registerCallbacks(
   PrintPass.registerCallbacks(PIC);
   TimePasses.registerCallbacks(PIC);
   OptNone.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..51354fcc0341
--- /dev/null
+++ b/llvm/test/Other/change-printer.ll
@@ -0,0 +1,109 @@
+; 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=CHECK0
+;
+; 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=CHECK1
+;
+; 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=CHECK2
+;
+; 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=CHECK3
+;
+; 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=CHECK4
+;
+; 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=CHECK5
+;
+; 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=CHECK6
+;
+; 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=CHECK7
+;
+; 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=CHECK8
+;
+; 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=CHECK9
+
+define i32 @g() {
+entry:
+  %a = add i32 2, 3
+  ret i32 %a
+}
+
+define i32 @f() {
+entry:
+  %a = add i32 2, 3
+  ret i32 %a
+}
+
+; CHECK0: *** IR Dump At Start: ***
+; CHECK0: ; ModuleID = '<stdin>'
+; CHECK0: *** IR Dump After VerifierPass (module) omitted because no change ***
+; CHECK0: *** IR Dump After InstSimplifyPass *** (function: g)
+; CHECK0: *** IR Pass PassManager<llvm::Function> (function: g) ignored ***
+; CHECK0: *** IR Dump After InstSimplifyPass *** (function: f)
+; CHECK0: *** IR Pass PassManager<llvm::Function> (function: f) ignored ***
+; CHECK0: *** IR Pass ModuleToFunctionPassAdaptor<llvm::PassManager<llvm::Function> > (module) ignored ***
+; CHECK0: *** IR Dump After VerifierPass (module) omitted because no change ***
+; CHECK0: *** IR Dump After PrintModulePass (module) omitted because no change ***
+
+; CHECK1: *** IR Dump At Start: ***
+; CHECK1: *** IR Dump After InstSimplifyPass (function: g) filtered out ***
+; CHECK1: *** IR Dump After InstSimplifyPass *** (function: f)
+
+; CHECK2: *** IR Dump At Start: ***
+; CHECK2: *** IR Dump After InstSimplifyPass *** (function: g)
+; CHECK2: ModuleID = '<stdin>'
+; CHECK2: *** IR Dump After InstSimplifyPass *** (function: f)
+; CHECK2: ModuleID = '<stdin>'
+
+; CHECK3: *** IR Dump At Start: ***
+; CHECK3: *** IR Dump After InstSimplifyPass (function: g) filtered out ***
+; CHECK3: *** IR Dump After InstSimplifyPass *** (function: f)
+; CHECK3: ModuleID = '<stdin>'
+
+; CHECK4: *** IR Dump At Start: ***
+; CHECK4: *** IR Dump After InstSimplifyPass *** (function: g)
+; CHECK4: *** IR Dump After InstSimplifyPass *** (function: f)
+
+; CHECK5: *** IR Dump After InstSimplifyPass (function: g) filtered out ***
+; CHECK5: *** IR Dump At Start: *** (function: g)
+; CHECK5: *** IR Dump After NoOpFunctionPass (function: g) omitted because no change ***
+; CHECK5: *** IR Dump After InstSimplifyPass (function: f) filtered out ***
+; CHECK5: *** IR Dump After NoOpFunctionPass (function: f) omitted because no change ***
+
+; CHECK6: *** IR Dump At Start: *** (function: g)
+; CHECK6: *** IR Dump After InstSimplifyPass *** (function: g)
+; CHECK6: *** IR Dump After NoOpFunctionPass (function: g) omitted because no change ***
+; CHECK6: *** IR Dump After InstSimplifyPass *** (function: f)
+; CHECK6: *** IR Dump After NoOpFunctionPass (function: f) omitted because no change ***
+
+; CHECK7: *** IR Dump After InstSimplifyPass (function: g) filtered out ***
+; CHECK7: *** IR Dump After NoOpFunctionPass (function: g) filtered out ***
+; CHECK7: *** IR Dump At Start: *** (function: f)
+; CHECK7: *** IR Dump After InstSimplifyPass *** (function: f)
+; CHECK7: *** IR Dump After NoOpFunctionPass (function: f) omitted because no change ***
+
+; CHECK8: *** IR Dump After InstSimplifyPass (function: g) filtered out ***
+; CHECK8: *** IR Dump After NoOpFunctionPass (function: g) filtered out ***
+; CHECK8: *** IR Dump At Start: *** (function: f)
+; CHECK8: *** IR Dump After InstSimplifyPass *** (function: f)
+; CHECK8: ModuleID = '<stdin>'
+; CHECK8: *** IR Dump After NoOpFunctionPass (function: f) omitted because no change ***
+
+; CHECK9: *** IR Dump At Start: ***
+; CHECK9: *** IR Dump After InstSimplifyPass (function: g) filtered out ***
+; CHECK9: *** IR Dump After InstSimplifyPass (function: g) filtered out ***
+; CHECK9: *** IR Dump After InstSimplifyPass *** (function: f)
+; CHECK9: *** IR Dump After InstSimplifyPass (function: f) omitted because no change ***


        


More information about the llvm-commits mailing list