Skip to content

Commit 3d2527e

Browse files
authored
[Kaleidoscope] Switch to the new PassManager, revisited. (#72324)
Rollforward of #69032, which was reverted in [63d19cf](63d19cf). New: implemented changes in #69032 (comment). Given the PassBuilder is how we expect users to register passes, the tutorial should reflect that.
1 parent 4ac5b0d commit 3d2527e

File tree

5 files changed

+213
-95
lines changed

5 files changed

+213
-95
lines changed

llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl04.rst

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,6 @@ use, in the form of "passes".
9494
LLVM Optimization Passes
9595
========================
9696

97-
.. warning::
98-
99-
Due to the transition to the new PassManager infrastructure this tutorial
100-
is based on ``llvm::legacy::FunctionPassManager`` which can be found in
101-
`LegacyPassManager.h <https://llvm.org/doxygen/classllvm_1_1legacy_1_1FunctionPassManager.html>`_.
102-
For the purpose of the this tutorial the above should be used until
103-
the pass manager transition is complete.
104-
10597
LLVM provides many optimization passes, which do many different sorts of
10698
things and have different tradeoffs. Unlike other systems, LLVM doesn't
10799
hold to the mistaken notion that one set of optimizations is right for
@@ -127,44 +119,80 @@ in. If we wanted to make a "static Kaleidoscope compiler", we would use
127119
exactly the code we have now, except that we would defer running the
128120
optimizer until the entire file has been parsed.
129121

122+
In addition to the distinction between function and module passes, passes can be
123+
divided into transform and analysis passes. Transform passes mutate the IR, and
124+
analysis passes compute information that other passes can use. In order to add
125+
a transform pass, all analysis passes it depends upon must be registered in
126+
advance.
127+
130128
In order to get per-function optimizations going, we need to set up a
131129
`FunctionPassManager <../../WritingAnLLVMPass.html#what-passmanager-doesr>`_ to hold
132130
and organize the LLVM optimizations that we want to run. Once we have
133131
that, we can add a set of optimizations to run. We'll need a new
134132
FunctionPassManager for each module that we want to optimize, so we'll
135-
write a function to create and initialize both the module and pass manager
136-
for us:
133+
add to a function created in the previous chapter (``InitializeModule()``):
137134

138135
.. code-block:: c++
139136

140-
void InitializeModuleAndPassManager(void) {
137+
void InitializeModuleAndManagers(void) {
141138
// Open a new context and module.
142-
TheModule = std::make_unique<Module>("my cool jit", *TheContext);
139+
TheContext = std::make_unique<LLVMContext>();
140+
TheModule = std::make_unique<Module>("KaleidoscopeJIT", *TheContext);
141+
TheModule->setDataLayout(TheJIT->getDataLayout());
143142
144-
// Create a new pass manager attached to it.
145-
TheFPM = std::make_unique<legacy::FunctionPassManager>(TheModule.get());
143+
// Create a new builder for the module.
144+
Builder = std::make_unique<IRBuilder<>>(*TheContext);
145+
146+
// Create new pass and analysis managers.
147+
TheFPM = std::make_unique<FunctionPassManager>();
148+
TheLAM = std::make_unique<LoopAnalysisManager>();
149+
TheFAM = std::make_unique<FunctionAnalysisManager>();
150+
TheCGAM = std::make_unique<CGSCCAnalysisManager>();
151+
TheMAM = std::make_unique<ModuleAnalysisManager>();
152+
ThePIC = std::make_unique<PassInstrumentationCallbacks>();
153+
TheSI = std::make_unique<StandardInstrumentations>(*TheContext,
154+
/*DebugLogging*/ true);
155+
TheSI->registerCallbacks(*ThePIC, TheMAM.get());
156+
...
146157
158+
After initializing the global module ``TheModule`` and the FunctionPassManager,
159+
we need to initialize other parts of the framework. The four AnalysisManagers
160+
allow us to add analysis passes that run across the four levels of the IR
161+
hierarchy. PassInstrumentationCallbacks and StandardInstrumentations are
162+
required for the pass instrumentation framework, which allows developers to
163+
customize what happens between passes.
164+
165+
Once these managers are set up, we use a series of "addPass" calls to add a
166+
bunch of LLVM transform passes:
167+
168+
.. code-block:: c++
169+
170+
// Add transform passes.
147171
// Do simple "peephole" optimizations and bit-twiddling optzns.
148-
TheFPM->add(createInstructionCombiningPass());
172+
TheFPM->addPass(InstCombinePass());
149173
// Reassociate expressions.
150-
TheFPM->add(createReassociatePass());
174+
TheFPM->addPass(ReassociatePass());
151175
// Eliminate Common SubExpressions.
152-
TheFPM->add(createGVNPass());
176+
TheFPM->addPass(GVNPass());
153177
// Simplify the control flow graph (deleting unreachable blocks, etc).
154-
TheFPM->add(createCFGSimplificationPass());
155-
156-
TheFPM->doInitialization();
157-
}
158-
159-
This code initializes the global module ``TheModule``, and the function pass
160-
manager ``TheFPM``, which is attached to ``TheModule``. Once the pass manager is
161-
set up, we use a series of "add" calls to add a bunch of LLVM passes.
178+
TheFPM->addPass(SimplifyCFGPass());
162179

163180
In this case, we choose to add four optimization passes.
164181
The passes we choose here are a pretty standard set
165182
of "cleanup" optimizations that are useful for a wide variety of code. I won't
166183
delve into what they do but, believe me, they are a good starting place :).
167184

185+
Next, we register the analysis passes used by the transform passes.
186+
187+
.. code-block:: c++
188+
189+
// Register analysis passes used in these transform passes.
190+
PassBuilder PB;
191+
PB.registerModuleAnalyses(*TheMAM);
192+
PB.registerFunctionAnalyses(*TheFAM);
193+
PB.crossRegisterProxies(*TheLAM, *TheFAM, *TheCGAM, *TheMAM);
194+
}
195+
168196
Once the PassManager is set up, we need to make use of it. We do this by
169197
running it after our newly created function is constructed (in
170198
``FunctionAST::codegen()``), but before it is returned to the client:
@@ -179,7 +207,7 @@ running it after our newly created function is constructed (in
179207
verifyFunction(*TheFunction);
180208
181209
// Optimize the function.
182-
TheFPM->run(*TheFunction);
210+
TheFPM->run(*TheFunction, *TheFAM);
183211
184212
return TheFunction;
185213
}

