diff --git a/llvm/lib/Passes/StandardInstrumentations.cpp b/llvm/lib/Passes/StandardInstrumentations.cpp --- a/llvm/lib/Passes/StandardInstrumentations.cpp +++ b/llvm/lib/Passes/StandardInstrumentations.cpp @@ -96,11 +96,16 @@ cl::desc("Generate dot files into specified directory for changed IRs"), cl::Hidden, cl::init("./")); -// An option to print the IR that was being processed when a pass crashes. -static cl::opt - PrintCrashIR("print-on-crash", - cl::desc("Print the last form of the IR before crash"), - cl::Hidden); +// Options to print the IR that was being processed when a pass crashes. +static cl::opt PrintOnCrashPath( + "print-on-crash-path", + cl::desc("Print the last form of the IR before crash to a file"), + cl::Hidden); + +static cl::opt PrintOnCrash( + "print-on-crash", + cl::desc("Print the last form of the IR before crash (use -print-on-crash-path to dump to a file)"), + cl::Hidden); static cl::opt OptBisectPrintIRPath( "opt-bisect-print-ir-path", @@ -2186,7 +2191,17 @@ PrintCrashIRInstrumentation *PrintCrashIRInstrumentation::CrashReporter = nullptr; -void PrintCrashIRInstrumentation::reportCrashIR() { dbgs() << SavedIR; } +void PrintCrashIRInstrumentation::reportCrashIR() { + if (!PrintOnCrashPath.empty()) { + std::error_code EC; + raw_fd_ostream Out(PrintOnCrashPath, EC); + if (EC) + report_fatal_error(errorCodeToError(EC)); + Out << SavedIR; + } else { + dbgs() << SavedIR; + } +} void PrintCrashIRInstrumentation::SignalHandler(void *) { // Called by signal handlers so do not lock here @@ -2194,7 +2209,8 @@ if (!CrashReporter) return; - assert(PrintCrashIR && "Did not expect to get here without option set."); + assert((PrintOnCrash || !PrintOnCrashPath.empty()) && + "Did not expect to get here without option set."); CrashReporter->reportCrashIR(); } @@ -2202,31 +2218,32 @@ if (!CrashReporter) return; - assert(PrintCrashIR && "Did not expect to get here without option set."); + assert((PrintOnCrash || !PrintOnCrashPath.empty()) && + "Did not expect to get here without option set."); CrashReporter = nullptr; } void PrintCrashIRInstrumentation::registerCallbacks( PassInstrumentationCallbacks &PIC) { - if (!PrintCrashIR || CrashReporter) + if ((!PrintOnCrash && PrintOnCrashPath.empty()) || CrashReporter) return; sys::AddSignalHandler(SignalHandler, nullptr); CrashReporter = this; - PIC.registerBeforeNonSkippedPassCallback([&PIC, this](StringRef PassID, - Any IR) { - SavedIR.clear(); - raw_string_ostream OS(SavedIR); - OS << formatv("*** Dump of {0}IR Before Last Pass {1}", - llvm::forcePrintModuleIR() ? "Module " : "", PassID); - if (!isInteresting(IR, PassID, PIC.getPassNameForClassName(PassID))) { - OS << " Filtered Out ***\n"; - return; - } - OS << " Started ***\n"; - unwrapAndPrint(OS, IR); - }); + PIC.registerBeforeNonSkippedPassCallback( + [&PIC, this](StringRef PassID, Any IR) { + SavedIR.clear(); + raw_string_ostream OS(SavedIR); + OS << formatv("*** Dump of {0}IR Before Last Pass {1}", + llvm::forcePrintModuleIR() ? "Module " : "", PassID); + if (!isInteresting(IR, PassID, PIC.getPassNameForClassName(PassID))) { + OS << " Filtered Out ***\n"; + return; + } + OS << " Started ***\n"; + unwrapAndPrint(OS, IR); + }); } void StandardInstrumentations::registerCallbacks( diff --git a/llvm/test/Other/print-on-crash.ll b/llvm/test/Other/print-on-crash.ll --- a/llvm/test/Other/print-on-crash.ll +++ b/llvm/test/Other/print-on-crash.ll @@ -3,10 +3,13 @@ ; RUN: not --crash opt -print-on-crash -passes=trigger-crash < %s 2>&1 | FileCheck %s --check-prefix=CHECK_SIMPLE +; RUN: not --crash opt -print-on-crash-path=%t -passes=trigger-crash < %s +; RUN: FileCheck %s --check-prefix=CHECK_SIMPLE --input-file=%t + ; A test that the signal handler set by the hidden option -print-on-crash ; is not called when no pass crashes. -; RUN: opt -print-on-crash -passes="default" < %s 2>&1 | FileCheck %s --check-prefix=CHECK_NO_CRASH +; RUN: opt -disable-output -print-on-crash -passes="default" < %s 2>&1 | FileCheck %s --check-prefix=CHECK_NO_CRASH --allow-empty ; RUN: not --crash opt -print-on-crash -print-module-scope -passes=trigger-crash < %s 2>&1 | FileCheck %s --check-prefix=CHECK_MODULE