Skip to content

Commit 253a294

Browse files
authored
[PassManager] Add pretty stack frames (#96078)
In NewPM pass managers, add a "pretty stack frame" that tells you which pass crashed while running which function. For example `opt -O3 -passes-ep-peephole=trigger-crash-function test.ll` will print something like this: ``` Stack dump: 0. Program arguments: build/bin/opt -S -O3 -passes-ep-peephole=trigger-crash-function test.ll 1. Running pass "function<eager-inv>(mem2reg,instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,trigger-crash-function,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;no-sink-common-insts;speculate-blocks;simplify-cond-branch>)" on module "test.ll" 2. Running pass "trigger-crash-function" on function "fshl_concat_i8_i8" ``` While the crashing pass is usually evident from the stack trace, this also shows which function triggered the crash, as well as the pipeline string for the pass (including options). Similar functionality existed in the LegacyPM.
1 parent dfd2711 commit 253a294

File tree

8 files changed

+95
-11
lines changed

8 files changed

+95
-11
lines changed

llvm/include/llvm/IR/PassInstrumentation.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,13 @@ class PassInstrumentation {
332332
if (Callbacks)
333333
Callbacks->BeforeNonSkippedPassCallbacks.pop_back();
334334
}
335+
336+
/// Get the pass name for a given pass class name.
337+
StringRef getPassNameForClassName(StringRef ClassName) const {
338+
if (Callbacks)
339+
return Callbacks->getPassNameForClassName(ClassName);
340+
return {};
341+
}
335342
};
336343

337344
bool isSpecialPass(StringRef PassID, const std::vector<StringRef> &Specials);

llvm/include/llvm/IR/PassManager.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,11 +224,21 @@ class PassManager : public PassInfoMixin<
224224
std::vector<std::unique_ptr<PassConceptT>> Passes;
225225
};
226226

227+
template <typename IRUnitT>
228+
void printIRUnitNameForStackTrace(raw_ostream &OS, const IRUnitT &IR);
229+
230+
template <>
231+
void printIRUnitNameForStackTrace<Module>(raw_ostream &OS, const Module &IR);
232+
227233
extern template class PassManager<Module>;
228234

229235
/// Convenience typedef for a pass manager over modules.
230236
using ModulePassManager = PassManager<Module>;
231237

238+
template <>
239+
void printIRUnitNameForStackTrace<Function>(raw_ostream &OS,
240+
const Function &IR);
241+
232242
extern template class PassManager<Function>;
233243

234244
/// Convenience typedef for a pass manager over functions.

llvm/include/llvm/IR/PassManagerImpl.h

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@
1515
#ifndef LLVM_IR_PASSMANAGERIMPL_H
1616
#define LLVM_IR_PASSMANAGERIMPL_H
1717

18-
#include "llvm/Support/CommandLine.h"
1918
#include "llvm/IR/PassInstrumentation.h"
2019
#include "llvm/IR/PassManager.h"
20+
#include "llvm/Support/CommandLine.h"
21+
#include "llvm/Support/PrettyStackTrace.h"
2122

2223
extern llvm::cl::opt<bool> UseNewDbgInfoFormat;
2324