llvm/examples/Kaleidoscope/Chapter4/toy.cpp

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,19 @@
77
#include "llvm/IR/Function.h"
88
#include "llvm/IR/IRBuilder.h"
99
#include "llvm/IR/LLVMContext.h"
10-
#include "llvm/IR/LegacyPassManager.h"
1110
#include "llvm/IR/Module.h"
11+
#include "llvm/IR/PassManager.h"
1212
#include "llvm/IR/Type.h"
1313
#include "llvm/IR/Verifier.h"
14+
#include "llvm/Passes/PassBuilder.h"
15+
#include "llvm/Passes/StandardInstrumentations.h"
1416
#include "llvm/Support/TargetSelect.h"
1517
#include "llvm/Target/TargetMachine.h"
1618
#include "llvm/Transforms/InstCombine/InstCombine.h"
1719
#include "llvm/Transforms/Scalar.h"
1820
#include "llvm/Transforms/Scalar/GVN.h"
21+
#include "llvm/Transforms/Scalar/Reassociate.h"
22+
#include "llvm/Transforms/Scalar/SimplifyCFG.h"
1923
#include <algorithm>
2024
#include <cassert>
2125
#include <cctype>
@@ -413,8 +417,14 @@ static std::unique_ptr<LLVMContext> TheContext;
413417
static std::unique_ptr<Module> TheModule;
414418
static std::unique_ptr<IRBuilder<>> Builder;
415419
static std::map<std::string, Value *> NamedValues;
416-
static std::unique_ptr<legacy::FunctionPassManager> TheFPM;
417420
static std::unique_ptr<KaleidoscopeJIT> TheJIT;
421+
static std::unique_ptr<FunctionPassManager> TheFPM;
422+
static std::unique_ptr<LoopAnalysisManager> TheLAM;
423+
static std::unique_ptr<FunctionAnalysisManager> TheFAM;
424+
static std::unique_ptr<CGSCCAnalysisManager> TheCGAM;
425+
static std::unique_ptr<ModuleAnalysisManager> TheMAM;
426+
static std::unique_ptr<PassInstrumentationCallbacks> ThePIC;
427+
static std::unique_ptr<StandardInstrumentations> TheSI;
418428
static std::map<std::string, std::unique_ptr<PrototypeAST>> FunctionProtos;
419429
static ExitOnError ExitOnErr;
420430

