Skip to content

Commit 2aaf753

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 36c6632 commit 2aaf753

File tree

8 files changed

+97
-16
lines changed

8 files changed

+97
-16
lines changed

llvm/include/llvm/IR/PassInstrumentation.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,13 @@ class PassInstrumentation {
326326
if (Callbacks)
327327
Callbacks->BeforeNonSkippedPassCallbacks.pop_back();
328328
}
329+
330+
/// Get the pass name for a given pass class name.
331+
StringRef getPassNameForClassName(StringRef ClassName) const {
332+
if (Callbacks)
333+
return Callbacks->getPassNameForClassName(ClassName);
334+
return {};
335+
}
329336
};
330337

331338
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
@@ -221,11 +221,21 @@ class PassManager : public PassInfoMixin<
221221
std::vector<std::unique_ptr<PassConceptT>> Passes;
222222
};
223223

224+
template <typename IRUnitT>
225+
void printIRUnitNameForStackTrace(raw_ostream &OS, const IRUnitT &IR);
226+
227+
template <>
228+
void printIRUnitNameForStackTrace<Module>(raw_ostream &OS, const Module &IR);
229+
224230
extern template class PassManager<Module>;
225231

226232
/// Convenience typedef for a pass manager over modules.
227233
using ModulePassManager = PassManager<Module>;
228234

235+
template <>
236+
void printIRUnitNameForStackTrace<Function>(raw_ostream &OS,
237+
const Function &IR);
238+
229239
extern template class PassManager<Function>;
230240

231241
/// 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: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -330,21 +330,27 @@ namespace {
330330
/// This is for optimization purposes so we don't populate it if we never use
331331
/// it. This should be updated if new pass instrumentation wants to use the map.
332332
/// We currently only use this for --print-before/after.
333-
bool shouldPopulateClassToPassNames() {
334-
return PrintPipelinePasses || !printBeforePasses().empty() ||
335-
!printAfterPasses().empty() || !isFilterPassesEmpty() ||
336-
TargetPassConfig::hasLimitedCodeGenPipeline();
337-
}
333+
bool shouldPopulateClassToPassNames() { return true; }
338334

339-
// A pass for testing -print-on-crash.
335+
// Passes for testing crashes.
340336
// DO NOT USE THIS EXCEPT FOR TESTING!
341-
class TriggerCrashPass : public PassInfoMixin<TriggerCrashPass> {
337+
class TriggerCrashModulePass : public PassInfoMixin<TriggerCrashModulePass> {
342338
public:
343339
PreservedAnalyses run(Module &, ModuleAnalysisManager &) {
344340
abort();
345341
return PreservedAnalyses::all();
346342
}
347-
static StringRef name() { return "TriggerCrashPass"; }
343+
static StringRef name() { return "TriggerCrashModulePass"; }
344+
};
345+
346+
class TriggerCrashFunctionPass
347+
: public PassInfoMixin<TriggerCrashFunctionPass> {
348+
public:
349+
PreservedAnalyses run(Function &, FunctionAnalysisManager &) {
350+
abort();
351+
return PreservedAnalyses::all();
352+
}
353+
static StringRef name() { return "TriggerCrashFunctionPass"; }
348354
};
349355

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