Skip to content

Commit 5db2c27

Browse files
Add marker passes to various pipeline stages (#50111)
1 parent a595274 commit 5db2c27

File tree

5 files changed

+458
-18
lines changed

5 files changed

+458
-18
lines changed

doc/src/devdocs/llvm.md

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,39 @@ Here are example settings using `bash` syntax:
8282
* `export JULIA_LLVM_ARGS=-debug-only=loop-vectorize` dumps LLVM `DEBUG(...)` diagnostics for
8383
loop vectorizer. If you get warnings about "Unknown command line argument", rebuild LLVM with
8484
`LLVM_ASSERTIONS = 1`.
85-
* `export JULIA_LLVM_ARGS=-help` shows a list of available options.
85+
* `export JULIA_LLVM_ARGS=-help` shows a list of available options. `export JULIA_LLVM_ARGS=-help-hidden` shows even more.
8686
* `export JULIA_LLVM_ARGS="-fatal-warnings -print-options"` is an example how to use multiple options.
8787

88+
### Useful `JULIA_LLVM_ARGS` parameters
89+
* `-print-after=PASS`: prints the IR after any execution of `PASS`, useful for checking changes done by a pass.
90+
* `-print-before=PASS`: prints the IR before any execution of `PASS`, useful for checking the input to a pass.
91+
* `-print-changed`: prints the IR whenever a pass changes the IR, useful for narrowing down which passes are causing problems.
92+
* `-print-(before|after)=MARKER-PASS`: the Julia pipeline ships with a number of marker passes in the pipeline, which can be used to identify where problems or optimizations are occurring. A marker pass is defined as a pass which appears once in the pipeline and performs no transformations on the IR, and is only useful for targeting print-before/print-after. Currently, the following marker passes exist in the pipeline:
93+
* BeforeOptimization
94+
* BeforeEarlySimplification
95+
* AfterEarlySimplification
96+
* BeforeEarlyOptimization
97+
* AfterEarlyOptimization
98+
* BeforeLoopOptimization
99+
* BeforeLICM
100+
* AfterLICM
101+
* BeforeLoopSimplification
102+
* AfterLoopSimplification
103+
* AfterLoopOptimization
104+
* BeforeScalarOptimization
105+
* AfterScalarOptimization
106+
* BeforeVectorization
107+
* AfterVectorization
108+
* BeforeIntrinsicLowering
109+
* AfterIntrinsicLowering
110+
* BeforeCleanup
111+
* AfterCleanup
112+
* AfterOptimization
113+
* `-time-passes`: prints the time spent in each pass, useful for identifying which passes are taking a long time.
114+
* `-print-module-scope`: used in conjunction with `-print-(before|after)`, gets the entire module rather than the IR unit received by the pass
115+
* `-debug`: prints out a lot of debugging information throughout LLVM
116+
* `-debug-only=NAME`, prints out debugging statements from files with `DEBUG_TYPE` defined to `NAME`, useful for getting additional context about a problem
117+
88118
## Debugging LLVM transformations in isolation
89119

90120
On occasion, it can be useful to debug LLVM's transformations in isolation from

src/llvm-demote-float16.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,12 @@ namespace {
5151

5252
static bool have_fp16(Function &caller, const Triple &TT) {
5353
Attribute FSAttr = caller.getFnAttribute("target-features");
54-
StringRef FS =
55-
FSAttr.isValid() ? FSAttr.getValueAsString() : jl_ExecutionEngine->getTargetFeatureString();
54+
StringRef FS = "";
55+
if (FSAttr.isValid())
56+
FS = FSAttr.getValueAsString();
57+
else if (jl_ExecutionEngine)
58+
FS = jl_ExecutionEngine->getTargetFeatureString();
59+
// else probably called from opt, just do nothing
5660
if (TT.isAArch64()) {
5761
if (FS.find("+fp16fml") != llvm::StringRef::npos || FS.find("+fullfp16") != llvm::StringRef::npos){
5862
return true;

src/passes.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,4 +103,47 @@ struct JuliaLICMPass : PassInfoMixin<JuliaLICMPass> {
103103
LoopStandardAnalysisResults &AR, LPMUpdater &U) JL_NOTSAFEPOINT;
104104
};
105105

106+
#define MODULE_MARKER_PASS(NAME) \
107+
struct NAME##MarkerPass : PassInfoMixin<NAME##MarkerPass> { \
108+
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) JL_NOTSAFEPOINT { return PreservedAnalyses::all(); } \
109+
static bool isRequired() { return true; } \
110+
};
111+
112+
#define FUNCTION_MARKER_PASS(NAME) \
113+
struct NAME##MarkerPass : PassInfoMixin<NAME##MarkerPass> { \
114+
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) JL_NOTSAFEPOINT { return PreservedAnalyses::all(); } \
115+
static bool isRequired() { return true; } \
116+
};
117+
118+
#define LOOP_MARKER_PASS(NAME) \
119+
struct NAME##MarkerPass : PassInfoMixin<NAME##MarkerPass> { \
120+
PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM, \
121+
LoopStandardAnalysisResults &AR, LPMUpdater &U) JL_NOTSAFEPOINT { \
122+
return PreservedAnalyses::all(); \
123+
} \
124+
static bool isRequired() { return true; } \
125+
};
126+
127+
// These are useful for debugging with --print-before/after
128+
MODULE_MARKER_PASS(BeforeOptimization)
129+
MODULE_MARKER_PASS(BeforeEarlySimplification)
130+
MODULE_MARKER_PASS(AfterEarlySimplification)
131+
MODULE_MARKER_PASS(BeforeEarlyOptimization)
132+
MODULE_MARKER_PASS(AfterEarlyOptimization)
133+
FUNCTION_MARKER_PASS(BeforeLoopOptimization)
134+
LOOP_MARKER_PASS(BeforeLICM)
135+
LOOP_MARKER_PASS(AfterLICM)
136+
LOOP_MARKER_PASS(BeforeLoopSimplification)
137+
LOOP_MARKER_PASS(AfterLoopSimplification)
138+
FUNCTION_MARKER_PASS(AfterLoopOptimization)
139+
FUNCTION_MARKER_PASS(BeforeScalarOptimization)
140+
FUNCTION_MARKER_PASS(AfterScalarOptimization)
141+
FUNCTION_MARKER_PASS(BeforeVectorization)
142+
FUNCTION_MARKER_PASS(AfterVectorization)
143+
MODULE_MARKER_PASS(BeforeIntrinsicLowering)
144+
MODULE_MARKER_PASS(AfterIntrinsicLowering)
145+
MODULE_MARKER_PASS(BeforeCleanup)
146+
MODULE_MARKER_PASS(AfterCleanup)
147+
MODULE_MARKER_PASS(AfterOptimization)
148+
106149
#endif