@@ -535,7 +545,7 @@ Function *FunctionAST::codegen() {
535545
verifyFunction(*TheFunction);
536546

537547
// Run the optimizer on the function.
538-
TheFPM->run(*TheFunction);
548+
TheFPM->run(*TheFunction, *TheFAM);
539549

540550
return TheFunction;
541551
}
@@ -549,28 +559,41 @@ Function *FunctionAST::codegen() {
549559
// Top-Level parsing and JIT Driver
550560
//===----------------------------------------------------------------------===//
551561

552-
static void InitializeModuleAndPassManager() {
562+
static void InitializeModuleAndManagers() {
553563
// Open a new context and module.
554564
TheContext = std::make_unique<LLVMContext>();
555-
TheModule = std::make_unique<Module>("my cool jit", *TheContext);
565+
TheModule = std::make_unique<Module>("KaleidoscopeJIT", *TheContext);
556566
TheModule->setDataLayout(TheJIT->getDataLayout());
557567

558568
// Create a new builder for the module.
559569
Builder = std::make_unique<IRBuilder<>>(*TheContext);
560570

561-
// Create a new pass manager attached to it.
562-
TheFPM = std::make_unique<legacy::FunctionPassManager>(TheModule.get());
563-
571+
// Create new pass and analysis managers.
572+
TheFPM = std::make_unique<FunctionPassManager>();
573+
TheLAM = std::make_unique<LoopAnalysisManager>();
574+
TheFAM = std::make_unique<FunctionAnalysisManager>();
575+
TheCGAM = std::make_unique<CGSCCAnalysisManager>();
576+
TheMAM = std::make_unique<ModuleAnalysisManager>();
577+
ThePIC = std::make_unique<PassInstrumentationCallbacks>();
578+
TheSI = std::make_unique<StandardInstrumentations>(*TheContext,
579+
/*DebugLogging*/ true);
580+
TheSI->registerCallbacks(*ThePIC, TheMAM.get());
581+
582+
// Add transform passes.
564583
// Do simple "peephole" optimizations and bit-twiddling optzns.
565-
TheFPM->add(createInstructionCombiningPass());
584+
TheFPM->addPass(InstCombinePass());
566585
// Reassociate expressions.
567-
TheFPM->add(createReassociatePass());
586+
TheFPM->addPass(ReassociatePass());
568587
// Eliminate Common SubExpressions.
569-
TheFPM->add(createGVNPass());
588+
TheFPM->addPass(GVNPass());
570589
// Simplify the control flow graph (deleting unreachable blocks, etc).
571-
TheFPM->add(createCFGSimplificationPass());
590+
TheFPM->addPass(SimplifyCFGPass());
572591

573-
TheFPM->doInitialization();
592+
// Register analysis passes used in these transform passes.
593+
PassBuilder PB;
594+
PB.registerModuleAnalyses(*TheMAM);
595+
PB.registerFunctionAnalyses(*TheFAM);
596+
PB.crossRegisterProxies(*TheLAM, *TheFAM, *TheCGAM, *TheMAM);
574597
}
575598

576599
static void HandleDefinition() {
@@ -581,7 +604,7 @@ static void HandleDefinition() {
581604
fprintf(stderr, "\n");
582605
ExitOnErr(TheJIT->addModule(
583606
ThreadSafeModule(std::move(TheModule), std::move(TheContext))));
584-
InitializeModuleAndPassManager();
607+
InitializeModuleAndManagers();
585608
}
586609
} else {
587610
// Skip token for error recovery.
@@ -613,7 +636,7 @@ static void HandleTopLevelExpression() {
613636

614637
auto TSM = ThreadSafeModule(std::move(TheModule), std::move(TheContext));
615638
ExitOnErr(TheJIT->addModule(std::move(TSM), RT));
616-
InitializeModuleAndPassManager();
639+
InitializeModuleAndManagers();
617640

618641
// Search the JIT for the __anon_expr symbol.
619642
auto ExprSymbol = ExitOnErr(TheJIT->lookup("__anon_expr"));
@@ -699,7 +722,7 @@ int main() {
699722

700723
TheJIT = ExitOnErr(KaleidoscopeJIT::Create());
701724

702-
InitializeModuleAndPassManager();
725+
InitializeModuleAndManagers();
703726

704727
// Run the main "interpreter loop" now.
705728
MainLoop();

llvm/examples/Kaleidoscope/Chapter5/toy.cpp

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,19 @@
88
#include "llvm/IR/IRBuilder.h"
99
#include "llvm/IR/Instructions.h"
1010
#include "llvm/IR/LLVMContext.h"
11-
#include "llvm/IR/LegacyPassManager.h"
1211
#include "llvm/IR/Module.h"
12+
#include "llvm/IR/PassManager.h"
1313
#include "llvm/IR/Type.h"
1414
#include "llvm/IR/Verifier.h"
15+
#include "llvm/Passes/PassBuilder.h"
16+
#include "llvm/Passes/StandardInstrumentations.h"
1517
#include "llvm/Support/TargetSelect.h"
1618
#include "llvm/Target/TargetMachine.h"
1719
#include "llvm/Transforms/InstCombine/InstCombine.h"
1820
#include "llvm/Transforms/Scalar.h"
1921
#include "llvm/Transforms/Scalar/GVN.h"
22+
#include "llvm/Transforms/Scalar/Reassociate.h"
23+
#include "llvm/Transforms/Scalar/SimplifyCFG.h"
2024
#include <algorithm>
2125
#include <cassert>
2226
#include <cctype>
@@ -540,8 +544,14 @@ static std::unique_ptr<LLVMContext> TheContext;
540544
static std::unique_ptr<Module> TheModule;
541545
static std::unique_ptr<IRBuilder<>> Builder;
542546
static std::map<std::string, Value *> NamedValues;
543-
static std::unique_ptr<legacy::FunctionPassManager> TheFPM;
544547
static std::unique_ptr<KaleidoscopeJIT> TheJIT;
548+
static std::unique_ptr<FunctionPassManager> TheFPM;
549+
static std::unique_ptr<LoopAnalysisManager> TheLAM;
550+
static std::unique_ptr<FunctionAnalysisManager> TheFAM;
551+
static std::unique_ptr<CGSCCAnalysisManager> TheCGAM;
552+
static std::unique_ptr<ModuleAnalysisManager> TheMAM;
553+
static std::unique_ptr<PassInstrumentationCallbacks> ThePIC;
554+
static std::unique_ptr<StandardInstrumentations> TheSI;
545555
static std::map<std::string, std::unique_ptr<PrototypeAST>> FunctionProtos;
546556
static ExitOnError ExitOnErr;
547557

@@ -809,7 +819,7 @@ Function *FunctionAST::codegen() {
809819
verifyFunction(*TheFunction);
810820

811821
// Run the optimizer on the function.
812-
TheFPM->run(*TheFunction);
822+
TheFPM->run(*TheFunction, *TheFAM);
813823

814824
return TheFunction;
815825
}
@@ -823,28 +833,41 @@ Function *FunctionAST::codegen() {
823833
// Top-Level parsing and JIT Driver
824834
//===----------------------------------------------------------------------===//
825835

826-
static void InitializeModuleAndPassManager() {
827-
// Open a new module.
836+
static void InitializeModuleAndManagers() {
837+
// Open a new context and module.
828838
TheContext = std::make_unique<LLVMContext>();
829-
TheModule = std::make_unique<Module>("my cool jit", *TheContext);
839+
TheModule = std::make_unique<Module>("KaleidoscopeJIT", *TheContext);
830840
TheModule->setDataLayout(TheJIT->getDataLayout());
831841

832842
// Create a new builder for the module.
833843
Builder = std::make_unique<IRBuilder<>>(*TheContext);
834844

835-
// Create a new pass manager attached to it.
836-
TheFPM = std::make_unique<legacy::FunctionPassManager>(TheModule.get());
837-
845+
// Create new pass and analysis managers.
846+
TheFPM = std::make_unique<FunctionPassManager>();
847+
TheLAM = std::make_unique<LoopAnalysisManager>();
848+
TheFAM = std::make_unique<FunctionAnalysisManager>();
849+
TheCGAM = std::make_unique<CGSCCAnalysisManager>();
850+
TheMAM = std::make_unique<ModuleAnalysisManager>();
851+
ThePIC = std::make_unique<PassInstrumentationCallbacks>();
852+
TheSI = std::make_unique<StandardInstrumentations>(*TheContext,
853+
/*DebugLogging*/ true);
854+
TheSI->registerCallbacks(*ThePIC, TheMAM.get());
855+
856+
// Add transform passes.
838857
// Do simple "peephole" optimizations and bit-twiddling optzns.
839-
TheFPM->add(createInstructionCombiningPass());
858+
TheFPM->addPass(InstCombinePass());
840859
// Reassociate expressions.
841-
TheFPM->add(createReassociatePass());
860+
TheFPM->addPass(ReassociatePass());
842861
// Eliminate Common SubExpressions.
843-
TheFPM->add(createGVNPass());
862+
TheFPM->addPass(GVNPass());
844863
// Simplify the control flow graph (deleting unreachable blocks, etc).
845-
TheFPM->add(createCFGSimplificationPass());
864+
TheFPM->addPass(SimplifyCFGPass());
846865

847-
TheFPM->doInitialization();
866+
// Register analysis passes used in these transform passes.
867+
PassBuilder PB;
868+
PB.registerModuleAnalyses(*TheMAM);
869+
PB.registerFunctionAnalyses(*TheFAM);
870+
PB.crossRegisterProxies(*TheLAM, *TheFAM, *TheCGAM, *TheMAM);
848871
}
849872

850873
static void HandleDefinition() {
@@ -855,7 +878,7 @@ static void HandleDefinition() {
855878
fprintf(stderr, "\n");
856879
ExitOnErr(TheJIT->addModule(
857880
ThreadSafeModule(std::move(TheModule), std::move(TheContext))));
858-
InitializeModuleAndPassManager();
881+
InitializeModuleAndManagers();
859882
}
860883
} else {
861884
// Skip token for error recovery.
@@ -887,7 +910,7 @@ static void HandleTopLevelExpression() {
887910

888911
auto TSM = ThreadSafeModule(std::move(TheModule), std::move(TheContext));
889912
ExitOnErr(TheJIT->addModule(std::move(TSM), RT));
890-
InitializeModuleAndPassManager();
913+
InitializeModuleAndManagers();
891914

892915
// Search the JIT for the __anon_expr symbol.
893916
auto ExprSymbol = ExitOnErr(TheJIT->lookup("__anon_expr"));
@@ -973,7 +996,7 @@ int main() {
973996

974997
TheJIT = ExitOnErr(KaleidoscopeJIT::Create());
975998

976-
InitializeModuleAndPassManager();
999+
InitializeModuleAndManagers();
9771000

9781001
// Run the main "interpreter loop" now.
9791002
MainLoop();

0 commit comments

Comments
 (0)