forked from OSchip/llvm-project
Add new hidden option -print-on-crash that prints out IR that caused opt pipeline to crash
A new hidden option -print-on-crash that prints the IR as it was upon entering the last pass when there is a crash. The IR is saved in its print form before each pass is started and a signal handler is registered. If the compilation crashes, the signal handler will print the saved IR to dbgs(). This option can be modified using -print-module-scope to get the IR for the complete module. Note that this option only works with the new pass manager. Reviewed By: yrouban Differential Revision: https://reviews.llvm.org/D86657
This commit is contained in:
parent
21c060c497
commit
24239e246c
|
@ -480,6 +480,25 @@ protected:
|
|||
std::unique_ptr<raw_fd_ostream> HTML;
|
||||
};
|
||||
|
||||
// Print IR on crash.
|
||||
class PrintCrashIRInstrumentation {
|
||||
public:
|
||||
PrintCrashIRInstrumentation()
|
||||
: SavedIR("*** Dump of IR Before Last Pass Unknown ***") {}
|
||||
~PrintCrashIRInstrumentation();
|
||||
void registerCallbacks(PassInstrumentationCallbacks &PIC);
|
||||
void reportCrashIR();
|
||||
|
||||
protected:
|
||||
std::string SavedIR;
|
||||
|
||||
private:
|
||||
// The crash reporter that will report on a crash.
|
||||
static PrintCrashIRInstrumentation *CrashReporter;
|
||||
// Crash handler registered when print-on-crash is specified.
|
||||
static void SignalHandler(void *);
|
||||
};
|
||||
|
||||
/// This class provides an interface to register all the standard pass
|
||||
/// instrumentations and manages their state (if any).
|
||||
class StandardInstrumentations {
|
||||
|
@ -493,6 +512,7 @@ class StandardInstrumentations {
|
|||
PseudoProbeVerifier PseudoProbeVerification;
|
||||
InLineChangePrinter PrintChangedDiff;
|
||||
DotCfgChangeReporter WebsiteChangeReporter;
|
||||
PrintCrashIRInstrumentation PrintCrashIR;
|
||||
VerifyInstrumentation Verify;
|
||||
|
||||
bool VerifyEach;
|
||||
|
|
|
@ -375,6 +375,17 @@ bool shouldPopulateClassToPassNames() {
|
|||
!printAfterPasses().empty();
|
||||
}
|
||||
|
||||
// A pass for testing -print-on-crash.
|
||||
// DO NOT USE THIS EXCEPT FOR TESTING!
|
||||
class TriggerCrashPass : public PassInfoMixin<TriggerCrashPass> {
|
||||
public:
|
||||
PreservedAnalyses run(Module &, ModuleAnalysisManager &) {
|
||||
abort();
|
||||
return PreservedAnalyses::all();
|
||||
}
|
||||
static StringRef name() { return "TriggerCrashPass"; }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
PassBuilder::PassBuilder(TargetMachine *TM, PipelineTuningOptions PTO,
|
||||
|
|
|
@ -114,6 +114,7 @@ MODULE_PASS("strip-debug-declare", StripDebugDeclarePass())
|
|||
MODULE_PASS("strip-nondebug", StripNonDebugSymbolsPass())
|
||||
MODULE_PASS("strip-nonlinetable-debuginfo", StripNonLineTableDebugInfoPass())
|
||||
MODULE_PASS("synthetic-counts-propagation", SyntheticCountsPropagation())
|
||||
MODULE_PASS("trigger-crash", TriggerCrashPass())
|
||||
MODULE_PASS("verify", VerifierPass())
|
||||
MODULE_PASS("view-callgraph", CallGraphViewerPass())
|
||||
MODULE_PASS("wholeprogramdevirt", WholeProgramDevirtPass())
|
||||
|
|
|
@ -28,12 +28,14 @@
|
|||
#include "llvm/IR/PrintPasses.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/CrashRecoveryContext.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
#include "llvm/Support/GraphWriter.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/Program.h"
|
||||
#include "llvm/Support/Regex.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
@ -165,6 +167,12 @@ static cl::opt<std::string> DotCfgDir(
|
|||
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<bool>
|
||||
PrintCrashIR("print-on-crash",
|
||||
cl::desc("Print the last form of the IR before crash"),
|
||||
cl::init(false), cl::Hidden);
|
||||
|
||||
namespace {
|
||||
|
||||
// Perform a system based diff between \p Before and \p After, using
|
||||
|
@ -2115,6 +2123,51 @@ StandardInstrumentations::StandardInstrumentations(
|
|||
ChangePrinter::PrintChangedDotCfgVerbose),
|
||||
Verify(DebugLogging), VerifyEach(VerifyEach) {}
|
||||
|
||||
PrintCrashIRInstrumentation *PrintCrashIRInstrumentation::CrashReporter =
|
||||
nullptr;
|
||||
|
||||
void PrintCrashIRInstrumentation::reportCrashIR() { dbgs() << SavedIR; }
|
||||
|
||||
void PrintCrashIRInstrumentation::SignalHandler(void *) {
|
||||
// Called by signal handlers so do not lock here
|
||||
// Is the PrintCrashIRInstrumentation still alive?
|
||||
if (!CrashReporter)
|
||||
return;
|
||||
|
||||
assert(PrintCrashIR && "Did not expect to get here without option set.");
|
||||
CrashReporter->reportCrashIR();
|
||||
}
|
||||
|
||||
PrintCrashIRInstrumentation::~PrintCrashIRInstrumentation() {
|
||||
if (!CrashReporter)
|
||||
return;
|
||||
|
||||
assert(PrintCrashIR && "Did not expect to get here without option set.");
|
||||
CrashReporter = nullptr;
|
||||
}
|
||||
|
||||
void PrintCrashIRInstrumentation::registerCallbacks(
|
||||
PassInstrumentationCallbacks &PIC) {
|
||||
if (!PrintCrashIR || CrashReporter)
|
||||
return;
|
||||
|
||||
sys::AddSignalHandler(SignalHandler, nullptr);
|
||||
CrashReporter = this;
|
||||
|
||||
PIC.registerBeforeNonSkippedPassCallback([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)) {
|
||||
OS << " Filtered Out ***\n";
|
||||
return;
|
||||
}
|
||||
OS << " Started ***\n";
|
||||
unwrapAndPrint(OS, IR);
|
||||
});
|
||||
}
|
||||
|
||||
void StandardInstrumentations::registerCallbacks(
|
||||
PassInstrumentationCallbacks &PIC, FunctionAnalysisManager *FAM) {
|
||||
PrintIR.registerCallbacks(PIC);
|
||||
|
@ -2130,6 +2183,7 @@ void StandardInstrumentations::registerCallbacks(
|
|||
Verify.registerCallbacks(PIC);
|
||||
PrintChangedDiff.registerCallbacks(PIC);
|
||||
WebsiteChangeReporter.registerCallbacks(PIC);
|
||||
PrintCrashIR.registerCallbacks(PIC);
|
||||
}
|
||||
|
||||
template class ChangeReporter<std::string>;
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
; A test that the hidden option -print-on-crash properly sets a signal handler
|
||||
; which gets called when a pass crashes. The trigger-crash pass asserts.
|
||||
|
||||
; RUN: not --crash opt -print-on-crash -passes=trigger-crash < %s 2>&1 | FileCheck %s --check-prefix=CHECK_SIMPLE
|
||||
|
||||
; 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<O2>" < %s 2>&1 | FileCheck %s --check-prefix=CHECK_NO_CRASH
|
||||
|
||||
; RUN: not --crash opt -print-on-crash -print-module-scope -passes=trigger-crash < %s 2>&1 | FileCheck %s --check-prefix=CHECK_MODULE
|
||||
|
||||
; RUN: not --crash opt -print-on-crash -print-module-scope -passes=trigger-crash -filter-passes=TriggerCrashPass < %s 2>&1 | FileCheck %s --check-prefix=CHECK_MODULE
|
||||
|
||||
; RUN: not --crash opt -print-on-crash -print-module-scope -passes=trigger-crash -filter-passes=blah < %s 2>&1 | FileCheck %s --check-prefix=CHECK_FILTERED
|
||||
|
||||
; CHECK_SIMPLE: *** Dump of IR Before Last Pass {{.*}} Started ***
|
||||
; CHECK_SIMPLE: @main
|
||||
; CHECK_SIMPLE: entry:
|
||||
; CHECK_NO_CRASH-NOT: *** Dump of IR
|
||||
; CHECK_MODULE: *** Dump of Module IR Before Last Pass {{.*}} Started ***
|
||||
; CHECK_MODULE: ; ModuleID = {{.*}}
|
||||
; CHECK_FILTERED: *** Dump of Module IR Before Last Pass {{.*}} Filtered Out ***
|
||||
|
||||
define i32 @main() {
|
||||
entry:
|
||||
%retval = alloca i32, align 4
|
||||
store i32 0, i32* %retval, align 4
|
||||
ret i32 0
|
||||
}
|
Loading…
Reference in New Issue