[llvm] 4b661b4 - Introduce -print-changed=[diff | diff-quiet] which show changes in patch-like format

Jamie Schmeiser via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 8 07:11:47 PST 2021


Author: Jamie Schmeiser
Date: 2021-02-08T10:11:22-05:00
New Revision: 4b661b4059b0b5fa8594a0717df208a122ea15da

URL: https://github.com/llvm/llvm-project/commit/4b661b4059b0b5fa8594a0717df208a122ea15da
DIFF: https://github.com/llvm/llvm-project/commit/4b661b4059b0b5fa8594a0717df208a122ea15da.diff

LOG: Introduce -print-changed=[diff | diff-quiet] which show changes in patch-like format
Summary:
Introduce base classes that hold a textual represent of the IR
based on basic blocks and a base class for comparing this
representation.  A new change printer is introduced that uses these
classes to save and compare representations of the IR before and after
each pass.  It only reports when changes are made by a pass (similar to
-print-changed) except that the changes are shown in a patch-like format
with those lines that are removed shown in red prefixed with '-' and those
added shown in green with '+'.  This functionality was introduced in my
tutorial at the 2020 virtual developer's meeting.

Author: Jamie Schmeiser <schmeise at ca.ibm.com>
Reviewed By: aeubanks (Arthur Eubanks)
Differential Revision: https://reviews.llvm.org/D91890

Added: 
    llvm/test/Other/ChangePrinters/lit.local.cfg
    llvm/test/Other/ChangePrinters/print-changed-diff.ll

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

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Passes/StandardInstrumentations.h b/llvm/include/llvm/Passes/StandardInstrumentations.h
index 61c86b0468f2..f023a2924d8f 100644
--- a/llvm/include/llvm/Passes/StandardInstrumentations.h
+++ b/llvm/include/llvm/Passes/StandardInstrumentations.h
@@ -15,6 +15,7 @@
 #ifndef LLVM_PASSES_STANDARDINSTRUMENTATIONS_H
 #define LLVM_PASSES_STANDARDINSTRUMENTATIONS_H
 
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/IR/BasicBlock.h"
@@ -256,6 +257,131 @@ class IRChangedPrinter : public TextChangeReporter<std::string> {
   bool same(const std::string &Before, const std::string &After) override;
 };
 