@@ -26,6 +27,28 @@ namespace llvm {
2627
template <typename IRUnitT, typename AnalysisManagerT, typename... ExtraArgTs>
2728
PreservedAnalyses PassManager<IRUnitT, AnalysisManagerT, ExtraArgTs...>::run(
2829
IRUnitT &IR, AnalysisManagerT &AM, ExtraArgTs... ExtraArgs) {
30+
class StackTraceEntry : public PrettyStackTraceEntry {
31+
const PassInstrumentation &PI;
32+
PassConceptT &Pass;
33+
IRUnitT &IR;
34+
35+
public:
36+
explicit StackTraceEntry(const PassInstrumentation &PI, PassConceptT &Pass,
37+
IRUnitT &IR)
38+
: PI(PI), Pass(Pass), IR(IR) {}
39+
40+
void print(raw_ostream &OS) const override {
41+
OS << "Running pass \"";
42+
Pass.printPipeline(OS, [this](StringRef ClassName) {
43+
auto PassName = PI.getPassNameForClassName(ClassName);
44+
return PassName.empty() ? ClassName : PassName;
45+
});
46+
OS << "\" on ";
47+
printIRUnitNameForStackTrace(OS, IR);
48+
OS << "\n";
49+
}
50+
};
51+
2952
PreservedAnalyses PA = PreservedAnalyses::all();
3053

3154
// Request PassInstrumentation from analysis manager, will use it to run
@@ -47,6 +70,7 @@ PreservedAnalyses PassManager<IRUnitT, AnalysisManagerT, ExtraArgTs...>::run(
4770
if (!PI.runBeforePass<IRUnitT>(*Pass, IR))
4871
continue;
4972

73+
StackTraceEntry Entry(PI, *Pass, IR);
5074
PreservedAnalyses PassPA = Pass->run(IR, AM, ExtraArgs...);
5175

5276
// Update the analysis manager as each pass runs and potentially

llvm/lib/IR/PassManager.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,18 @@ PreservedAnalyses ModuleToFunctionPassAdaptor::run(Module &M,
144144
return PA;
145145
}
146146

147+
template <>
148+
void llvm::printIRUnitNameForStackTrace<Module>(raw_ostream &OS,
149+
const Module &IR) {
150+
OS << "module \"" << IR.getName() << "\"";
151+
}
152+
153+
template <>
154+
void llvm::printIRUnitNameForStackTrace<Function>(raw_ostream &OS,
155+
const Function &IR) {
156+
OS << "function \"" << IR.getName() << "\"";
157+
}
158+
147159
AnalysisSetKey CFGAnalyses::SetKey;
148160

149161
AnalysisSetKey PreservedAnalyses::AllAnalysesKey;

llvm/lib/Passes/PassBuilder.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -326,15 +326,25 @@ AnalysisKey NoOpLoopAnalysis::Key;
326326

327327
namespace {
328328

329-
// A pass for testing -print-on-crash.
329+
// Passes for testing crashes.
330330
// DO NOT USE THIS EXCEPT FOR TESTING!
331-
class TriggerCrashPass : public PassInfoMixin<TriggerCrashPass> {
331+
class TriggerCrashModulePass : public PassInfoMixin<TriggerCrashModulePass> {
332332
public:
333333
PreservedAnalyses run(Module &, ModuleAnalysisManager &) {
334334
abort();
335335
return PreservedAnalyses::all();
336336
}
337-
static StringRef name() { return "TriggerCrashPass"; }
337+
static StringRef name() { return "TriggerCrashModulePass"; }
338+
};
339+
340+
class TriggerCrashFunctionPass
341+
: public PassInfoMixin<TriggerCrashFunctionPass> {
342+
public:
343+
PreservedAnalyses run(Function &, FunctionAnalysisManager &) {
344+
abort();
345+
return PreservedAnalyses::all();
346+
}
347+
static StringRef name() { return "TriggerCrashFunctionPass"; }
338348
};
339349

340350
// A pass for testing message reporting of -verify-each failures.

llvm/lib/Passes/PassRegistry.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ MODULE_PASS("strip-debug-declare", StripDebugDeclarePass())
137137
MODULE_PASS("strip-nondebug", StripNonDebugSymbolsPass())
138138
MODULE_PASS("strip-nonlinetable-debuginfo", StripNonLineTableDebugInfoPass())
139139
MODULE_PASS("synthetic-counts-propagation", SyntheticCountsPropagation())
140-
MODULE_PASS("trigger-crash", TriggerCrashPass())
140+
MODULE_PASS("trigger-crash-module", TriggerCrashModulePass())
141141
MODULE_PASS("trigger-verifier-error", TriggerVerifierErrorPass())
142142
MODULE_PASS("tsan-module", ModuleThreadSanitizerPass())
143143
MODULE_PASS("verify", VerifierPass())
@@ -459,6 +459,7 @@ FUNCTION_PASS("structurizecfg", StructurizeCFGPass())
459459
FUNCTION_PASS("tailcallelim", TailCallElimPass())
460460
FUNCTION_PASS("tlshoist", TLSVariableHoistPass())
461461
FUNCTION_PASS("transform-warning", WarnMissedTransformationsPass())
462+
FUNCTION_PASS("trigger-crash-function", TriggerCrashFunctionPass())
462463
FUNCTION_PASS("trigger-verifier-error", TriggerVerifierErrorPass())
463464
FUNCTION_PASS("tsan", ThreadSanitizerPass())
464465
FUNCTION_PASS("typepromotion", TypePromotionPass(TM))

llvm/test/Other/crash-stack-trace.ll

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
; REQUIRES: asserts
2+
3+
; RUN: not --crash opt -passes=trigger-crash-module %s -disable-output 2>&1 | \
4+
; RUN: FileCheck %s --check-prefix=CHECK-MODULE
5+
6+
; CHECK-MODULE: Stack dump:
7+
; CHECK-MODULE-NEXT: 0. Program arguments:
8+
; CHECK-MODULE-NEXT: 1. Running pass "trigger-crash-module" on module "{{.*}}crash-stack-trace.ll"
9+
10+
; RUN: not --crash opt -passes='sroa,trigger-crash-function' %s -disable-output 2>&1 | \
11+
; RUN: FileCheck %s --check-prefix=CHECK-FUNCTION
12+
13+
; CHECK-FUNCTION: Stack dump:
14+
; CHECK-FUNCTION-NEXT: 0. Program arguments:
15+
; CHECK-FUNCTION-NEXT: 1. Running pass "function(sroa<modify-cfg>,trigger-crash-function)" on module "{{.*}}crash-stack-trace.ll"
16+
; CHECK-FUNCTION-NEXT: 2. Running pass "trigger-crash-function" on function "foo"
17+
18+
define void @foo() {
19+
ret void
20+
}

llvm/test/Other/print-on-crash.ll

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
; A test that the hidden option -print-on-crash properly sets a signal handler
2-
; which gets called when a pass crashes. The trigger-crash pass asserts.
2+
; which gets called when a pass crashes. The trigger-crash-module pass asserts.
33

4-
; RUN: not --crash opt -print-on-crash -passes=trigger-crash < %s 2>&1 | FileCheck %s --check-prefix=CHECK_SIMPLE
4+
; RUN: not --crash opt -print-on-crash -passes=trigger-crash-module < %s 2>&1 | FileCheck %s --check-prefix=CHECK_SIMPLE
55

6-
; RUN: not --crash opt -print-on-crash-path=%t -passes=trigger-crash < %s
6+
; RUN: not --crash opt -print-on-crash-path=%t -passes=trigger-crash-module < %s
77
; RUN: FileCheck %s --check-prefix=CHECK_SIMPLE --input-file=%t
88

99
; A test that the signal handler set by the hidden option -print-on-crash
1010
; is not called when no pass crashes.
1111

1212
; RUN: opt -disable-output -print-on-crash -passes="default<O2>" < %s 2>&1 | FileCheck %s --check-prefix=CHECK_NO_CRASH --allow-empty
1313

14-
; RUN: not --crash opt -print-on-crash -print-module-scope -passes=trigger-crash < %s 2>&1 | FileCheck %s --check-prefix=CHECK_MODULE
14+
; RUN: not --crash opt -print-on-crash -print-module-scope -passes=trigger-crash-module < %s 2>&1 | FileCheck %s --check-prefix=CHECK_MODULE
1515

16-
; RUN: not --crash opt -print-on-crash -print-module-scope -passes=trigger-crash -filter-passes=trigger-crash < %s 2>&1 | FileCheck %s --check-prefix=CHECK_MODULE
16+
; RUN: not --crash opt -print-on-crash -print-module-scope -passes=trigger-crash-module -filter-passes=trigger-crash-module < %s 2>&1 | FileCheck %s --check-prefix=CHECK_MODULE
1717

18-
; 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
18+
; RUN: not --crash opt -print-on-crash -print-module-scope -passes=trigger-crash-module -filter-passes=blah < %s 2>&1 | FileCheck %s --check-prefix=CHECK_FILTERED
1919

2020
; CHECK_SIMPLE: *** Dump of IR Before Last Pass {{.*}} Started ***
2121
; CHECK_SIMPLE: @main

0 commit comments

Comments
 (0)