diff --git a/llvm/include/llvm/IR/PrintPasses.h b/llvm/include/llvm/IR/PrintPasses.h index e721db9993412..599820a1e3ef4 100644 --- a/llvm/include/llvm/IR/PrintPasses.h +++ b/llvm/include/llvm/IR/PrintPasses.h @@ -54,6 +54,14 @@ bool forcePrintModuleIR(); // Returns true if we should print the function. bool isFunctionInPrintList(StringRef FunctionName); +// 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); + } // namespace llvm #endif // LLVM_IR_PRINTPASSES_H diff --git a/llvm/lib/CodeGen/MachineFunctionPass.cpp b/llvm/lib/CodeGen/MachineFunctionPass.cpp index 477310f591122..c6f7393338e8e 100644 --- a/llvm/lib/CodeGen/MachineFunctionPass.cpp +++ b/llvm/lib/CodeGen/MachineFunctionPass.cpp @@ -120,8 +120,34 @@ bool MachineFunctionPass::runOnFunction(Function &F) { if (const PassInfo *PI = Pass::lookupPassInfo(getPassID())) Arg = PI->getPassArgument(); errs() << ("*** IR Dump After " + getPassName() + " (" + Arg + ") on " + - MF.getName() + " ***\n" + AfterStr); - } else if (PrintChanged == ChangePrinter::Verbose) { + MF.getName() + " ***\n"); + switch (PrintChanged) { + case ChangePrinter::None: + llvm_unreachable(""); + case ChangePrinter::Quiet: + case ChangePrinter::Verbose: + case ChangePrinter::DotCfgQuiet: // unimplemented + case ChangePrinter::DotCfgVerbose: // unimplemented + errs() << AfterStr; + break; + case ChangePrinter::DiffQuiet: + case ChangePrinter::DiffVerbose: + case ChangePrinter::ColourDiffQuiet: + case ChangePrinter::ColourDiffVerbose: { + bool Color = llvm::is_contained( + {ChangePrinter::ColourDiffQuiet, ChangePrinter::ColourDiffVerbose}, + PrintChanged.getValue()); + StringRef Removed = Color ? "\033[31m-%l\033[0m\n" : "-%l\n"; + StringRef Added = Color ? "\033[32m+%l\033[0m\n" : "+%l\n"; + StringRef NoChange = " %l\n"; + errs() << doSystemDiff(BeforeStr, AfterStr, Removed, Added, NoChange); + break; + } + } + } else if (llvm::is_contained({ChangePrinter::Verbose, + ChangePrinter::DiffVerbose, + ChangePrinter::ColourDiffVerbose}, + PrintChanged.getValue())) { errs() << ("*** IR Dump After " + getPassName() + " on " + MF.getName() + " omitted because no change ***\n"); } diff --git a/llvm/lib/IR/PrintPasses.cpp b/llvm/lib/IR/PrintPasses.cpp index fe2da5ca114f2..e7ecd7e3972fd 100644 --- a/llvm/lib/IR/PrintPasses.cpp +++ b/llvm/lib/IR/PrintPasses.cpp @@ -8,6 +8,9 @@ #include "llvm/IR/PrintPasses.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Program.h" #include using namespace llvm; @@ -73,6 +76,11 @@ cl::opt llvm::PrintChanged( // Sentinel value for unspecified option. clEnumValN(ChangePrinter::Verbose, "", ""))); +// An option for specifying the diff used by print-changed=[diff | diff-quiet] +static cl::opt + DiffBinary("print-changed-diff-path", cl::Hidden, cl::init("diff"), + cl::desc("system diff used by change reporters")); + static cl::opt PrintModuleScope("print-module-scope", cl::desc("When printing IR for print-[before|after]{-all} " @@ -130,3 +138,66 @@ bool llvm::isFunctionInPrintList(StringRef FunctionName) { return PrintFuncNames.empty() || PrintFuncNames.count(std::string(FunctionName)); } + +std::string llvm::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; + static std::string FileName[NumFiles]; + static int FD[NumFiles]{-1, -1, -1}; + for (unsigned I = 0; I < NumFiles; ++I) { + if (FD[I] == -1) { + SmallVector SV; + std::error_code EC = + sys::fs::createTemporaryFile("tmpdiff", "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 DiffExe = sys::findProgramByName(DiffBinary); + if (!DiffExe) + return "Unable to find diff executable."; + + SmallString<128> OLF, NLF, ULF; + ("--old-line-format=" + OldLineFormat).toVector(OLF); + ("--new-line-format=" + NewLineFormat).toVector(NLF); + ("--unchanged-line-format=" + UnchangedLineFormat).toVector(ULF); + + StringRef Args[] = {DiffBinary, "-w", "-d", OLF, + NLF, ULF, FileName[0], FileName[1]}; + Optional 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 (const std::string &I : FileName) { + std::error_code EC = sys::fs::remove(I); + if (EC) + return "Unable to remove temporary file."; + } + return Diff; +} diff --git a/llvm/lib/Passes/StandardInstrumentations.cpp b/llvm/lib/Passes/StandardInstrumentations.cpp index a0c63fb33369e..e6dab5f09a452 100644 --- a/llvm/lib/Passes/StandardInstrumentations.cpp +++ b/llvm/lib/Passes/StandardInstrumentations.cpp @@ -69,11 +69,6 @@ static cl::opt 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 - DiffBinary("print-changed-diff-path", cl::Hidden, cl::init("diff"), - cl::desc("system diff used by change reporters")); - // An option for specifying the dot used by // print-changed=[dot-cfg | dot-cfg-quiet] static cl::opt @@ -116,73 +111,6 @@ static cl::opt 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; - static std::string FileName[NumFiles]; - static int FD[NumFiles]{-1, -1, -1}; - for (unsigned I = 0; I < NumFiles; ++I) { - if (FD[I] == -1) { - SmallVector SV; - std::error_code EC = - sys::fs::createTemporaryFile("tmpdiff", "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 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[] = {DiffBinary, "-w", "-d", OLF, - NLF, ULF, FileName[0], FileName[1]}; - Optional 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 (const std::string &I : FileName) { - std::error_code EC = sys::fs::remove(I); - if (EC) - return "Unable to remove temporary file."; - } - return Diff; -} - /// Extract Module out of \p IR unit. May return nullptr if \p IR does not match /// certain global filters. Will never return nullptr if \p Force is true. const Module *unwrapModule(Any IR, bool Force = false) { diff --git a/llvm/test/Other/ChangePrinters/print-changed-diff-machine.ll b/llvm/test/Other/ChangePrinters/print-changed-diff-machine.ll new file mode 100644 index 0000000000000..3a4e3ef7ba9b5 --- /dev/null +++ b/llvm/test/Other/ChangePrinters/print-changed-diff-machine.ll @@ -0,0 +1,33 @@ +; REQUIRES: aarch64-registered-target +; RUN: llc -filetype=null -mtriple=aarch64 -O0 -print-changed=diff %s 2>&1 | FileCheck %s --check-prefixes=DIFF,VERBOSE +; RUN: llc -filetype=null -mtriple=aarch64 -O0 -print-changed=diff-quiet %s 2>&1 | FileCheck %s --check-prefixes=DIFF,QUIET +; RUN: llc -filetype=null -mtriple=aarch64 -O0 -print-changed=cdiff %s 2>&1 | FileCheck %s --check-prefixes=CDIFF,VERBOSE +; RUN: llc -filetype=null -mtriple=aarch64 -O0 -print-changed=cdiff-quiet %s 2>&1 | FileCheck %s --check-prefixes=CDIFF,QUIET + +; VERBOSE: *** IR Dump After AArch64O0PreLegalizerCombiner on foo omitted because no change *** +; QUIET-NOT: *** {{.*}} omitted because no change *** + +; DIFF: *** IR Dump After Legalizer (legalizer) on foo *** +; DIFF-NEXT: -# Machine code for function foo: IsSSA, TracksLiveness +; DIFF-NEXT: +# Machine code for function foo: IsSSA, TracksLiveness, Legalized +; DIFF-NEXT: Function Live Ins: $w0 + +; CDIFF: *** IR Dump After Legalizer (legalizer) on foo *** +; CDIFF-NEXT: {{.\[31m-}}# Machine code for function foo: IsSSA, TracksLiveness{{.\[0m}} +; CDIFF-NEXT: {{.\[32m\+}}# Machine code for function foo: IsSSA, TracksLiveness, Legalized{{.\[0m}} + +@var = global i32 0 + +define void @foo(i32 %a) { +entry: + %b = add i32 %a, 1 + store i32 %b, ptr @var + ret void +} + +define void @bar(i32 %a) { +entry: + %b = add i32 %a, 2 + store i32 %b, ptr @var + ret void +} diff --git a/llvm/test/Other/print-changed-machine.ll b/llvm/test/Other/print-changed-machine.ll index cb6a8b397dfa9..bd6f334696ff6 100644 --- a/llvm/test/Other/print-changed-machine.ll +++ b/llvm/test/Other/print-changed-machine.ll @@ -24,8 +24,8 @@ ; QUIET-NOT: *** ; QUIET: *** IR Dump After Legalizer (legalizer) on foo *** -;; Other modes are unimplemented. Currently they behave like 'quiet'. -; RUN: llc -filetype=null -mtriple=aarch64 -O0 -print-changed=diff %s 2>&1 | FileCheck %s --check-prefix=QUIET +;; dot-cfg/dot-cfg-quiet are unimplemented. Currently they behave like 'quiet'. +; RUN: llc -filetype=null -mtriple=aarch64 -O0 -print-changed=dot-cfg %s 2>&1 | FileCheck %s --check-prefix=QUIET @var = global i32 0