+// The following classes hold a representation of the IR for a change
+// reporter that uses string comparisons of the basic blocks
+// that are created using print (ie, similar to dump()).
+// These classes respect the filtering of passes and functions using
+// -filter-passes and -filter-print-funcs.
+//
+// Information that needs to be saved for a basic block in order to compare
+// before and after the pass to determine if it was changed by a pass.
+class ChangedBlockData {
+public:
+  ChangedBlockData(const BasicBlock &B);
+
+  bool operator==(const ChangedBlockData &That) const {
+    return Body == That.Body;
+  }
+  bool operator!=(const ChangedBlockData &That) const {
+    return Body != That.Body;
+  }
+
+  // Return the label of the represented basic block.
+  StringRef getLabel() const { return Label; }
+  // Return the string representation of the basic block.
+  StringRef getBody() const { return Body; }
+
+protected:
+  std::string Label;
+  std::string Body;
+};
+
+template <typename IRData> class OrderedChangedData {
+public:
+  // Return the names in the order they were saved
+  std::vector<std::string> &getOrder() { return Order; }
+  const std::vector<std::string> &getOrder() const { return Order; }
+
+  // Return a map of names to saved representations
+  StringMap<IRData> &getData() { return Data; }
+  const StringMap<IRData> &getData() const { return Data; }
+
+  bool operator==(const OrderedChangedData<IRData> &That) const {
+    return Data == That.getData();
+  }
+
+  // Call the lambda \p HandlePair on each corresponding pair of data from
+  // \p Before and \p After.  The order is based on the order in \p After
+  // with ones that are only in \p Before interspersed based on where they
+  // occur in \p Before.  This is used to present the output in an order
+  // based on how the data is ordered in LLVM.
+  static void
+  report(const OrderedChangedData &Before, const OrderedChangedData &After,
+         function_ref<void(const IRData *, const IRData *)> HandlePair);
+
+protected:
+  std::vector<std::string> Order;
+  StringMap<IRData> Data;
+};
+
+// The data saved for comparing functions.
+using ChangedFuncData = OrderedChangedData<ChangedBlockData>;
+
+// A map of names to the saved data.
+using ChangedIRData = OrderedChangedData<ChangedFuncData>;
+
+// A class that compares two IRs and does a 
diff  between them.  The
+// added lines are prefixed with a '+', the removed lines are prefixed
+// with a '-' and unchanged lines are prefixed with a space (to have
+// things line up).
+class ChangedIRComparer {
+public:
+  ChangedIRComparer(raw_ostream &OS, const ChangedIRData &Before,
+                    const ChangedIRData &After)
+      : Before(Before), After(After), Out(OS) {}
+
+  // Compare the 2 IRs.
+  void compare(Any IR, StringRef Prefix, StringRef PassID, StringRef Name);
+
+  // Analyze \p IR and build the IR representation in \p Data.
+  static void analyzeIR(Any IR, ChangedIRData &Data);
+
+protected:
+  // Return the module when that is the appropriate level of
+  // comparison for \p IR.
+  static const Module *getModuleForComparison(Any IR);
+
+  // Generate the data for \p F into \p Data.
+  static bool generateFunctionData(ChangedIRData &Data, const Function &F);
+
+  // Called to handle the compare of a function. When \p InModule is set,
+  // this function is being handled as part of comparing a module.
+  void handleFunctionCompare(StringRef Name, StringRef Prefix, StringRef PassID,
+                             bool InModule, const ChangedFuncData &Before,
+                             const ChangedFuncData &After);
+
+  const ChangedIRData &Before;
+  const ChangedIRData &After;
+  raw_ostream &Out;
+};
+
+// A change printer that prints out in-line 
diff erences in the basic
+// blocks.  It uses an InlineComparer to do the comparison so it shows
+// the 
diff erences prefixed with '-' and '+' for code that is removed
+// and added, respectively.  Changes to the IR that do not affect basic
+// blocks are not reported as having changed the IR.  The option
+// -print-module-scope does not affect this change reporter.
+class InLineChangePrinter : public TextChangeReporter<ChangedIRData> {
+public:
+  InLineChangePrinter(bool VerboseMode)
+      : TextChangeReporter<ChangedIRData>(VerboseMode) {}
+  ~InLineChangePrinter() override;
+  void registerCallbacks(PassInstrumentationCallbacks &PIC);
+
+protected:
+  // Create a representation of the IR.
+  virtual void generateIRRepresentation(Any IR, StringRef PassID,
+                                        ChangedIRData &Output) override;
+
+  // Called when an interesting IR has changed.
+  virtual void handleAfter(StringRef PassID, std::string &Name,
+                           const ChangedIRData &Before,
+                           const ChangedIRData &After, Any) override;
+  // Called to compare the before and after representations of the IR.
+  virtual bool same(const ChangedIRData &Before,
+                    const ChangedIRData &After) override;
+};
+
 class VerifyInstrumentation {
   bool DebugLogging;
 
@@ -275,6 +401,7 @@ class StandardInstrumentations {
   PreservedCFGCheckerInstrumentation PreservedCFGChecker;
   IRChangedPrinter PrintChangedIR;
   PseudoProbeVerifier PseudoProbeVerification;
+  InLineChangePrinter PrintChangedDiff;
   VerifyInstrumentation Verify;
 
   bool VerifyEach;
@@ -290,6 +417,9 @@ class StandardInstrumentations {
 extern template class ChangeReporter<std::string>;
 extern template class TextChangeReporter<std::string>;
 
+extern template class ChangeReporter<ChangedIRData>;
+extern template class TextChangeReporter<ChangedIRData>;
+
 } // namespace llvm
 
 #endif

diff  --git a/llvm/lib/Passes/StandardInstrumentations.cpp b/llvm/lib/Passes/StandardInstrumentations.cpp
index 6795aed7b04e..86aaab5a8156 100644
--- a/llvm/lib/Passes/StandardInstrumentations.cpp
+++ b/llvm/lib/Passes/StandardInstrumentations.cpp
@@ -27,6 +27,8 @@
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Program.h"
 #include "llvm/Support/raw_ostream.h"
 #include <unordered_set>
 #include <vector>
@@ -66,14 +68,33 @@ static cl::opt<bool>
 // reported as filtered out.  The -print-before-changed option will print
 // the IR as it was before each pass that changed it.  The optional
 // value of quiet will only report when the IR changes, suppressing
-// all other messages, including the initial IR.
-enum ChangePrinter { NoChangePrinter, PrintChangedVerbose, PrintChangedQuiet };
+// all other messages, including the initial IR.  The values "
diff " and
+// "
diff -quiet" will present the changes in a form similar to a patch, in
+// either verbose or quiet mode, respectively.  The lines that are removed
+// and added are prefixed with '-' and '+', respectively.  The
+// -filter-print-funcs and -filter-passes can be used to filter the output.
+// This reporter relies on the linux 
diff  utility to do comparisons and
+// insert the prefixes.  For systems that do not have the necessary
+// facilities, the error message will be shown in place of the expected output.
+//
+enum class ChangePrinter {
+  NoChangePrinter,
+  PrintChangedVerbose,
+  PrintChangedQuiet,
+  PrintChangedDiffVerbose,
+  PrintChangedDiffQuiet
+};
 static cl::opt<ChangePrinter> PrintChanged(
     "print-changed", cl::desc("Print changed IRs"), cl::Hidden,
-    cl::ValueOptional, cl::init(NoChangePrinter),
-    cl::values(clEnumValN(PrintChangedQuiet, "quiet", "Run in quiet mode"),
+    cl::ValueOptional, cl::init(ChangePrinter::NoChangePrinter),
+    cl::values(clEnumValN(ChangePrinter::PrintChangedQuiet, "quiet",
+                          "Run in quiet mode"),
+               clEnumValN(ChangePrinter::PrintChangedDiffVerbose, "
diff ",
+                          "Display patch-like changes"),
+               clEnumValN(ChangePrinter::PrintChangedDiffQuiet, "
diff -quiet",
+                          "Display patch-like changes in quiet mode"),
                // Sentinel value for unspecified option.
-               clEnumValN(PrintChangedVerbose, "", "")));
+               clEnumValN(ChangePrinter::PrintChangedVerbose, "", "")));
 
 // An option that supports the -print-changed option.  See
 // the description for -print-changed for an explanation of the use
@@ -91,8 +112,79 @@ static cl::opt<bool>
                        cl::desc("Print before passes that change them"),
                        cl::init(false), cl::Hidden);
 
