diff --git a/llvm/include/llvm/Passes/StandardInstrumentations.h b/llvm/include/llvm/Passes/StandardInstrumentations.h --- a/llvm/include/llvm/Passes/StandardInstrumentations.h +++ b/llvm/include/llvm/Passes/StandardInstrumentations.h @@ -75,6 +75,8 @@ }; class OptBisectInstrumentation { + bool HasWrittenIR = false; + public: OptBisectInstrumentation() = default; void registerCallbacks(PassInstrumentationCallbacks &PIC); 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 @@ -30,6 +30,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/GraphWriter.h" #include "llvm/Support/MemoryBuffer.h" @@ -101,6 +102,10 @@ cl::desc("Print the last form of the IR before crash"), cl::init(false), cl::Hidden); +static cl::opt OptBisectPrintIRPath( + "opt-bisect-print-ir-path", + cl::desc("Print IR to path when opt-bisect-limit is reached"), cl::Hidden); + namespace { /// Extract Module out of \p IR unit. May return nullptr if \p IR does not match @@ -765,9 +770,23 @@ PassInstrumentationCallbacks &PIC) { if (!getOptBisector().isEnabled()) return; - PIC.registerShouldRunOptionalPassCallback([](StringRef PassID, Any IR) { - return isIgnored(PassID) || - getOptBisector().checkPass(PassID, getIRName(IR)); + PIC.registerShouldRunOptionalPassCallback([this](StringRef PassID, Any IR) { + if (isIgnored(PassID)) + return true; + bool ShouldRun = getOptBisector().checkPass(PassID, getIRName(IR)); + if (!ShouldRun && !this->HasWrittenIR && !OptBisectPrintIRPath.empty()) { + // FIXME: print IR if limit is higher than number of opt-bisect + // invocations + this->HasWrittenIR = true; + const Module *M = unwrapModule(IR, /*Force=*/true); + assert(M && "expected Module"); + std::error_code EC; + raw_fd_ostream OS(OptBisectPrintIRPath, EC); + if (EC) + report_fatal_error(errorCodeToError(EC)); + M->print(OS, nullptr); + } + return ShouldRun; }); } diff --git a/llvm/test/Other/opt-bisect-print-ir-path.ll b/llvm/test/Other/opt-bisect-print-ir-path.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Other/opt-bisect-print-ir-path.ll @@ -0,0 +1,28 @@ +; RUN: opt -disable-verify -passes=instcombine < %s -opt-bisect-limit=0 -opt-bisect-print-ir-path=%t -disable-output +; RUN: FileCheck %s --check-prefix=LIMIT0 --input-file %t +; RUN: opt -disable-verify -passes=instcombine < %s -opt-bisect-limit=1 -opt-bisect-print-ir-path=%t -disable-output +; RUN: FileCheck %s --check-prefix=LIMIT1 --input-file %t +; RUN: opt -disable-verify -passes=instcombine < %s -opt-bisect-limit=2 -opt-bisect-print-ir-path=%t -disable-output +; FIXME: print IR if limit is higher than number of opt-bisect invocations + +; Check that we only print the module once +; RUN: opt -disable-verify -passes=instcombine < %s -opt-bisect-limit=1 -opt-bisect-print-ir-path=- -disable-output 2>&1 | FileCheck %s + +; LIMIT0: ret i32 %r +; LIMIT0: ret i32 %r + +; LIMIT1: ret i32 2 +; LIMIT1: ret i32 %r + +; CHECK: ModuleID +; CHECK-NOT: ModuleID + +define i32 @f1() { + %r = add i32 1, 1 + ret i32 %r +} + +define i32 @f2() { + %r = add i32 1, 1 + ret i32 %r +}