[llvm] 9544a32 - A new option -print-on-crash that prints the IR as it was upon entering the last pass when there is a crash.

Philip Reames via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 23 09:43:24 PDT 2021


This is awesome, and long overdue.  Thanks!

Philip

On 3/23/21 6:30 AM, Jamie Schmeiser via llvm-commits wrote:
> Author: Jamie Schmeiser
> Date: 2021-03-23T09:29:17-04:00
> New Revision: 9544a32287eccb42a4367cff9b5888855d6b8756
>
> URL: https://github.com/llvm/llvm-project/commit/9544a32287eccb42a4367cff9b5888855d6b8756
> DIFF: https://github.com/llvm/llvm-project/commit/9544a32287eccb42a4367cff9b5888855d6b8756.diff
>
> LOG: A new option -print-on-crash that prints the IR as it was upon entering the last pass when there is a crash.
> Summary:
> 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.
>
> Author: Jamie Schmeiser <schmeise at ca.ibm.com>
> Reviewed By: aeubanks (Arthur Eubanks) yrouban (Yevgeny Rouban)
> Differential Revision: https://reviews.llvm.org/D86657
>
> Added:
>      llvm/test/Other/print-on-crash.ll
>
> Modified:
>      llvm/include/llvm/Passes/StandardInstrumentations.h
>      llvm/lib/Passes/PassBuilder.cpp
>      llvm/lib/Passes/PassRegistry.def
>      llvm/lib/Passes/StandardInstrumentations.cpp
>
> Removed:
>      
>
>
> ################################################################################
> diff  --git a/llvm/include/llvm/Passes/StandardInstrumentations.h b/llvm/include/llvm/Passes/StandardInstrumentations.h
> index f023a2924d8f..1717f09258e5 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/DenseSet.h"
>   #include "llvm/ADT/STLExtras.h"
>   #include "llvm/ADT/SmallVector.h"
>   #include "llvm/ADT/StringRef.h"
> @@ -25,6 +26,7 @@
>   #include "llvm/Support/CommandLine.h"
>   #include "llvm/Transforms/IPO/SampleProfileProbe.h"
>   
> +#include <mutex>
>   #include <string>
>   #include <utility>
>   
> @@ -390,6 +392,35 @@ class VerifyInstrumentation {
>     void registerCallbacks(PassInstrumentationCallbacks &PIC);
>   };
>   
> +// 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:
> +  // All of the crash reporters that will report on a crash.
> +  static DenseSet<PrintCrashIRInstrumentation *> *CrashReporters;
> +  // Crash handler registered when print-on-crash is specified.
> +  static void SignalHandler(void *);
> +  // Exception-safe locking
> +  class MtxLock {
> +  public:
> +    MtxLock() { Mtx.lock(); }
> +    ~MtxLock() { Mtx.unlock(); }
> +
> +  protected:
> +    // Avoid races when creating/destroying the crash IR printers.
> +    static std::mutex Mtx;
> +  };
> +};
> +
>   /// This class provides an interface to register all the standard pass
>   /// instrumentations and manages their state (if any).
>   class StandardInstrumentations {
> @@ -402,6 +433,7 @@ class StandardInstrumentations {
>     IRChangedPrinter PrintChangedIR;
>     PseudoProbeVerifier PseudoProbeVerification;
>     InLineChangePrinter PrintChangedDiff;
> +  PrintCrashIRInstrumentation PrintCrashIR;
>     VerifyInstrumentation Verify;
>   
>     bool VerifyEach;
> @@ -419,7 +451,6 @@ 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/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
> index 3a325277e370..3119445da738 100644
> --- a/llvm/lib/Passes/PassBuilder.cpp
> +++ b/llvm/lib/Passes/PassBuilder.cpp
> @@ -438,6 +438,18 @@ bool shouldPopulateClassToPassNames() {
>     return !printBeforePasses().empty() || !printAfterPasses().empty();
>   }
>   
> +// A pass for testing -print-on-crash.
> +// DO NOT USE THIS EXCEPT FOR TESTING!
> +class TriggerCrashPass : public PassInfoMixin<TriggerCrashPass> {
> +public:
> +  PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
> +};
> +
> +// DO NOT USE THIS EXCEPT FOR TESTING!
> +PreservedAnalyses TriggerCrashPass::run(Function &, FunctionAnalysisManager &) {
> +  __builtin_trap();
> +}
> +
>   } // namespace
>   
>   PassBuilder::PassBuilder(bool DebugLogging, TargetMachine *TM,
>
> diff  --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
> index 579143d3c1c8..ca3ed7f19bf6 100644
> --- a/llvm/lib/Passes/PassRegistry.def
> +++ b/llvm/lib/Passes/PassRegistry.def
> @@ -311,6 +311,7 @@ FUNCTION_PASS("sroa", SROA())
>   FUNCTION_PASS("strip-gc-relocates", StripGCRelocates())
>   FUNCTION_PASS("structurizecfg", StructurizeCFGPass())
>   FUNCTION_PASS("tailcallelim", TailCallElimPass())
> +FUNCTION_PASS("trigger-crash", TriggerCrashPass())
>   FUNCTION_PASS("unify-loop-exits", UnifyLoopExitsPass())
>   FUNCTION_PASS("vector-combine", VectorCombinePass())
>   FUNCTION_PASS("verify", VerifierPass())
>
> diff  --git a/llvm/lib/Passes/StandardInstrumentations.cpp b/llvm/lib/Passes/StandardInstrumentations.cpp
> index 601957034489..ff2a014f8453 100644
> --- a/llvm/lib/Passes/StandardInstrumentations.cpp
> +++ b/llvm/lib/Passes/StandardInstrumentations.cpp
> @@ -15,6 +15,7 @@
>   #include "llvm/Passes/StandardInstrumentations.h"
>   #include "llvm/ADT/Any.h"
>   #include "llvm/ADT/Optional.h"
> +#include "llvm/ADT/SmallString.h"
>   #include "llvm/ADT/StringRef.h"
>   #include "llvm/Analysis/CallGraphSCCPass.h"
>   #include "llvm/Analysis/LazyCallGraph.h"
> @@ -25,10 +26,12 @@
>   #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/MemoryBuffer.h"
>   #include "llvm/Support/Program.h"
> +#include "llvm/Support/Signals.h"
>   #include "llvm/Support/raw_ostream.h"
>   #include <unordered_set>
>   #include <vector>
> @@ -117,6 +120,12 @@ static cl::opt<std::string>
>       DiffBinary("print-changed-
> diff -path", cl::Hidden, cl::init("
> diff "),
>                  cl::desc("system
> diff  used by change reporters"));
>   
> +// 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
> @@ -1153,6 +1162,68 @@ StandardInstrumentations::StandardInstrumentations(bool DebugLogging,
>         PrintChangedDiff(PrintChanged == ChangePrinter::PrintChangedDiffVerbose),
>         Verify(DebugLogging), VerifyEach(VerifyEach) {}
>   
> +std::mutex PrintCrashIRInstrumentation::MtxLock::Mtx;
> +DenseSet<PrintCrashIRInstrumentation *>
> +    *PrintCrashIRInstrumentation::CrashReporters = nullptr;
> +
> +void PrintCrashIRInstrumentation::reportCrashIR() { dbgs() << SavedIR; }
> +
> +void PrintCrashIRInstrumentation::SignalHandler(void *) {
> +  // Called by signal handlers so do not lock here
> +  // Are any of PrintCrashIRInstrumentation objects still alive?
> +  if (!CrashReporters)
> +    return;
> +
> +  assert(PrintCrashIR && "Did not expect to get here without option set.");
> +  for (auto I : *CrashReporters)
> +    I->reportCrashIR();
> +}
> +
> +PrintCrashIRInstrumentation::~PrintCrashIRInstrumentation() {
> +  if (!PrintCrashIR)
> +    return;
> +
> +  MtxLock Lock;
> +  assert(CrashReporters && "Expected CrashReporters to be set");
> +
> +  // Was this registered?
> +  DenseSet<PrintCrashIRInstrumentation *>::iterator I =
> +      CrashReporters->find(this);
> +  if (I == CrashReporters->end())
> +    return;
> +  CrashReporters->erase(I);
> +  if (!CrashReporters->empty())
> +    return;
> +  delete CrashReporters;
> +  CrashReporters = nullptr;
> +}
> +
> +void PrintCrashIRInstrumentation::registerCallbacks(
> +    PassInstrumentationCallbacks &PIC) {
> +  if (!PrintCrashIR)
> +    return;
> +
> +  {
> +    MtxLock Lock;
> +    if (!CrashReporters) {
> +      CrashReporters = new DenseSet<PrintCrashIRInstrumentation *>();
> +      sys::AddSignalHandler(SignalHandler, nullptr);
> +    }
> +    CrashReporters->insert(this);
> +  }
> +  PIC.registerBeforeNonSkippedPassCallback([this](StringRef PassID, Any IR) {
> +    assert((MtxLock(), CrashReporters && CrashReporters->find(this) !=
> +                                             CrashReporters->end()) &&
> +           "Expected CrashReporters to be set and containing this");
> +    SavedIR.clear();
> +    SmallString<80> Banner =
> +        formatv("*** Dump of {0}IR Before Last Pass {1} Started ***",
> +                llvm::forcePrintModuleIR() ? "Module " : "", PassID);
> +    raw_string_ostream OS(SavedIR);
> +    unwrapAndPrint(OS, IR, Banner, llvm::forcePrintModuleIR());
> +  });
> +}
> +
>   void StandardInstrumentations::registerCallbacks(
>       PassInstrumentationCallbacks &PIC) {
>     PrintIR.registerCallbacks(PIC);
> @@ -1166,6 +1237,7 @@ void StandardInstrumentations::registerCallbacks(
>     if (VerifyEach)
>       Verify.registerCallbacks(PIC);
>     PrintChangedDiff.registerCallbacks(PIC);
> +  PrintCrashIR.registerCallbacks(PIC);
>   }
>   
>   namespace llvm {
>
> diff  --git a/llvm/test/Other/print-on-crash.ll b/llvm/test/Other/print-on-crash.ll
> new file mode 100644
> index 000000000000..42da46237432
> --- /dev/null
> +++ b/llvm/test/Other/print-on-crash.ll
> @@ -0,0 +1,28 @@
> +; 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 calls
> +; __builtin_trap.
> +
> +; 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
> +
> +; The input corresponds to "int main() { return 0; }" but is irrelevant.
> +
> +; 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 = {{.*}}
> +
> +define i32 @main() {
> +entry:
> +  %retval = alloca i32, align 4
> +  store i32 0, i32* %retval, align 4
> +  ret i32 0
> +}
>
>
>          
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits


More information about the llvm-commits mailing list