+// An option for specifying the 
diff  used by print-changed=[
diff  | 
diff -quiet]
+static cl::opt<std::string>
+    DiffBinary("print-changed-
diff -path", cl::Hidden, cl::init("
diff "),
+               cl::desc("system 
diff  used by change reporters"));
+
 namespace {
 
+// Perform a system based 
diff  between \p Before and \p After, using
+// \p OldLineFormat, \p NewLineFormat, and \p UnchangedLineFormat
+// to control the formatting of the output.  Return an error message
+// for any failures instead of the 
diff .
+std::string doSystemDiff(StringRef Before, StringRef After,
+                         StringRef OldLineFormat, StringRef NewLineFormat,
+                         StringRef UnchangedLineFormat) {
+  StringRef SR[2]{Before, After};
+  // Store the 2 bodies into temporary files and call 
diff  on them
+  // to get the body of the node.
+  const unsigned NumFiles = 3;
+  std::string FileName[NumFiles];
+  int FD[NumFiles]{-1, -1, -1};
+  for (unsigned I = 0; I < NumFiles; ++I) {
+    if (FD[I] == -1) {
+      SmallVector<char, 200> SV;
+      std::error_code EC =
+          sys::fs::createTemporaryFile("tmp
diff ", "txt", FD[I], SV);
+      if (EC)
+        return "Unable to create temporary file.";
+      FileName[I] = Twine(SV).str();
+    }
+    // The third file is used as the result of the 
diff .
+    if (I == NumFiles - 1)
+      break;
+
+    std::error_code EC = sys::fs::openFileForWrite(FileName[I], FD[I]);
+    if (EC)
+      return "Unable to open temporary file for writing.";
+
+    raw_fd_ostream OutStream(FD[I], /*shouldClose=*/true);
+    if (FD[I] == -1)
+      return "Error opening file for writing.";
+    OutStream << SR[I];
+  }
+
+  static ErrorOr<std::string> DiffExe = sys::findProgramByName(DiffBinary);
+  if (!DiffExe)
+    return "Unable to find 
diff  executable.";
+
+  SmallString<128> OLF = formatv("--old-line-format={0}", OldLineFormat);
+  SmallString<128> NLF = formatv("--new-line-format={0}", NewLineFormat);
+  SmallString<128> ULF =
+      formatv("--unchanged-line-format={0}", UnchangedLineFormat);
+
+  StringRef Args[] = {"-w", "-d", OLF, NLF, ULF, FileName[0], FileName[1]};
+  Optional<StringRef> Redirects[] = {None, StringRef(FileName[2]), None};
+  int Result = sys::ExecuteAndWait(*DiffExe, Args, None, Redirects);
+  if (Result < 0)
+    return "Error executing system 
diff .";
+  std::string Diff;
+  auto B = MemoryBuffer::getFile(FileName[2]);
+  if (B && *B)
+    Diff = (*B)->getBuffer().str();
+  else
+    return "Unable to read result.";
+
+  // Clean up.
+  for (unsigned I = 0; I < NumFiles; ++I) {
+    std::error_code EC = sys::fs::remove(FileName[I]);
+    if (EC)
+      return "Unable to remove temporary file.";
+  }
+  return Diff;
+}
+
 /// 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>>
@@ -371,6 +463,12 @@ void ChangeReporter<IRUnitT>::registerRequiredCallbacks(
       });
 }
 
+ChangedBlockData::ChangedBlockData(const BasicBlock &B)
+    : Label(B.getName().str()) {
+  raw_string_ostream SS(Body);
+  B.print(SS, nullptr, true, true);
+}
+
 template <typename IRUnitT>
 TextChangeReporter<IRUnitT>::TextChangeReporter(bool Verbose)
     : ChangeReporter<IRUnitT>(Verbose), Out(dbgs()) {}
@@ -415,7 +513,8 @@ void TextChangeReporter<IRUnitT>::handleIgnored(StringRef PassID,
 IRChangedPrinter::~IRChangedPrinter() {}
 
 void IRChangedPrinter::registerCallbacks(PassInstrumentationCallbacks &PIC) {
-  if (PrintChanged != NoChangePrinter)
+  if (PrintChanged == ChangePrinter::PrintChangedVerbose ||
+      PrintChanged == ChangePrinter::PrintChangedQuiet)
     TextChangeReporter<std::string>::registerRequiredCallbacks(PIC);
 }
 
@@ -464,6 +563,145 @@ bool IRChangedPrinter::same(const std::string &S1, const std::string &S2) {
   return S1 == S2;
 }
 
+template <typename IRData>
+void OrderedChangedData<IRData>::report(
+    const OrderedChangedData &Before, const OrderedChangedData &After,
+    function_ref<void(const IRData *, const IRData *)> HandlePair) {
+  const auto &BFD = Before.getData();
+  const auto &AFD = After.getData();
+  std::vector<std::string>::const_iterator BI = Before.getOrder().begin();
+  std::vector<std::string>::const_iterator BE = Before.getOrder().end();
+  std::vector<std::string>::const_iterator AI = After.getOrder().begin();
+  std::vector<std::string>::const_iterator AE = After.getOrder().end();
+
+  auto handlePotentiallyRemovedIRData = [&](std::string S) {
+    // The order in LLVM may have changed so check if still exists.
+    if (!AFD.count(S)) {
+      // This has been removed.
+      HandlePair(&BFD.find(*BI)->getValue(), nullptr);
+    }
+  };
+  auto handleNewIRData = [&](std::vector<const IRData *> &Q) {
+    // Print out any queued up new sections
+    for (const IRData *NBI : Q)
+      HandlePair(nullptr, NBI);
+    Q.clear();
+  };
+
+  // Print out the IRData in the after order, with before ones interspersed
+  // appropriately (ie, somewhere near where they were in the before list).
+  // Start at the beginning of both lists.  Loop through the
+  // after list.  If an element is common, then advance in the before list
+  // reporting the removed ones until the common one is reached.  Report any
+  // queued up new ones and then report the common one.  If an element is not
+  // common, then enqueue it for reporting.  When the after list is exhausted,
+  // loop through the before list, reporting any removed ones.  Finally,
+  // report the rest of the enqueued new ones.
+  std::vector<const IRData *> NewIRDataQueue;
+  while (AI != AE) {
+    if (!BFD.count(*AI)) {
+      // This section is new so place it in the queue.  This will cause it
+      // to be reported after deleted sections.
+      NewIRDataQueue.emplace_back(&AFD.find(*AI)->getValue());
+      ++AI;
+      continue;
+    }
+    // This section is in both; advance and print out any before-only
+    // until we get to it.
+    while (*BI != *AI) {
+      handlePotentiallyRemovedIRData(*BI);
+      ++BI;
+    }
+    // Report any new sections that were queued up and waiting.
+    handleNewIRData(NewIRDataQueue);
+
+    const IRData &AData = AFD.find(*AI)->getValue();
+    const IRData &BData = BFD.find(*AI)->getValue();
+    HandlePair(&BData, &AData);
+    ++BI;
+    ++AI;
+  }
+
+  // Check any remaining before sections to see if they have been removed
+  while (BI != BE) {
+    handlePotentiallyRemovedIRData(*BI);
+    ++BI;
+  }
+
+  handleNewIRData(NewIRDataQueue);
+}
+
+void ChangedIRComparer::compare(Any IR, StringRef Prefix, StringRef PassID,
+                                StringRef Name) {
+  if (!getModuleForComparison(IR)) {
+    // Not a module so just handle the single function.
+    assert(Before.getData().size() == 1 && "Expected only one function.");
+    assert(After.getData().size() == 1 && "Expected only one function.");
+    handleFunctionCompare(Name, Prefix, PassID, false,
+                          Before.getData().begin()->getValue(),
+                          After.getData().begin()->getValue());
+    return;
+  }
+
+  ChangedIRData::report(
+      Before, After, [&](const ChangedFuncData *B, const ChangedFuncData *A) {
+        ChangedFuncData Missing;
+        if (!B)
+          B = &Missing;
+        else if (!A)
+          A = &Missing;
+        assert(B != &Missing && A != &Missing &&
+               "Both functions cannot be missing.");
+        handleFunctionCompare(Name, Prefix, PassID, true, *B, *A);
+      });
+}
+
+void ChangedIRComparer::analyzeIR(Any IR, ChangedIRData &Data) {
+  if (const Module *M = getModuleForComparison(IR)) {
+    // Create data for each existing/interesting function in the module.
+    for (const Function &F : *M)
+      generateFunctionData(Data, F);
+    return;
+  }
+
+  const Function *F = nullptr;
+  if (any_isa<const Function *>(IR))
+    F = any_cast<const Function *>(IR);
+  else {
+    assert(any_isa<const Loop *>(IR) && "Unknown IR unit.");
+    const Loop *L = any_cast<const Loop *>(IR);
+    F = L->getHeader()->getParent();
+  }
+  assert(F && "Unknown IR unit.");
+  generateFunctionData(Data, *F);
+}
+
+const Module *ChangedIRComparer::getModuleForComparison(Any IR) {
+  if (any_isa<const Module *>(IR))
+    return any_cast<const Module *>(IR);
+  if (any_isa<const LazyCallGraph::SCC *>(IR))
+    return any_cast<const LazyCallGraph::SCC *>(IR)
+        ->begin()
+        ->getFunction()
+        .getParent();
+  return nullptr;
+}
+
+bool ChangedIRComparer::generateFunctionData(ChangedIRData &Data,
+                                             const Function &F) {
+  if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) {
+    ChangedFuncData CFD;
+    for (const auto &B : F) {
+      CFD.getOrder().emplace_back(B.getName());
+      CFD.getData().insert({B.getName(), B});
+    }
+    Data.getOrder().emplace_back(F.getName());
+    Data.getData().insert({F.getName(), CFD});
+    return true;
+  }
+  return false;
+}
+
 PrintIRInstrumentation::~PrintIRInstrumentation() {
   assert(ModuleDescStack.empty() && "ModuleDescStack is not empty at exit");
 }
@@ -867,11 +1105,61 @@ void VerifyInstrumentation::registerCallbacks(
       });
 }
 
