Skip to content

Commit b218927

Browse files
committed
[PassManager] Add pretty stack frames
In NewPM pass managers, add a "pretty stack frame" that tells you which pass crashed while running which function: ``` Stack dump: 0. Program arguments: build/bin/opt -S -passes=instcombine llvm/test/Transforms/InstCombine/vec_shuffle.ll 1. Running pass "ModuleToFunctionPassAdaptor" on module "llvm/test/Transforms/InstCombine/vec_shuffle.ll" 2. Running pass "InstCombinePass" on function "test16a" ``` While the crashing pass is usually evident from the stack trace, knowing which function caused it is quite handy. Similar functionality existed in the LegacyPM.
1 parent 957dc43 commit b218927

File tree

8 files changed

+96
-11
lines changed

8 files changed

+96
-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: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using namespace llvm;
1414

1515
namespace llvm {
16+
1617
// Explicit template instantiations and specialization defininitions for core
1718
// template typedefs.
1819
template class AllAnalysesOn<Module>;
@@ -144,6 +145,18 @@ PreservedAnalyses ModuleToFunctionPassAdaptor::run(Module &M,
144145
return PA;
145146
}
146147

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

149162
AnalysisSetKey PreservedAnalyses::AllAnalysesKey;

llvm/lib/Passes/PassBuilder.cpp

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

326326
namespace {
327327

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

339349
// 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)