src/pipeline.cpp

Lines changed: 64 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ namespace {
327327
#define JULIA_PASS(ADD_PASS) if (!options.llvm_only) { ADD_PASS; } else do { } while (0)
328328

329329
static void buildEarlySimplificationPipeline(ModulePassManager &MPM, PassBuilder *PB, OptimizationLevel O, const OptimizationOptions &options) JL_NOTSAFEPOINT {
330+
MPM.addPass(BeforeEarlySimplificationMarkerPass());
330331
#ifdef JL_DEBUG_BUILD
331332
addVerificationPasses(MPM, options.llvm_only);
332333
#endif
@@ -349,9 +350,11 @@ static void buildEarlySimplificationPipeline(ModulePassManager &MPM, PassBuilder
349350
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
350351
}
351352
invokeEarlySimplificationCallbacks(MPM, PB, O);
353+
MPM.addPass(AfterEarlySimplificationMarkerPass());
352354
}
353355

354356
static void buildEarlyOptimizerPipeline(ModulePassManager &MPM, PassBuilder *PB, OptimizationLevel O, const OptimizationOptions &options) JL_NOTSAFEPOINT {
357+
MPM.addPass(BeforeEarlyOptimizationMarkerPass());
355358
invokeOptimizerEarlyCallbacks(MPM, PB, O);
356359
{
357360
CGSCCPassManager CGPM;
@@ -387,9 +390,11 @@ static void buildEarlyOptimizerPipeline(ModulePassManager &MPM, PassBuilder *PB,
387390
invokePeepholeEPCallbacks(FPM, PB, O);
388391
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
389392
}
393+
MPM.addPass(AfterEarlyOptimizationMarkerPass());
390394
}
391395

392396
static void buildLoopOptimizerPipeline(FunctionPassManager &FPM, PassBuilder *PB, OptimizationLevel O, const OptimizationOptions &options) JL_NOTSAFEPOINT {
397+
FPM.addPass(BeforeLoopOptimizationMarkerPass());
393398
{
394399
LoopPassManager LPM;
395400
if (O.getSpeedupLevel() >= 2) {
@@ -401,11 +406,13 @@ static void buildLoopOptimizerPipeline(FunctionPassManager &FPM, PassBuilder *PB
401406
}
402407
if (O.getSpeedupLevel() >= 2) {
403408
LoopPassManager LPM;
409+
LPM.addPass(BeforeLICMMarkerPass());
404410
LPM.addPass(LICMPass(LICMOptions()));
405411
LPM.addPass(JuliaLICMPass());
406412
LPM.addPass(SimpleLoopUnswitchPass(/*NonTrivial*/true, true));
407413
LPM.addPass(LICMPass(LICMOptions()));
408414
LPM.addPass(JuliaLICMPass());
415+
LPM.addPass(AfterLICMMarkerPass());
409416
//LICM needs MemorySSA now, so we must use it
410417
FPM.addPass(createFunctionToLoopPassAdaptor(std::move(LPM), /*UseMemorySSA = */true));
411418
}
@@ -414,6 +421,7 @@ static void buildLoopOptimizerPipeline(FunctionPassManager &FPM, PassBuilder *PB
414421
}
415422
{
416423
LoopPassManager LPM;
424+
LPM.addPass(BeforeLoopSimplificationMarkerPass());
417425
if (O.getSpeedupLevel() >= 2) {
418426
LPM.addPass(LoopInstSimplifyPass());
419427
LPM.addPass(LoopIdiomRecognizePass());
@@ -424,12 +432,15 @@ static void buildLoopOptimizerPipeline(FunctionPassManager &FPM, PassBuilder *PB
424432
LPM.addPass(LoopFullUnrollPass());
425433
}
426434
invokeLoopOptimizerEndCallbacks(LPM, PB, O);
435+
LPM.addPass(AfterLoopSimplificationMarkerPass());
427436
//We don't know if the loop end callbacks support MSSA
428437
FPM.addPass(createFunctionToLoopPassAdaptor(std::move(LPM), /*UseMemorySSA = */false));
429438
}
439+
FPM.addPass(AfterLoopOptimizationMarkerPass());
430440
}
431441

432442
static void buildScalarOptimizerPipeline(FunctionPassManager &FPM, PassBuilder *PB, OptimizationLevel O, const OptimizationOptions &options) JL_NOTSAFEPOINT {
443+
FPM.addPass(BeforeScalarOptimizationMarkerPass());
433444
if (O.getSpeedupLevel() >= 2) {
434445
JULIA_PASS(FPM.addPass(AllocOptPass()));
435446
FPM.addPass(SROAPass());
@@ -460,9 +471,11 @@ static void buildScalarOptimizerPipeline(FunctionPassManager &FPM, PassBuilder *
460471
FPM.addPass(LoopDistributePass());
461472
}
462473
invokeScalarOptimizerCallbacks(FPM, PB, O);
474+
FPM.addPass(AfterScalarOptimizationMarkerPass());
463475
}
464476

465477
static void buildVectorPipeline(FunctionPassManager &FPM, PassBuilder *PB, OptimizationLevel O, const OptimizationOptions &options) JL_NOTSAFEPOINT {
478+
FPM.addPass(BeforeVectorizationMarkerPass());
466479
//TODO look into loop vectorize options
467480
FPM.addPass(InjectTLIMappings());
468481
FPM.addPass(LoopVectorizePass());
@@ -477,9 +490,11 @@ static void buildVectorPipeline(FunctionPassManager &FPM, PassBuilder *PB, Optim
477490
// This unroll will unroll vectorized loops
478491
// as well as loops that we tried but failed to vectorize
479492
FPM.addPass(LoopUnrollPass(LoopUnrollOptions(O.getSpeedupLevel(), /*OnlyWhenForced = */ false, /*ForgetSCEV = */false)));
493+
FPM.addPass(AfterVectorizationMarkerPass());
480494
}
481495

482496
static void buildIntrinsicLoweringPipeline(ModulePassManager &MPM, PassBuilder *PB, OptimizationLevel O, const OptimizationOptions &options) JL_NOTSAFEPOINT {
497+
MPM.addPass(BeforeIntrinsicLoweringMarkerPass());
483498
if (options.lower_intrinsics) {
484499
//TODO barrier pass?
485500
{
@@ -510,9 +525,11 @@ static void buildIntrinsicLoweringPipeline(ModulePassManager &MPM, PassBuilder *
510525
} else {
511526
JULIA_PASS(MPM.addPass(RemoveNIPass()));
512527
}
528+
MPM.addPass(AfterIntrinsicLoweringMarkerPass());
513529
}
514530

515531
static void buildCleanupPipeline(ModulePassManager &MPM, PassBuilder *PB, OptimizationLevel O, const OptimizationOptions &options) JL_NOTSAFEPOINT {
532+
MPM.addPass(BeforeCleanupMarkerPass());
516533
if (O.getSpeedupLevel() >= 2) {
517534
FunctionPassManager FPM;
518535
JULIA_PASS(FPM.addPass(CombineMulAddPass()));
@@ -530,9 +547,11 @@ static void buildCleanupPipeline(ModulePassManager &MPM, PassBuilder *PB, Optimi
530547
}
531548
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
532549
}
550+
MPM.addPass(AfterCleanupMarkerPass());
533551
}
534552

535553
static void buildPipeline(ModulePassManager &MPM, PassBuilder *PB, OptimizationLevel O, const OptimizationOptions &options) JL_NOTSAFEPOINT {
554+
MPM.addPass(BeforeOptimizationMarkerPass());
536555
buildEarlySimplificationPipeline(MPM, PB, O, options);
537556
MPM.addPass(AlwaysInlinerPass());
538557
buildEarlyOptimizerPipeline(MPM, PB, O, options);
@@ -549,40 +568,41 @@ static void buildPipeline(ModulePassManager &MPM, PassBuilder *PB, OptimizationL
549568
}
550569
buildIntrinsicLoweringPipeline(MPM, PB, O, options);
551570
buildCleanupPipeline(MPM, PB, O, options);
571+
MPM.addPass(AfterOptimizationMarkerPass());
552572
}
553573

554574
#undef JULIA_PASS
555575

556576
namespace {
557-
auto createPIC(StandardInstrumentations &SI) JL_NOTSAFEPOINT {
558-
auto PIC = std::make_unique<PassInstrumentationCallbacks>();
577+
578+
void adjustPIC(PassInstrumentationCallbacks &PIC) JL_NOTSAFEPOINT {
559579
//Borrowed from LLVM PassBuilder.cpp:386
560580
#define MODULE_PASS(NAME, CLASS, CREATE_PASS) \
561-
PIC->addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
581+
PIC.addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
562582
#define MODULE_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS) \
563-
PIC->addClassToPassName(CLASS, NAME);
583+
PIC.addClassToPassName(CLASS, NAME);
564584
#define MODULE_ANALYSIS(NAME, CREATE_PASS) \
565-
PIC->addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
585+
PIC.addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
566586
#define FUNCTION_PASS(NAME, CLASS, CREATE_PASS) \
567-
PIC->addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
587+
PIC.addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
568588
#define FUNCTION_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS) \
569-
PIC->addClassToPassName(CLASS, NAME);
589+
PIC.addClassToPassName(CLASS, NAME);
570590
#define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \
571-
PIC->addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
591+
PIC.addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
572592
#define LOOPNEST_PASS(NAME, CREATE_PASS) \
573-
PIC->addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
593+
PIC.addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
574594
#define LOOP_PASS(NAME, CLASS, CREATE_PASS) \
575-
PIC->addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
595+
PIC.addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
576596
#define LOOP_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS) \
577-
PIC->addClassToPassName(CLASS, NAME);
597+
PIC.addClassToPassName(CLASS, NAME);
578598
#define LOOP_ANALYSIS(NAME, CREATE_PASS) \
579-
PIC->addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
599+
PIC.addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
580600
#define CGSCC_PASS(NAME, CLASS, CREATE_PASS) \
581-
PIC->addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
601+
PIC.addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
582602
#define CGSCC_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS) \
583-
PIC->addClassToPassName(CLASS, NAME);
603+
PIC.addClassToPassName(CLASS, NAME);
584604
#define CGSCC_ANALYSIS(NAME, CREATE_PASS) \
585-
PIC->addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
605+
PIC.addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
586606

587607
#include "llvm-julia-passes.inc"
588608

@@ -599,7 +619,32 @@ PIC->addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
599619
#undef CGSCC_PASS
600620
#undef CGSCC_PASS_WITH_PARAMS
601621
#undef CGSCC_ANALYSIS
622+
// Marker passes are set separately so that we don't export them by accident
623+
PIC.addClassToPassName("BeforeOptimizationMarkerPass", "BeforeOptimization");
624+
PIC.addClassToPassName("BeforeEarlySimplificationMarkerPass", "BeforeEarlySimplification");
625+
PIC.addClassToPassName("AfterEarlySimplificationMarkerPass", "AfterEarlySimplification");
626+
PIC.addClassToPassName("BeforeEarlyOptimizationMarkerPass", "BeforeEarlyOptimization");
627+
PIC.addClassToPassName("AfterEarlyOptimizationMarkerPass", "AfterEarlyOptimization");
628+
PIC.addClassToPassName("BeforeLoopOptimizationMarkerPass", "BeforeLoopOptimization");
629+
PIC.addClassToPassName("BeforeLICMMarkerPass", "BeforeLICM");
630+
PIC.addClassToPassName("AfterLICMMarkerPass", "AfterLICM");
631+
PIC.addClassToPassName("BeforeLoopSimplificationMarkerPass", "BeforeLoopSimplification");
632+
PIC.addClassToPassName("AfterLoopSimplificationMarkerPass", "AfterLoopSimplification");
633+
PIC.addClassToPassName("AfterLoopOptimizationMarkerPass", "AfterLoopOptimization");
634+
PIC.addClassToPassName("BeforeScalarOptimizationMarkerPass", "BeforeScalarOptimization");
635+
PIC.addClassToPassName("AfterScalarOptimizationMarkerPass", "AfterScalarOptimization");
636+
PIC.addClassToPassName("BeforeVectorizationMarkerPass", "BeforeVectorization");
637+
PIC.addClassToPassName("AfterVectorizationMarkerPass", "AfterVectorization");
638+
PIC.addClassToPassName("BeforeIntrinsicLoweringMarkerPass", "BeforeIntrinsicLowering");
639+
PIC.addClassToPassName("AfterIntrinsicLoweringMarkerPass", "AfterIntrinsicLowering");
640+
PIC.addClassToPassName("BeforeCleanupMarkerPass", "BeforeCleanup");
641+
PIC.addClassToPassName("AfterCleanupMarkerPass", "AfterCleanup");
642+
PIC.addClassToPassName("AfterOptimizationMarkerPass", "AfterOptimization");
643+
}
602644

645+
auto createPIC(StandardInstrumentations &SI) JL_NOTSAFEPOINT {
646+
auto PIC = std::make_unique<PassInstrumentationCallbacks>();
647+
adjustPIC(*PIC);
603648
SI.registerCallbacks(*PIC);
604649
return PIC;
605650
}
@@ -744,6 +789,10 @@ static llvm::Optional<std::pair<OptimizationLevel, OptimizationOptions>> parseJu
744789
// forward the callbacks to the respective passes. LLVM seems to prefer this,
745790
// and when we add the full pass builder having them directly will be helpful.
746791
void registerCallbacks(PassBuilder &PB) JL_NOTSAFEPOINT {
792+
auto PIC = PB.getPassInstrumentationCallbacks();
793+
if (PIC) {
794+
adjustPIC(*PIC);
795+
}
747796
PB.registerPipelineParsingCallback(
748797
[](StringRef Name, FunctionPassManager &PM,
749798
ArrayRef<PassBuilder::PipelineElement> InnerPipeline) {

0 commit comments

Comments
 (0)