+InLineChangePrinter::~InLineChangePrinter() {}
+
+void InLineChangePrinter::generateIRRepresentation(Any IR, StringRef PassID,
+                                                   ChangedIRData &D) {
+  ChangedIRComparer::analyzeIR(IR, D);
+}
+
+void InLineChangePrinter::handleAfter(StringRef PassID, std::string &Name,
+                                      const ChangedIRData &Before,
+                                      const ChangedIRData &After, Any IR) {
+  if (Name == "")
+    Name = " (module)";
+  SmallString<20> Banner =
+      formatv("*** IR Dump After {0} ***{1}\n", PassID, Name);
+  Out << Banner;
+  ChangedIRComparer(Out, Before, After).compare(IR, "", PassID, Name);
+  Out << "\n";
+}
+
+bool InLineChangePrinter::same(const ChangedIRData &D1,
+                               const ChangedIRData &D2) {
+  return D1 == D2;
+}
+
+void ChangedIRComparer::handleFunctionCompare(StringRef Name, StringRef Prefix,
+                                              StringRef PassID, bool InModule,
+                                              const ChangedFuncData &Before,
+                                              const ChangedFuncData &After) {
+  // Print a banner when this is being shown in the context of a module
+  if (InModule)
+    Out << "\n*** IR for function " << Name << " ***\n";
+
+  ChangedFuncData::report(
+      Before, After, [&](const ChangedBlockData *B, const ChangedBlockData *A) {
+        StringRef BStr = B ? B->getBody() : "\n";
+        StringRef AStr = A ? A->getBody() : "\n";
+        const std::string Removed = "\033[31m-%l\033[0m\n";
+        const std::string Added = "\033[32m+%l\033[0m\n";
+        const std::string NoChange = " %l\n";
+        Out << doSystemDiff(BStr, AStr, Removed, Added, NoChange);
+      });
+}
+
+void InLineChangePrinter::registerCallbacks(PassInstrumentationCallbacks &PIC) {
+  if (PrintChanged == ChangePrinter::PrintChangedDiffVerbose ||
+      PrintChanged == ChangePrinter::PrintChangedDiffQuiet)
+    TextChangeReporter<ChangedIRData>::registerRequiredCallbacks(PIC);
+}
+
 StandardInstrumentations::StandardInstrumentations(bool DebugLogging,
                                                    bool VerifyEach)
     : PrintPass(DebugLogging), OptNone(DebugLogging),
-      PrintChangedIR(PrintChanged != PrintChangedQuiet), Verify(DebugLogging),
-      VerifyEach(VerifyEach) {}
+      PrintChangedIR(PrintChanged == ChangePrinter::PrintChangedVerbose),
+      PrintChangedDiff(PrintChanged == ChangePrinter::PrintChangedDiffVerbose),
+      Verify(DebugLogging), VerifyEach(VerifyEach) {}
 
 void StandardInstrumentations::registerCallbacks(
     PassInstrumentationCallbacks &PIC) {
@@ -885,6 +1173,7 @@ void StandardInstrumentations::registerCallbacks(
   PseudoProbeVerification.registerCallbacks(PIC);
   if (VerifyEach)
     Verify.registerCallbacks(PIC);
+  PrintChangedDiff.registerCallbacks(PIC);
 }
 
 namespace llvm {
@@ -892,4 +1181,7 @@ namespace llvm {
 template class ChangeReporter<std::string>;
 template class TextChangeReporter<std::string>;
 
+template class ChangeReporter<ChangedIRData>;
+template class TextChangeReporter<ChangedIRData>;
+
 } // namespace llvm

diff  --git a/llvm/test/Other/ChangePrinters/lit.local.cfg b/llvm/test/Other/ChangePrinters/lit.local.cfg
new file mode 100644
index 000000000000..95046e4f0039
--- /dev/null
+++ b/llvm/test/Other/ChangePrinters/lit.local.cfg
@@ -0,0 +1,16 @@
+import os
+import subprocess
+
+def have_needed_
diff _support():
+    if not os.path.exists('/usr/bin/
diff '):
+        return False
+
+    ld_cmd = subprocess.Popen(
+        ['/usr/bin/
diff ', '--help'], stdout=subprocess.PIPE, env={'LANG': 'C'})
+    ld_out = ld_cmd.stdout.read().decode()
+    ld_cmd.wait()
+
+    return '-line-format' in ld_out
+
+if not have_needed_
diff _support():
+  config.unsupported = True

diff  --git a/llvm/test/Other/ChangePrinters/print-changed-
diff .ll b/llvm/test/Other/ChangePrinters/print-changed-
diff .ll
new file mode 100644
index 000000000000..45322c29508e
--- /dev/null
+++ b/llvm/test/Other/ChangePrinters/print-changed-
diff .ll
@@ -0,0 +1,288 @@
+; Simple checks of -print-changed=
diff 
+;
+; Note that (mostly) only the banners are checked.
+;
+; Simple functionality check.
+; RUN: opt -S -print-changed=
diff  -passes=instsimplify 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-DIFF-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=
diff  -passes=instsimplify -filter-print-funcs=f  2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-DIFF-FUNC-FILTER
+;
+; Check that the reporting of IRs respects is not affected by
+; -print-module-scope
+; RUN: opt -S -print-changed=
diff  -passes=instsimplify -print-module-scope 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-DIFF-PRINT-MOD-SCOPE
+;
+; Check that reporting of multiple functions happens
+; RUN: opt -S -print-changed=
diff  -passes=instsimplify -filter-print-funcs="f,g" 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-DIFF-FILTER-MULT-FUNC
+;
+; Check that the reporting of IRs respects -filter-passes
+; RUN: opt -S -print-changed=
diff  -passes="instsimplify,no-op-function" -filter-passes="NoOpFunctionPass" 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-DIFF-FILTER-PASSES
+;
+; Check that the reporting of IRs respects -filter-passes with multiple passes
+; RUN: opt -S -print-changed=
diff  -passes="instsimplify,no-op-function" -filter-passes="NoOpFunctionPass,InstSimplifyPass" 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-DIFF-FILTER-MULT-PASSES
+;
+; Check that the reporting of IRs respects both -filter-passes and -filter-print-funcs
+; RUN: opt -S -print-changed=
diff  -passes="instsimplify,no-op-function" -filter-passes="NoOpFunctionPass,InstSimplifyPass" -filter-print-funcs=f 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-DIFF-FILTER-FUNC-PASSES
+;
+; Check that repeated passes that change the IR are printed and that the
+; others (including g) are filtered out.  Note that only the first time
+; instsimplify is run on f will result in changes
+; RUN: opt -S -print-changed=
diff  -passes="instsimplify,instsimplify" -filter-print-funcs=f  2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-DIFF-MULT-PASSES-FILTER-FUNC
+;
+; Simple checks of -print-changed=
diff -quiet
+;
+; Note that (mostly) only the banners are checked.
+;
+; Simple functionality check.
+; RUN: opt -S -print-changed=
diff -quiet -passes=instsimplify 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-DIFF-QUIET-SIMPLE --allow-empty
+;
+; 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=
diff -quiet -passes=instsimplify -filter-print-funcs=f  2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-DIFF-QUIET-FUNC-FILTER
+;
+; Check that the reporting of IRs respects is not affected by
+; -print-module-scope
+; RUN: opt -S -print-changed=
diff -quiet -passes=instsimplify -print-module-scope 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-DIFF-QUIET-PRINT-MOD-SCOPE
+;
+; Check that reporting of multiple functions happens
+; RUN: opt -S -print-changed=
diff -quiet -passes=instsimplify -filter-print-funcs="f,g" 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-DIFF-QUIET-FILTER-MULT-FUNC
+;
+; Check that the reporting of IRs respects -filter-passes
+; RUN: opt -S -print-changed=
diff -quiet -passes="instsimplify,no-op-function" -filter-passes="NoOpFunctionPass" 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-DIFF-QUIET-FILTER-PASSES-NONE --allow-empty
+;
+; Check that the reporting of IRs respects -filter-passes with multiple passes
+; RUN: opt -S -print-changed=
diff -quiet -passes="instsimplify,no-op-function" -filter-passes="NoOpFunctionPass,InstSimplifyPass" 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-DIFF-QUIET-FILTER-MULT-PASSES
+;
+; Check that the reporting of IRs respects both -filter-passes and -filter-print-funcs
+; RUN: opt -S -print-changed=
diff -quiet -passes="instsimplify,no-op-function" -filter-passes="NoOpFunctionPass,InstSimplifyPass" -filter-print-funcs=f 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-DIFF-QUIET-FILTER-FUNC-PASSES
+;
+; Check that repeated passes that change the IR are printed and that the
+; others (including g) are filtered out.  Note that only the first time
+; instsimplify is run on f will result in changes
+; RUN: opt -S -print-changed=
diff -quiet -passes="instsimplify,instsimplify" -filter-print-funcs=f  2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-DIFF-QUIET-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-DIFF-SIMPLE: *** IR Dump At Start: ***
+; CHECK-DIFF-SIMPLE: ModuleID = {{.+}}
+; CHECK-DIFF-SIMPLE: *** IR Dump After VerifierPass (module) omitted because no change ***
+; CHECK-DIFF-SIMPLE: *** IR Dump After InstSimplifyPass *** (function: g)
+; CHECK-DIFF-SIMPLE-NOT: ModuleID = {{.+}}
+; CHECK-DIFF-SIMPLE-NOT: *** IR{{.*}}
+; CHECK-DIFF-SIMPLE: entry:
+; CHECK-DIFF-SIMPLE-NEXT:-  %a = add i32 2, 3
+; CHECK-DIFF-SIMPLE-NEXT:-  ret i32 %a
+; CHECK-DIFF-SIMPLE-NEXT:+  ret i32 5
+; CHECK-DIFF-SIMPLE: *** IR Pass PassManager{{.*}} (function: g) ignored ***
+; CHECK-DIFF-SIMPLE: *** IR Dump After InstSimplifyPass *** (function: f)
+; CHECK-DIFF-SIMPLE-NOT: ModuleID = {{.+}}
+; CHECK-DIFF-SIMPLE-NOT: *** IR{{.*}}
+; CHECK-DIFF-SIMPLE: entry:
+; CHECK-DIFF-SIMPLE-NEXT:-  %a = add i32 2, 3
+; CHECK-DIFF-SIMPLE-NEXT:-  ret i32 %a
+; CHECK-DIFF-SIMPLE-NEXT:+  ret i32 5
+; CHECK-DIFF-SIMPLE: *** IR Pass PassManager{{.*}} (function: f) ignored ***
+; CHECK-DIFF-SIMPLE: *** IR Pass ModuleToFunctionPassAdaptor (module) ignored ***
+; CHECK-DIFF-SIMPLE: *** IR Dump After VerifierPass (module) omitted because no change ***
+; CHECK-DIFF-SIMPLE: *** IR Dump After PrintModulePass (module) omitted because no change ***
+
+; CHECK-DIFF-FUNC-FILTER: *** IR Dump At Start: ***
+; CHECK-DIFF-FUNC-FILTER-NEXT: ; ModuleID = {{.+}}
+; CHECK-DIFF-FUNC-FILTER: *** IR Dump After InstSimplifyPass (function: g) filtered out ***
+; CHECK-DIFF-FUNC-FILTER: *** IR Dump After InstSimplifyPass *** (function: f)
+; CHECK-DIFF-FUNC-FILTER-NOT: ModuleID = {{.+}}
+; CHECK-DIFF-FUNC-FILTER: entry:
+; CHECK-DIFF-FUNC-FILTER:-  %a = add i32 2, 3
+; CHECK-DIFF-FUNC-FILTER:-  ret i32 %a
+; CHECK-DIFF-FUNC-FILTER:+  ret i32 5
+; CHECK-DIFF-FUNC-FILTER: *** IR Pass PassManager{{.*}} (function: f) ignored ***
+; CHECK-DIFF-FUNC-FILTER: *** IR Pass ModuleToFunctionPassAdaptor (module) ignored ***
+; CHECK-DIFF-FUNC-FILTER: *** IR Dump After VerifierPass (module) omitted because no change ***
+; CHECK-DIFF-FUNC-FILTER: *** IR Dump After PrintModulePass (module) omitted because no change ***
+
+; CHECK-DIFF-PRINT-MOD-SCOPE: *** IR Dump At Start: ***
+; CHECK-DIFF-PRINT-MOD-SCOPE: ModuleID = {{.+}}
+; CHECK-DIFF-PRINT-MOD-SCOPE: *** IR Dump After InstSimplifyPass *** (function: g)
+; CHECK-DIFF-PRINT-MOD-SCOPE-NOT: ModuleID = {{.+}}
+; CHECK-DIFF-PRINT-MOD-SCOPE: entry:
+; CHECK-DIFF-PRINT-MOD-SCOPE:-  %a = add i32 2, 3
+; CHECK-DIFF-PRINT-MOD-SCOPE:-  ret i32 %a
+; CHECK-DIFF-PRINT-MOD-SCOPE:+  ret i32 5
+; CHECK-DIFF-PRINT-MOD-SCOPE: *** IR Dump After InstSimplifyPass *** (function: f)
+; CHECK-DIFF-PRINT-MOD-SCOPE-NOT: ModuleID = {{.+}}
+; CHECK-DIFF-PRINT-MOD-SCOPE: entry:
+; CHECK-DIFF-PRINT-MOD-SCOPE:-  %a = add i32 2, 3
+; CHECK-DIFF-PRINT-MOD-SCOPE:-  ret i32 %a
+; CHECK-DIFF-PRINT-MOD-SCOPE:+  ret i32 5
+; CHECK-DIFF-PRINT-MOD-SCOPE: *** IR Pass PassManager{{.*}} (function: f) ignored ***
+; CHECK-DIFF-PRINT-MOD-SCOPE: *** IR Pass ModuleToFunctionPassAdaptor (module) ignored ***
+; CHECK-DIFF-PRINT-MOD-SCOPE: *** IR Dump After VerifierPass (module) omitted because no change ***
+; CHECK-DIFF-PRINT-MOD-SCOPE: *** IR Dump After PrintModulePass (module) omitted because no change ***
+
+; CHECK-DIFF-FILTER-MULT-FUNC: *** IR Dump At Start: ***
+; CHECK-DIFF-FILTER-MULT-FUNC: *** IR Dump After InstSimplifyPass *** (function: g)
+; CHECK-DIFF-FILTER-MULT-FUNC-NOT: ModuleID = {{.+}}
+; CHECK-DIFF-FILTER-MULT-FUNC: entry:
+; CHECK-DIFF-FILTER-MULT-FUNC:-  %a = add i32 2, 3
+; CHECK-DIFF-FILTER-MULT-FUNC:-  ret i32 %a
+; CHECK-DIFF-FILTER-MULT-FUNC:+  ret i32 5
+; CHECK-DIFF-FILTER-MULT-FUNC: *** IR Dump After InstSimplifyPass *** (function: f)
+; CHECK-DIFF-FILTER-MULT-FUNC-NOT: ModuleID = {{.+}}
+; CHECK-DIFF-FILTER-MULT-FUNC: entry:
+; CHECK-DIFF-FILTER-MULT-FUNC:-  %a = add i32 2, 3
+; CHECK-DIFF-FILTER-MULT-FUNC:-  ret i32 %a
+; CHECK-DIFF-FILTER-MULT-FUNC:+  ret i32 5
+; CHECK-DIFF-FILTER-MULT-FUNC: *** IR Pass PassManager{{.*}} (function: f) ignored ***
+; CHECK-DIFF-FILTER-MULT-FUNC: *** IR Pass ModuleToFunctionPassAdaptor (module) ignored ***
+; CHECK-DIFF-FILTER-MULT-FUNC: *** IR Dump After VerifierPass (module) omitted because no change ***
+; CHECK-DIFF-FILTER-MULT-FUNC: *** IR Dump After PrintModulePass (module) omitted because no change ***
+
+; CHECK-DIFF-FILTER-PASSES: *** IR Dump After InstSimplifyPass (function: g) filtered out ***
+; CHECK-DIFF-FILTER-PASSES: *** IR Dump At Start: *** (function: g)
+; CHECK-DIFF-FILTER-PASSES: *** IR Dump After NoOpFunctionPass (function: g) omitted because no change ***
+; CHECK-DIFF-FILTER-PASSES: *** IR Dump After InstSimplifyPass (function: f) filtered out ***
+; CHECK-DIFF-FILTER-PASSES: *** IR Dump After NoOpFunctionPass (function: f) omitted because no change ***
+
+; CHECK-DIFF-FILTER-MULT-PASSES: *** IR Dump At Start: *** (function: g)
+; CHECK-DIFF-FILTER-MULT-PASSES: *** IR Dump After InstSimplifyPass *** (function: g)
+; CHECK-DIFF-FILTER-MULT-PASSES-NOT: ModuleID = {{.+}}
+; CHECK-DIFF-FILTER-MULT-PASSES: entry:
+; CHECK-DIFF-FILTER-MULT-PASSES:-  %a = add i32 2, 3
+; CHECK-DIFF-FILTER-MULT-PASSES:-  ret i32 %a
+; CHECK-DIFF-FILTER-MULT-PASSES:+  ret i32 5
+; CHECK-DIFF-FILTER-MULT-PASSES: *** IR Dump After NoOpFunctionPass (function: g) omitted because no change ***
+; CHECK-DIFF-FILTER-MULT-PASSES: *** IR Dump After InstSimplifyPass *** (function: f)
+; CHECK-DIFF-FILTER-MULT-PASSES-NOT: ModuleID = {{.+}}
+; CHECK-DIFF-FILTER-MULT-PASSES: entry:
+; CHECK-DIFF-FILTER-MULT-PASSES:-  %a = add i32 2, 3
+; CHECK-DIFF-FILTER-MULT-PASSES:-  ret i32 %a
+; CHECK-DIFF-FILTER-MULT-PASSES:+  ret i32 5
+; CHECK-DIFF-FILTER-MULT-PASSES: *** IR Dump After NoOpFunctionPass (function: f) omitted because no change ***
+
+; CHECK-DIFF-FILTER-FUNC-PASSES: *** IR Dump After InstSimplifyPass (function: g) filtered out ***
+; CHECK-DIFF-FILTER-FUNC-PASSES: *** IR Dump After NoOpFunctionPass (function: g) filtered out ***
+; CHECK-DIFF-FILTER-FUNC-PASSES: *** IR Dump At Start: *** (function: f)
+; CHECK-DIFF-FILTER-FUNC-PASSES: *** IR Dump After InstSimplifyPass *** (function: f)
+; CHECK-DIFF-FILTER-FUNC-PASSES-NOT: ModuleID = {{.+}}
+; CHECK-DIFF-FILTER-FUNC-PASSES: entry:
+; CHECK-DIFF-FILTER-FUNC-PASSES:-  %a = add i32 2, 3
+; CHECK-DIFF-FILTER-FUNC-PASSES:-  ret i32 %a
+; CHECK-DIFF-FILTER-FUNC-PASSES:+  ret i32 5
+; CHECK-DIFF-FILTER-FUNC-PASSES: *** IR Dump After NoOpFunctionPass (function: f) omitted because no change ***
+
+; CHECK-DIFF-MULT-PASSES-FILTER-FUNC: *** IR Dump At Start: ***
+; CHECK-DIFF-MULT-PASSES-FILTER-FUNC: *** IR Dump After InstSimplifyPass (function: g) filtered out ***
+; CHECK-DIFF-MULT-PASSES-FILTER-FUNC: *** IR Dump After InstSimplifyPass (function: g) filtered out ***
+; CHECK-DIFF-MULT-PASSES-FILTER-FUNC: *** IR Dump After InstSimplifyPass *** (function: f)
+; CHECK-DIFF-MULT-PASSES-FILTER-FUNC-NOT: ModuleID = {{.+}}
+; CHECK-DIFF-MULT-PASSES-FILTER-FUNC: entry:
+; CHECK-DIFF-MULT-PASSES-FILTER-FUNC:-  %a = add i32 2, 3
+; CHECK-DIFF-MULT-PASSES-FILTER-FUNC:-  ret i32 %a
+; CHECK-DIFF-MULT-PASSES-FILTER-FUNC:+  ret i32 5
+; CHECK-DIFF-MULT-PASSES-FILTER-FUNC: *** IR Dump After InstSimplifyPass (function: f) omitted because no change ***
+
+; CHECK-DIFF-QUIET-SIMPLE-NOT: *** IR Dump {{.*(At Start:|no change|ignored|filtered out)}} ***
+; CHECK-DIFF-QUIET-SIMPLE: *** IR Dump After InstSimplifyPass *** (function: g)
+; CHECK-DIFF-QUIET-SIMPLE-NOT: ModuleID = {{.+}}
+; CHECK-DIFF-QUIET-SIMPLE-NOT: *** IR{{.*}}
+; CHECK-DIFF-QUIET-SIMPLE: entry:
+; CHECK-DIFF-QUIET-SIMPLE-NEXT:-  %a = add i32 2, 3
+; CHECK-DIFF-QUIET-SIMPLE-NEXT:-  ret i32 %a
+; CHECK-DIFF-QUIET-SIMPLE-NEXT:+  ret i32 5
+; CHECK-DIFF-QUIET-SIMPLE-EMPTY:
+; CHECK-DIFF-QUIET-SIMPLE-NEXT: *** IR Dump After InstSimplifyPass *** (function: f)
+; CHECK-DIFF-QUIET-SIMPLE-NOT: ModuleID = {{.+}}
+; CHECK-DIFF-QUIET-SIMPLE-NOT: *** IR{{.*}}
+; CHECK-DIFF-QUIET-SIMPLE: entry:
+; CHECK-DIFF-QUIET-SIMPLE-NEXT:-  %a = add i32 2, 3
+; CHECK-DIFF-QUIET-SIMPLE-NEXT:-  ret i32 %a
+; CHECK-DIFF-QUIET-SIMPLE-NEXT:+  ret i32 5
+; CHECK-DIFF-QUIET-SIMPLE-NOT: *** IR{{.*}}
+
+; CHECK-DIFF-QUIET-FUNC-FILTER-NOT: *** IR Dump {{.*(At Start:|no change|ignored|filtered out)}} ***
+; CHECK-DIFF-QUIET-FUNC-FILTER: *** IR Dump After InstSimplifyPass *** (function: f)
+; CHECK-DIFF-QUIET-FUNC-FILTER-NOT: ModuleID = {{.+}}
+; CHECK-DIFF-QUIET-FUNC-FILTER: entry:
+; CHECK-DIFF-QUIET-FUNC-FILTER:-  %a = add i32 2, 3
+; CHECK-DIFF-QUIET-FUNC-FILTER:-  ret i32 %a
+; CHECK-DIFF-QUIET-FUNC-FILTER:+  ret i32 5
+; CHECK-DIFF-QUIET-FUNC-FILTER-NOT: *** IR{{.*}}
+
+; CHECK-DIFF-QUIET-PRINT-MOD-SCOPE-NOT: *** IR Dump {{.*(At Start:|no change|ignored|filtered out)}} ***
+; CHECK-DIFF-QUIET-PRINT-MOD-SCOPE: *** IR Dump After InstSimplifyPass *** (function: g)
+; CHECK-DIFF-QUIET-PRINT-MOD-SCOPE-NOT: ModuleID = {{.+}}
+; CHECK-DIFF-QUIET-PRINT-MOD-SCOPE: entry:
+; CHECK-DIFF-QUIET-PRINT-MOD-SCOPE:-  %a = add i32 2, 3
+; CHECK-DIFF-QUIET-PRINT-MOD-SCOPE:-  ret i32 %a
+; CHECK-DIFF-QUIET-PRINT-MOD-SCOPE:+  ret i32 5
+; CHECK-DIFF-QUIET-PRINT-MOD-SCOPE-EMPTY:
+; CHECK-DIFF-QUIET-PRINT-MOD-SCOPE-NEXT: *** IR Dump After InstSimplifyPass *** (function: f)
+; CHECK-DIFF-QUIET-PRINT-MOD-SCOPE-NOT: ModuleID = {{.+}}
+; CHECK-DIFF-QUIET-PRINT-MOD-SCOPE: entry:
+; CHECK-DIFF-QUIET-PRINT-MOD-SCOPE:-  %a = add i32 2, 3
+; CHECK-DIFF-QUIET-PRINT-MOD-SCOPE:-  ret i32 %a
+; CHECK-DIFF-QUIET-PRINT-MOD-SCOPE:+  ret i32 5
+; CHECK-DIFF-QUIET-PRINT-MOD-SCOPE-NOT: *** IR{{.*}}
+
+; CHECK-DIFF-QUIET-FILTER-MULT-FUNC-NOT: *** IR Dump {{.*(At Start:|no change|ignored|filtered out)}} ***
+; CHECK-DIFF-QUIET-FILTER-MULT-FUNC: *** IR Dump After InstSimplifyPass *** (function: g)
+; CHECK-DIFF-QUIET-FILTER-MULT-FUNC-NOT: ModuleID = {{.+}}
+; CHECK-DIFF-QUIET-FILTER-MULT-FUNC: entry:
+; CHECK-DIFF-QUIET-FILTER-MULT-FUNC:-  %a = add i32 2, 3
+; CHECK-DIFF-QUIET-FILTER-MULT-FUNC:-  ret i32 %a
+; CHECK-DIFF-QUIET-FILTER-MULT-FUNC:+  ret i32 5
+; CHECK-DIFF-QUIET-FILTER-MULT-FUNC-EMPTY:
+; CHECK-DIFF-QUIET-FILTER-MULT-FUNC-NEXT: *** IR Dump After InstSimplifyPass *** (function: f)
+; CHECK-DIFF-QUIET-FILTER-MULT-FUNC-NOT: ModuleID = {{.+}}
+; CHECK-DIFF-QUIET-FILTER-MULT-FUNC: entry:
+; CHECK-DIFF-QUIET-FILTER-MULT-FUNC:-  %a = add i32 2, 3
+; CHECK-DIFF-QUIET-FILTER-MULT-FUNC:-  ret i32 %a
+; CHECK-DIFF-QUIET-FILTER-MULT-FUNC:+  ret i32 5
+; CHECK-DIFF-QUIET-FILTER-MULT-FUNC-NOT: *** IR{{.*}}
+
+; CHECK-DIFF-QUIET-FILTER-PASSES-NONE-NOT: *** IR
+
+; CHECK-DIFF-QUIET-FILTER-MULT-PASSES-NOT: *** IR Dump {{.*(At Start:|no change|ignored|filtered out)}} ***
+; CHECK-DIFF-QUIET-FILTER-MULT-PASSES: *** IR Dump After InstSimplifyPass *** (function: g)
+; CHECK-DIFF-QUIET-FILTER-MULT-PASSES-NOT: ModuleID = {{.+}}
+; CHECK-DIFF-QUIET-FILTER-MULT-PASSES: entry:
+; CHECK-DIFF-QUIET-FILTER-MULT-PASSES:-  %a = add i32 2, 3
+; CHECK-DIFF-QUIET-FILTER-MULT-PASSES:-  ret i32 %a
+; CHECK-DIFF-QUIET-FILTER-MULT-PASSES:+  ret i32 5
+; CHECK-DIFF-QUIET-FILTER-MULT-PASSES-EMPTY:
+; CHECK-DIFF-QUIET-FILTER-MULT-PASSES: *** IR Dump After InstSimplifyPass *** (function: f)
+; CHECK-DIFF-QUIET-FILTER-MULT-PASSES-NOT: ModuleID = {{.+}}
+; CHECK-DIFF-QUIET-FILTER-MULT-PASSES: entry:
+; CHECK-DIFF-QUIET-FILTER-MULT-PASSES:-  %a = add i32 2, 3
+; CHECK-DIFF-QUIET-FILTER-MULT-PASSES:-  ret i32 %a
+; CHECK-DIFF-QUIET-FILTER-MULT-PASSES:+  ret i32 5
+; CHECK-DIFF-QUIET-FILTER-MULT-PASSES-NOT: *** IR
+
+; CHECK-DIFF-QUIET-FILTER-FUNC-PASSES-NOT: *** IR Dump {{.*(At Start:|no change|ignored|filtered out)}} ***
+; CHECK-DIFF-QUIET-FILTER-FUNC-PASSES: *** IR Dump After InstSimplifyPass *** (function: f)
+; CHECK-DIFF-QUIET-FILTER-FUNC-PASSES-NOT: ModuleID = {{.+}}
+; CHECK-DIFF-QUIET-FILTER-FUNC-PASSES: entry:
+; CHECK-DIFF-QUIET-FILTER-FUNC-PASSES:-  %a = add i32 2, 3
+; CHECK-DIFF-QUIET-FILTER-FUNC-PASSES:-  ret i32 %a
+; CHECK-DIFF-QUIET-FILTER-FUNC-PASSES:+  ret i32 5
+; CHECK-DIFF-QUIET-FILTER-FUNC-PASSES-NOT: *** IR
+
+; CHECK-DIFF-QUIET-MULT-PASSES-FILTER-FUNC-NOT: *** IR Dump {{.*(At Start:|no change|ignored|filtered out)}} ***
+; CHECK-DIFF-QUIET-MULT-PASSES-FILTER-FUNC: *** IR Dump After InstSimplifyPass *** (function: f)
+; CHECK-DIFF-QUIET-MULT-PASSES-FILTER-FUNC-NOT: ModuleID = {{.+}}
+; CHECK-DIFF-QUIET-MULT-PASSES-FILTER-FUNC: entry:
+; CHECK-DIFF-QUIET-MULT-PASSES-FILTER-FUNC:-  %a = add i32 2, 3
+; CHECK-DIFF-QUIET-MULT-PASSES-FILTER-FUNC:-  ret i32 %a
+; CHECK-DIFF-QUIET-MULT-PASSES-FILTER-FUNC:+  ret i32 5
+; CHECK-DIFF-QUIET-MULT-PASSES-FILTER-FUNC-NOT: *** IR


        


More information about the llvm-commits mailing list