[Kaleidoscope] Switch to the new PassManager. (#69032)

Using the new pass manager is more verbose; let me know if the tutorial
doesn't flow well with all the additions.
This commit is contained in:
Logikable 2023-10-18 09:25:50 -07:00 committed by GitHub
parent 47ed921985
commit 7b94744e77
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 282 additions and 91 deletions

View File

@ -94,14 +94,6 @@ use, in the form of "passes".
LLVM Optimization Passes LLVM Optimization Passes
======================== ========================
.. warning::
Due to the transition to the new PassManager infrastructure this tutorial
is based on ``llvm::legacy::FunctionPassManager`` which can be found in
`LegacyPassManager.h <https://llvm.org/doxygen/classllvm_1_1legacy_1_1FunctionPassManager.html>`_.
For the purpose of the this tutorial the above should be used until
the pass manager transition is complete.
LLVM provides many optimization passes, which do many different sorts of LLVM provides many optimization passes, which do many different sorts of
things and have different tradeoffs. Unlike other systems, LLVM doesn't things and have different tradeoffs. Unlike other systems, LLVM doesn't
hold to the mistaken notion that one set of optimizations is right for hold to the mistaken notion that one set of optimizations is right for
@ -127,44 +119,93 @@ in. If we wanted to make a "static Kaleidoscope compiler", we would use
exactly the code we have now, except that we would defer running the exactly the code we have now, except that we would defer running the
optimizer until the entire file has been parsed. optimizer until the entire file has been parsed.
In addition to the distinction between function and module passes, passes can be
divided into transform and analysis passes. Transform passes mutate the IR, and
analysis passes compute information that other passes can use. In order to add
a transform pass, all analysis passes it depends upon must be registered in
advance.
In order to get per-function optimizations going, we need to set up a In order to get per-function optimizations going, we need to set up a
`FunctionPassManager <../../WritingAnLLVMPass.html#what-passmanager-doesr>`_ to hold `FunctionPassManager <../../WritingAnLLVMPass.html#what-passmanager-doesr>`_ to hold
and organize the LLVM optimizations that we want to run. Once we have and organize the LLVM optimizations that we want to run. Once we have
that, we can add a set of optimizations to run. We'll need a new that, we can add a set of optimizations to run. We'll need a new
FunctionPassManager for each module that we want to optimize, so we'll FunctionPassManager for each module that we want to optimize, so we'll
write a function to create and initialize both the module and pass manager add to a function created in the previous chapter (``InitializeModule()``):
for us:
.. code-block:: c++ .. code-block:: c++
void InitializeModuleAndPassManager(void) { void InitializeModuleAndManagers(void) {
// Open a new context and module. // Open a new context and module.
TheModule = std::make_unique<Module>("my cool jit", *TheContext); TheContext = std::make_unique<LLVMContext>();
TheModule = std::make_unique<Module>("KaleidoscopeJIT", *TheContext);
TheModule->setDataLayout(TheJIT->getDataLayout());
// Create a new pass manager attached to it. // Create a new builder for the module.
TheFPM = std::make_unique<legacy::FunctionPassManager>(TheModule.get()); Builder = std::make_unique<IRBuilder<>>(*TheContext);
// Create new pass and analysis managers.
TheFPM = std::make_unique<FunctionPassManager>();
TheFAM = std::make_unique<FunctionAnalysisManager>();
TheMAM = std::make_unique<ModuleAnalysisManager>();
ThePIC = std::make_unique<PassInstrumentationCallbacks>();
TheSI = std::make_unique<StandardInstrumentations>(*TheContext,
/*DebugLogging*/ true);
TheSI->registerCallbacks(*ThePIC, TheMAM.get());
...
After initializing the global module ``TheModule`` and the FunctionPassManager,
we need to initialize other parts of the framework. The FunctionAnalysisManager
and ModuleAnalysisManager allow us to add analysis passes that run across the
function and the whole module, respectively. PassInstrumentationCallbacks
and StandardInstrumentations are required for the pass instrumentation
framework, which allows developers to customize what
happens between passes.
Once these managers are set up, we use a series of "addPass" calls to add a
bunch of LLVM transform passes:
.. code-block:: c++
// Add transform passes.
// Do simple "peephole" optimizations and bit-twiddling optzns. // Do simple "peephole" optimizations and bit-twiddling optzns.
TheFPM->add(createInstructionCombiningPass()); TheFPM->addPass(InstCombinePass());
// Reassociate expressions. // Reassociate expressions.
TheFPM->add(createReassociatePass()); TheFPM->addPass(ReassociatePass());
// Eliminate Common SubExpressions. // Eliminate Common SubExpressions.
TheFPM->add(createGVNPass()); TheFPM->addPass(GVNPass());
// Simplify the control flow graph (deleting unreachable blocks, etc). // Simplify the control flow graph (deleting unreachable blocks, etc).
TheFPM->add(createCFGSimplificationPass()); TheFPM->addPass(SimplifyCFGPass());
TheFPM->doInitialization();
}
This code initializes the global module ``TheModule``, and the function pass
manager ``TheFPM``, which is attached to ``TheModule``. Once the pass manager is
set up, we use a series of "add" calls to add a bunch of LLVM passes.
In this case, we choose to add four optimization passes. In this case, we choose to add four optimization passes.
The passes we choose here are a pretty standard set The passes we choose here are a pretty standard set
of "cleanup" optimizations that are useful for a wide variety of code. I won't of "cleanup" optimizations that are useful for a wide variety of code. I won't
delve into what they do but, believe me, they are a good starting place :). delve into what they do but, believe me, they are a good starting place :).
Next, we register the analysis passes used by the transform passes. This is
generally done using ``PassBuilder::register...Analyses()``, but we'll do it
manually to make clearer what's under the hood.
.. code-block:: c++
// Register analysis passes used in these transform passes.
TheFAM->registerPass([&] { return AAManager(); });
TheFAM->registerPass([&] { return AssumptionAnalysis(); });
TheFAM->registerPass([&] { return DominatorTreeAnalysis(); });
TheFAM->registerPass([&] { return LoopAnalysis(); });
TheFAM->registerPass([&] { return MemoryDependenceAnalysis(); });
TheFAM->registerPass([&] { return MemorySSAAnalysis(); });
TheFAM->registerPass([&] { return OptimizationRemarkEmitterAnalysis(); });
TheFAM->registerPass([&] {
return OuterAnalysisManagerProxy<ModuleAnalysisManager, Function>(*TheMAM);
});
TheFAM->registerPass(
[&] { return PassInstrumentationAnalysis(ThePIC.get()); });
TheFAM->registerPass([&] { return TargetIRAnalysis(); });
TheFAM->registerPass([&] { return TargetLibraryAnalysis(); });
TheMAM->registerPass([&] { return ProfileSummaryAnalysis(); });
}
Once the PassManager is set up, we need to make use of it. We do this by Once the PassManager is set up, we need to make use of it. We do this by
running it after our newly created function is constructed (in running it after our newly created function is constructed (in
``FunctionAST::codegen()``), but before it is returned to the client: ``FunctionAST::codegen()``), but before it is returned to the client:
@ -179,7 +220,7 @@ running it after our newly created function is constructed (in
verifyFunction(*TheFunction); verifyFunction(*TheFunction);
// Optimize the function. // Optimize the function.
TheFPM->run(*TheFunction); TheFPM->run(*TheFunction, *TheFAM);
return TheFunction; return TheFunction;
} }

View File

@ -1,21 +1,32 @@
#include "../include/KaleidoscopeJIT.h" #include "../include/KaleidoscopeJIT.h"
#include "llvm/ADT/APFloat.h" #include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLExtras.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/BasicAliasAnalysis.h"
#include "llvm/Analysis/MemoryDependenceAnalysis.h"
#include "llvm/Analysis/MemorySSA.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/IR/BasicBlock.h" #include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h" #include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h" #include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h" #include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h" #include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h" #include "llvm/IR/LLVMContext.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h" #include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/Type.h" #include "llvm/IR/Type.h"
#include "llvm/IR/Verifier.h" #include "llvm/IR/Verifier.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/StandardInstrumentations.h"
#include "llvm/Support/TargetSelect.h" #include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/InstCombine/InstCombine.h" #include "llvm/Transforms/InstCombine/InstCombine.h"
#include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Scalar/GVN.h" #include "llvm/Transforms/Scalar/GVN.h"
#include "llvm/Transforms/Scalar/Reassociate.h"
#include "llvm/Transforms/Scalar/SimplifyCFG.h"
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <cctype> #include <cctype>
@ -413,8 +424,12 @@ static std::unique_ptr<LLVMContext> TheContext;
static std::unique_ptr<Module> TheModule; static std::unique_ptr<Module> TheModule;
static std::unique_ptr<IRBuilder<>> Builder; static std::unique_ptr<IRBuilder<>> Builder;
static std::map<std::string, Value *> NamedValues; static std::map<std::string, Value *> NamedValues;
static std::unique_ptr<legacy::FunctionPassManager> TheFPM;
static std::unique_ptr<KaleidoscopeJIT> TheJIT; static std::unique_ptr<KaleidoscopeJIT> TheJIT;
static std::unique_ptr<FunctionPassManager> TheFPM;
static std::unique_ptr<FunctionAnalysisManager> TheFAM;
static std::unique_ptr<ModuleAnalysisManager> TheMAM;
static std::unique_ptr<PassInstrumentationCallbacks> ThePIC;
static std::unique_ptr<StandardInstrumentations> TheSI;
static std::map<std::string, std::unique_ptr<PrototypeAST>> FunctionProtos; static std::map<std::string, std::unique_ptr<PrototypeAST>> FunctionProtos;
static ExitOnError ExitOnErr; static ExitOnError ExitOnErr;
@ -535,7 +550,7 @@ Function *FunctionAST::codegen() {
verifyFunction(*TheFunction); verifyFunction(*TheFunction);
// Run the optimizer on the function. // Run the optimizer on the function.
TheFPM->run(*TheFunction); TheFPM->run(*TheFunction, *TheFAM);
return TheFunction; return TheFunction;
} }
@ -549,28 +564,51 @@ Function *FunctionAST::codegen() {
// Top-Level parsing and JIT Driver // Top-Level parsing and JIT Driver
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
static void InitializeModuleAndPassManager() { static void InitializeModuleAndManagers() {
// Open a new context and module. // Open a new context and module.
TheContext = std::make_unique<LLVMContext>(); TheContext = std::make_unique<LLVMContext>();
TheModule = std::make_unique<Module>("my cool jit", *TheContext); TheModule = std::make_unique<Module>("KaleidoscopeJIT", *TheContext);
TheModule->setDataLayout(TheJIT->getDataLayout()); TheModule->setDataLayout(TheJIT->getDataLayout());
// Create a new builder for the module. // Create a new builder for the module.
Builder = std::make_unique<IRBuilder<>>(*TheContext); Builder = std::make_unique<IRBuilder<>>(*TheContext);
// Create a new pass manager attached to it. // Create new pass and analysis managers.
TheFPM = std::make_unique<legacy::FunctionPassManager>(TheModule.get()); TheFPM = std::make_unique<FunctionPassManager>();
TheFAM = std::make_unique<FunctionAnalysisManager>();
TheMAM = std::make_unique<ModuleAnalysisManager>();
ThePIC = std::make_unique<PassInstrumentationCallbacks>();
TheSI = std::make_unique<StandardInstrumentations>(*TheContext,
/*DebugLogging*/ true);
TheSI->registerCallbacks(*ThePIC, TheMAM.get());
// Add transform passes.
// Do simple "peephole" optimizations and bit-twiddling optzns. // Do simple "peephole" optimizations and bit-twiddling optzns.
TheFPM->add(createInstructionCombiningPass()); TheFPM->addPass(InstCombinePass());
// Reassociate expressions. // Reassociate expressions.
TheFPM->add(createReassociatePass()); TheFPM->addPass(ReassociatePass());
// Eliminate Common SubExpressions. // Eliminate Common SubExpressions.
TheFPM->add(createGVNPass()); TheFPM->addPass(GVNPass());
// Simplify the control flow graph (deleting unreachable blocks, etc). // Simplify the control flow graph (deleting unreachable blocks, etc).
TheFPM->add(createCFGSimplificationPass()); TheFPM->addPass(SimplifyCFGPass());
TheFPM->doInitialization(); // Register analysis passes used in these transform passes.
TheFAM->registerPass([&] { return AAManager(); });
TheFAM->registerPass([&] { return AssumptionAnalysis(); });
TheFAM->registerPass([&] { return DominatorTreeAnalysis(); });
TheFAM->registerPass([&] { return LoopAnalysis(); });
TheFAM->registerPass([&] { return MemoryDependenceAnalysis(); });
TheFAM->registerPass([&] { return MemorySSAAnalysis(); });
TheFAM->registerPass([&] { return OptimizationRemarkEmitterAnalysis(); });
TheFAM->registerPass([&] {
return OuterAnalysisManagerProxy<ModuleAnalysisManager, Function>(*TheMAM);
});
TheFAM->registerPass(
[&] { return PassInstrumentationAnalysis(ThePIC.get()); });
TheFAM->registerPass([&] { return TargetIRAnalysis(); });
TheFAM->registerPass([&] { return TargetLibraryAnalysis(); });
TheMAM->registerPass([&] { return ProfileSummaryAnalysis(); });
} }
static void HandleDefinition() { static void HandleDefinition() {
@ -581,7 +619,7 @@ static void HandleDefinition() {
fprintf(stderr, "\n"); fprintf(stderr, "\n");
ExitOnErr(TheJIT->addModule( ExitOnErr(TheJIT->addModule(
ThreadSafeModule(std::move(TheModule), std::move(TheContext)))); ThreadSafeModule(std::move(TheModule), std::move(TheContext))));
InitializeModuleAndPassManager(); InitializeModuleAndManagers();
} }
} else { } else {
// Skip token for error recovery. // Skip token for error recovery.
@ -613,7 +651,7 @@ static void HandleTopLevelExpression() {
auto TSM = ThreadSafeModule(std::move(TheModule), std::move(TheContext)); auto TSM = ThreadSafeModule(std::move(TheModule), std::move(TheContext));
ExitOnErr(TheJIT->addModule(std::move(TSM), RT)); ExitOnErr(TheJIT->addModule(std::move(TSM), RT));
InitializeModuleAndPassManager(); InitializeModuleAndManagers();
// Search the JIT for the __anon_expr symbol. // Search the JIT for the __anon_expr symbol.
auto ExprSymbol = ExitOnErr(TheJIT->lookup("__anon_expr")); auto ExprSymbol = ExitOnErr(TheJIT->lookup("__anon_expr"));
@ -699,7 +737,7 @@ int main() {
TheJIT = ExitOnErr(KaleidoscopeJIT::Create()); TheJIT = ExitOnErr(KaleidoscopeJIT::Create());
InitializeModuleAndPassManager(); InitializeModuleAndManagers();
// Run the main "interpreter loop" now. // Run the main "interpreter loop" now.
MainLoop(); MainLoop();

View File

@ -1,6 +1,13 @@
#include "../include/KaleidoscopeJIT.h" #include "../include/KaleidoscopeJIT.h"
#include "llvm/ADT/APFloat.h" #include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLExtras.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/BasicAliasAnalysis.h"
#include "llvm/Analysis/MemoryDependenceAnalysis.h"
#include "llvm/Analysis/MemorySSA.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/IR/BasicBlock.h" #include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h" #include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h" #include "llvm/IR/DerivedTypes.h"
@ -8,15 +15,19 @@
#include "llvm/IR/IRBuilder.h" #include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h" #include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h" #include "llvm/IR/LLVMContext.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h" #include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/Type.h" #include "llvm/IR/Type.h"
#include "llvm/IR/Verifier.h" #include "llvm/IR/Verifier.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/StandardInstrumentations.h"
#include "llvm/Support/TargetSelect.h" #include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/InstCombine/InstCombine.h" #include "llvm/Transforms/InstCombine/InstCombine.h"
#include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Scalar/GVN.h" #include "llvm/Transforms/Scalar/GVN.h"
#include "llvm/Transforms/Scalar/Reassociate.h"
#include "llvm/Transforms/Scalar/SimplifyCFG.h"
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <cctype> #include <cctype>
@ -540,8 +551,12 @@ static std::unique_ptr<LLVMContext> TheContext;
static std::unique_ptr<Module> TheModule; static std::unique_ptr<Module> TheModule;
static std::unique_ptr<IRBuilder<>> Builder; static std::unique_ptr<IRBuilder<>> Builder;
static std::map<std::string, Value *> NamedValues; static std::map<std::string, Value *> NamedValues;
static std::unique_ptr<legacy::FunctionPassManager> TheFPM;
static std::unique_ptr<KaleidoscopeJIT> TheJIT; static std::unique_ptr<KaleidoscopeJIT> TheJIT;
static std::unique_ptr<FunctionPassManager> TheFPM;
static std::unique_ptr<FunctionAnalysisManager> TheFAM;
static std::unique_ptr<ModuleAnalysisManager> TheMAM;
static std::unique_ptr<PassInstrumentationCallbacks> ThePIC;
static std::unique_ptr<StandardInstrumentations> TheSI;
static std::map<std::string, std::unique_ptr<PrototypeAST>> FunctionProtos; static std::map<std::string, std::unique_ptr<PrototypeAST>> FunctionProtos;
static ExitOnError ExitOnErr; static ExitOnError ExitOnErr;
@ -809,7 +824,7 @@ Function *FunctionAST::codegen() {
verifyFunction(*TheFunction); verifyFunction(*TheFunction);
// Run the optimizer on the function. // Run the optimizer on the function.
TheFPM->run(*TheFunction); TheFPM->run(*TheFunction, *TheFAM);
return TheFunction; return TheFunction;
} }
@ -823,28 +838,51 @@ Function *FunctionAST::codegen() {
// Top-Level parsing and JIT Driver // Top-Level parsing and JIT Driver
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
static void InitializeModuleAndPassManager() { static void InitializeModuleAndManagers() {
// Open a new module. // Open a new context and module.
TheContext = std::make_unique<LLVMContext>(); TheContext = std::make_unique<LLVMContext>();
TheModule = std::make_unique<Module>("my cool jit", *TheContext); TheModule = std::make_unique<Module>("KaleidoscopeJIT", *TheContext);
TheModule->setDataLayout(TheJIT->getDataLayout()); TheModule->setDataLayout(TheJIT->getDataLayout());
// Create a new builder for the module. // Create a new builder for the module.
Builder = std::make_unique<IRBuilder<>>(*TheContext); Builder = std::make_unique<IRBuilder<>>(*TheContext);
// Create a new pass manager attached to it. // Create new pass and analysis managers.
TheFPM = std::make_unique<legacy::FunctionPassManager>(TheModule.get()); TheFPM = std::make_unique<FunctionPassManager>();
TheFAM = std::make_unique<FunctionAnalysisManager>();
TheMAM = std::make_unique<ModuleAnalysisManager>();
ThePIC = std::make_unique<PassInstrumentationCallbacks>();
TheSI = std::make_unique<StandardInstrumentations>(*TheContext,
/*DebugLogging*/ true);
TheSI->registerCallbacks(*ThePIC, TheMAM.get());
// Add transform passes.
// Do simple "peephole" optimizations and bit-twiddling optzns. // Do simple "peephole" optimizations and bit-twiddling optzns.
TheFPM->add(createInstructionCombiningPass()); TheFPM->addPass(InstCombinePass());
// Reassociate expressions. // Reassociate expressions.
TheFPM->add(createReassociatePass()); TheFPM->addPass(ReassociatePass());
// Eliminate Common SubExpressions. // Eliminate Common SubExpressions.
TheFPM->add(createGVNPass()); TheFPM->addPass(GVNPass());
// Simplify the control flow graph (deleting unreachable blocks, etc). // Simplify the control flow graph (deleting unreachable blocks, etc).
TheFPM->add(createCFGSimplificationPass()); TheFPM->addPass(SimplifyCFGPass());
TheFPM->doInitialization(); // Register analysis passes used in these transform passes.
TheFAM->registerPass([&] { return AAManager(); });
TheFAM->registerPass([&] { return AssumptionAnalysis(); });
TheFAM->registerPass([&] { return DominatorTreeAnalysis(); });
TheFAM->registerPass([&] { return LoopAnalysis(); });
TheFAM->registerPass([&] { return MemoryDependenceAnalysis(); });
TheFAM->registerPass([&] { return MemorySSAAnalysis(); });
TheFAM->registerPass([&] { return OptimizationRemarkEmitterAnalysis(); });
TheFAM->registerPass([&] {
return OuterAnalysisManagerProxy<ModuleAnalysisManager, Function>(*TheMAM);
});
TheFAM->registerPass(
[&] { return PassInstrumentationAnalysis(ThePIC.get()); });
TheFAM->registerPass([&] { return TargetIRAnalysis(); });
TheFAM->registerPass([&] { return TargetLibraryAnalysis(); });
TheMAM->registerPass([&] { return ProfileSummaryAnalysis(); });
} }
static void HandleDefinition() { static void HandleDefinition() {
@ -855,7 +893,7 @@ static void HandleDefinition() {
fprintf(stderr, "\n"); fprintf(stderr, "\n");
ExitOnErr(TheJIT->addModule( ExitOnErr(TheJIT->addModule(
ThreadSafeModule(std::move(TheModule), std::move(TheContext)))); ThreadSafeModule(std::move(TheModule), std::move(TheContext))));
InitializeModuleAndPassManager(); InitializeModuleAndManagers();
} }
} else { } else {
// Skip token for error recovery. // Skip token for error recovery.
@ -887,7 +925,7 @@ static void HandleTopLevelExpression() {
auto TSM = ThreadSafeModule(std::move(TheModule), std::move(TheContext)); auto TSM = ThreadSafeModule(std::move(TheModule), std::move(TheContext));
ExitOnErr(TheJIT->addModule(std::move(TSM), RT)); ExitOnErr(TheJIT->addModule(std::move(TSM), RT));
InitializeModuleAndPassManager(); InitializeModuleAndManagers();
// Search the JIT for the __anon_expr symbol. // Search the JIT for the __anon_expr symbol.
auto ExprSymbol = ExitOnErr(TheJIT->lookup("__anon_expr")); auto ExprSymbol = ExitOnErr(TheJIT->lookup("__anon_expr"));
@ -973,7 +1011,7 @@ int main() {
TheJIT = ExitOnErr(KaleidoscopeJIT::Create()); TheJIT = ExitOnErr(KaleidoscopeJIT::Create());
InitializeModuleAndPassManager(); InitializeModuleAndManagers();
// Run the main "interpreter loop" now. // Run the main "interpreter loop" now.
MainLoop(); MainLoop();

View File

@ -1,6 +1,13 @@
#include "../include/KaleidoscopeJIT.h" #include "../include/KaleidoscopeJIT.h"
#include "llvm/ADT/APFloat.h" #include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLExtras.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/BasicAliasAnalysis.h"
#include "llvm/Analysis/MemoryDependenceAnalysis.h"
#include "llvm/Analysis/MemorySSA.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/IR/BasicBlock.h" #include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h" #include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h" #include "llvm/IR/DerivedTypes.h"
@ -8,15 +15,19 @@
#include "llvm/IR/IRBuilder.h" #include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h" #include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h" #include "llvm/IR/LLVMContext.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h" #include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/Type.h" #include "llvm/IR/Type.h"
#include "llvm/IR/Verifier.h" #include "llvm/IR/Verifier.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/StandardInstrumentations.h"
#include "llvm/Support/TargetSelect.h" #include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/InstCombine/InstCombine.h" #include "llvm/Transforms/InstCombine/InstCombine.h"
#include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Scalar/GVN.h" #include "llvm/Transforms/Scalar/GVN.h"
#include "llvm/Transforms/Scalar/Reassociate.h"
#include "llvm/Transforms/Scalar/SimplifyCFG.h"
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <cctype> #include <cctype>
@ -632,8 +643,12 @@ static std::unique_ptr<LLVMContext> TheContext;
static std::unique_ptr<Module> TheModule; static std::unique_ptr<Module> TheModule;
static std::unique_ptr<IRBuilder<>> Builder; static std::unique_ptr<IRBuilder<>> Builder;
static std::map<std::string, Value *> NamedValues; static std::map<std::string, Value *> NamedValues;
static std::unique_ptr<legacy::FunctionPassManager> TheFPM;
static std::unique_ptr<KaleidoscopeJIT> TheJIT; static std::unique_ptr<KaleidoscopeJIT> TheJIT;
static std::unique_ptr<FunctionPassManager> TheFPM;
static std::unique_ptr<FunctionAnalysisManager> TheFAM;
static std::unique_ptr<ModuleAnalysisManager> TheMAM;
static std::unique_ptr<PassInstrumentationCallbacks> ThePIC;
static std::unique_ptr<StandardInstrumentations> TheSI;
static std::map<std::string, std::unique_ptr<PrototypeAST>> FunctionProtos; static std::map<std::string, std::unique_ptr<PrototypeAST>> FunctionProtos;
static ExitOnError ExitOnErr; static ExitOnError ExitOnErr;
@ -925,7 +940,7 @@ Function *FunctionAST::codegen() {
verifyFunction(*TheFunction); verifyFunction(*TheFunction);
// Run the optimizer on the function. // Run the optimizer on the function.
TheFPM->run(*TheFunction); TheFPM->run(*TheFunction, *TheFAM);
return TheFunction; return TheFunction;
} }
@ -942,28 +957,51 @@ Function *FunctionAST::codegen() {
// Top-Level parsing and JIT Driver // Top-Level parsing and JIT Driver
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
static void InitializeModuleAndPassManager() { static void InitializeModuleAndManagers() {
// Open a new module. // Open a new context and module.
TheContext = std::make_unique<LLVMContext>(); TheContext = std::make_unique<LLVMContext>();
TheModule = std::make_unique<Module>("my cool jit", *TheContext); TheModule = std::make_unique<Module>("KaleidoscopeJIT", *TheContext);
TheModule->setDataLayout(TheJIT->getDataLayout()); TheModule->setDataLayout(TheJIT->getDataLayout());
// Create a new builder for the module. // Create a new builder for the module.
Builder = std::make_unique<IRBuilder<>>(*TheContext); Builder = std::make_unique<IRBuilder<>>(*TheContext);
// Create a new pass manager attached to it. // Create new pass and analysis managers.
TheFPM = std::make_unique<legacy::FunctionPassManager>(TheModule.get()); TheFPM = std::make_unique<FunctionPassManager>();
TheFAM = std::make_unique<FunctionAnalysisManager>();
TheMAM = std::make_unique<ModuleAnalysisManager>();
ThePIC = std::make_unique<PassInstrumentationCallbacks>();
TheSI = std::make_unique<StandardInstrumentations>(*TheContext,
/*DebugLogging*/ true);
TheSI->registerCallbacks(*ThePIC, TheMAM.get());
// Add transform passes.
// Do simple "peephole" optimizations and bit-twiddling optzns. // Do simple "peephole" optimizations and bit-twiddling optzns.
TheFPM->add(createInstructionCombiningPass()); TheFPM->addPass(InstCombinePass());
// Reassociate expressions. // Reassociate expressions.
TheFPM->add(createReassociatePass()); TheFPM->addPass(ReassociatePass());
// Eliminate Common SubExpressions. // Eliminate Common SubExpressions.
TheFPM->add(createGVNPass()); TheFPM->addPass(GVNPass());
// Simplify the control flow graph (deleting unreachable blocks, etc). // Simplify the control flow graph (deleting unreachable blocks, etc).
TheFPM->add(createCFGSimplificationPass()); TheFPM->addPass(SimplifyCFGPass());
TheFPM->doInitialization(); // Register analysis passes used in these transform passes.
TheFAM->registerPass([&] { return AAManager(); });
TheFAM->registerPass([&] { return AssumptionAnalysis(); });
TheFAM->registerPass([&] { return DominatorTreeAnalysis(); });
TheFAM->registerPass([&] { return LoopAnalysis(); });
TheFAM->registerPass([&] { return MemoryDependenceAnalysis(); });
TheFAM->registerPass([&] { return MemorySSAAnalysis(); });
TheFAM->registerPass([&] { return OptimizationRemarkEmitterAnalysis(); });
TheFAM->registerPass([&] {
return OuterAnalysisManagerProxy<ModuleAnalysisManager, Function>(*TheMAM);
});
TheFAM->registerPass(
[&] { return PassInstrumentationAnalysis(ThePIC.get()); });
TheFAM->registerPass([&] { return TargetIRAnalysis(); });
TheFAM->registerPass([&] { return TargetLibraryAnalysis(); });
TheMAM->registerPass([&] { return ProfileSummaryAnalysis(); });
} }
static void HandleDefinition() { static void HandleDefinition() {
@ -974,7 +1012,7 @@ static void HandleDefinition() {
fprintf(stderr, "\n"); fprintf(stderr, "\n");
ExitOnErr(TheJIT->addModule( ExitOnErr(TheJIT->addModule(
ThreadSafeModule(std::move(TheModule), std::move(TheContext)))); ThreadSafeModule(std::move(TheModule), std::move(TheContext))));
InitializeModuleAndPassManager(); InitializeModuleAndManagers();
} }
} else { } else {
// Skip token for error recovery. // Skip token for error recovery.
@ -1006,7 +1044,7 @@ static void HandleTopLevelExpression() {
auto TSM = ThreadSafeModule(std::move(TheModule), std::move(TheContext)); auto TSM = ThreadSafeModule(std::move(TheModule), std::move(TheContext));
ExitOnErr(TheJIT->addModule(std::move(TSM), RT)); ExitOnErr(TheJIT->addModule(std::move(TSM), RT));
InitializeModuleAndPassManager(); InitializeModuleAndManagers();
// Search the JIT for the __anon_expr symbol. // Search the JIT for the __anon_expr symbol.
auto ExprSymbol = ExitOnErr(TheJIT->lookup("__anon_expr")); auto ExprSymbol = ExitOnErr(TheJIT->lookup("__anon_expr"));
@ -1092,7 +1130,7 @@ int main() {
TheJIT = ExitOnErr(KaleidoscopeJIT::Create()); TheJIT = ExitOnErr(KaleidoscopeJIT::Create());
InitializeModuleAndPassManager(); InitializeModuleAndManagers();
// Run the main "interpreter loop" now. // Run the main "interpreter loop" now.
MainLoop(); MainLoop();

View File

@ -1,6 +1,13 @@
#include "../include/KaleidoscopeJIT.h" #include "../include/KaleidoscopeJIT.h"
#include "llvm/ADT/APFloat.h" #include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLExtras.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/BasicAliasAnalysis.h"
#include "llvm/Analysis/MemoryDependenceAnalysis.h"
#include "llvm/Analysis/MemorySSA.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/IR/BasicBlock.h" #include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h" #include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h" #include "llvm/IR/DerivedTypes.h"
@ -8,15 +15,19 @@
#include "llvm/IR/IRBuilder.h" #include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h" #include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h" #include "llvm/IR/LLVMContext.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h" #include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/Type.h" #include "llvm/IR/Type.h"
#include "llvm/IR/Verifier.h" #include "llvm/IR/Verifier.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/StandardInstrumentations.h"
#include "llvm/Support/TargetSelect.h" #include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/InstCombine/InstCombine.h" #include "llvm/Transforms/InstCombine/InstCombine.h"
#include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Scalar/GVN.h" #include "llvm/Transforms/Scalar/GVN.h"
#include "llvm/Transforms/Scalar/Reassociate.h"
#include "llvm/Transforms/Scalar/SimplifyCFG.h"
#include "llvm/Transforms/Utils.h" #include "llvm/Transforms/Utils.h"
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
@ -705,8 +716,12 @@ static std::unique_ptr<LLVMContext> TheContext;
static std::unique_ptr<Module> TheModule; static std::unique_ptr<Module> TheModule;
static std::unique_ptr<IRBuilder<>> Builder; static std::unique_ptr<IRBuilder<>> Builder;
static std::map<std::string, AllocaInst *> NamedValues; static std::map<std::string, AllocaInst *> NamedValues;
static std::unique_ptr<legacy::FunctionPassManager> TheFPM;
static std::unique_ptr<KaleidoscopeJIT> TheJIT; static std::unique_ptr<KaleidoscopeJIT> TheJIT;
static std::unique_ptr<FunctionPassManager> TheFPM;
static std::unique_ptr<FunctionAnalysisManager> TheFAM;
static std::unique_ptr<ModuleAnalysisManager> TheMAM;
static std::unique_ptr<PassInstrumentationCallbacks> ThePIC;
static std::unique_ptr<StandardInstrumentations> TheSI;
static std::map<std::string, std::unique_ptr<PrototypeAST>> FunctionProtos; static std::map<std::string, std::unique_ptr<PrototypeAST>> FunctionProtos;
static ExitOnError ExitOnErr; static ExitOnError ExitOnErr;
@ -1094,7 +1109,7 @@ Function *FunctionAST::codegen() {
verifyFunction(*TheFunction); verifyFunction(*TheFunction);
// Run the optimizer on the function. // Run the optimizer on the function.
TheFPM->run(*TheFunction); TheFPM->run(*TheFunction, *TheFAM);
return TheFunction; return TheFunction;
} }
@ -1111,30 +1126,51 @@ Function *FunctionAST::codegen() {
// Top-Level parsing and JIT Driver // Top-Level parsing and JIT Driver
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
static void InitializeModuleAndPassManager() { static void InitializeModuleAndManagers() {
// Open a new module. // Open a new context and module.
TheContext = std::make_unique<LLVMContext>(); TheContext = std::make_unique<LLVMContext>();
TheModule = std::make_unique<Module>("my cool jit", *TheContext); TheModule = std::make_unique<Module>("KaleidoscopeJIT", *TheContext);
TheModule->setDataLayout(TheJIT->getDataLayout()); TheModule->setDataLayout(TheJIT->getDataLayout());
// Create a new builder for the module. // Create a new builder for the module.
Builder = std::make_unique<IRBuilder<>>(*TheContext); Builder = std::make_unique<IRBuilder<>>(*TheContext);
// Create a new pass manager attached to it. // Create new pass and analysis managers.
TheFPM = std::make_unique<legacy::FunctionPassManager>(TheModule.get()); TheFPM = std::make_unique<FunctionPassManager>();
TheFAM = std::make_unique<FunctionAnalysisManager>();
TheMAM = std::make_unique<ModuleAnalysisManager>();
ThePIC = std::make_unique<PassInstrumentationCallbacks>();
TheSI = std::make_unique<StandardInstrumentations>(*TheContext,
/*DebugLogging*/ true);
TheSI->registerCallbacks(*ThePIC, TheMAM.get());
// Promote allocas to registers. // Add transform passes.
TheFPM->add(createPromoteMemoryToRegisterPass());
// Do simple "peephole" optimizations and bit-twiddling optzns. // Do simple "peephole" optimizations and bit-twiddling optzns.
TheFPM->add(createInstructionCombiningPass()); TheFPM->addPass(InstCombinePass());
// Reassociate expressions. // Reassociate expressions.
TheFPM->add(createReassociatePass()); TheFPM->addPass(ReassociatePass());
// Eliminate Common SubExpressions. // Eliminate Common SubExpressions.
TheFPM->add(createGVNPass()); TheFPM->addPass(GVNPass());
// Simplify the control flow graph (deleting unreachable blocks, etc). // Simplify the control flow graph (deleting unreachable blocks, etc).
TheFPM->add(createCFGSimplificationPass()); TheFPM->addPass(SimplifyCFGPass());
TheFPM->doInitialization(); // Register analysis passes used in these transform passes.
TheFAM->registerPass([&] { return AAManager(); });
TheFAM->registerPass([&] { return AssumptionAnalysis(); });
TheFAM->registerPass([&] { return DominatorTreeAnalysis(); });
TheFAM->registerPass([&] { return LoopAnalysis(); });
TheFAM->registerPass([&] { return MemoryDependenceAnalysis(); });
TheFAM->registerPass([&] { return MemorySSAAnalysis(); });
TheFAM->registerPass([&] { return OptimizationRemarkEmitterAnalysis(); });
TheFAM->registerPass([&] {
return OuterAnalysisManagerProxy<ModuleAnalysisManager, Function>(*TheMAM);
});
TheFAM->registerPass(
[&] { return PassInstrumentationAnalysis(ThePIC.get()); });
TheFAM->registerPass([&] { return TargetIRAnalysis(); });
TheFAM->registerPass([&] { return TargetLibraryAnalysis(); });
TheMAM->registerPass([&] { return ProfileSummaryAnalysis(); });
} }
static void HandleDefinition() { static void HandleDefinition() {
@ -1145,7 +1181,7 @@ static void HandleDefinition() {
fprintf(stderr, "\n"); fprintf(stderr, "\n");
ExitOnErr(TheJIT->addModule( ExitOnErr(TheJIT->addModule(
ThreadSafeModule(std::move(TheModule), std::move(TheContext)))); ThreadSafeModule(std::move(TheModule), std::move(TheContext))));
InitializeModuleAndPassManager(); InitializeModuleAndManagers();
} }
} else { } else {
// Skip token for error recovery. // Skip token for error recovery.
@ -1177,7 +1213,7 @@ static void HandleTopLevelExpression() {
auto TSM = ThreadSafeModule(std::move(TheModule), std::move(TheContext)); auto TSM = ThreadSafeModule(std::move(TheModule), std::move(TheContext));
ExitOnErr(TheJIT->addModule(std::move(TSM), RT)); ExitOnErr(TheJIT->addModule(std::move(TSM), RT));
InitializeModuleAndPassManager(); InitializeModuleAndManagers();
// Search the JIT for the __anon_expr symbol. // Search the JIT for the __anon_expr symbol.
auto ExprSymbol = ExitOnErr(TheJIT->lookup("__anon_expr")); auto ExprSymbol = ExitOnErr(TheJIT->lookup("__anon_expr"));
@ -1264,7 +1300,7 @@ int main() {
TheJIT = ExitOnErr(KaleidoscopeJIT::Create()); TheJIT = ExitOnErr(KaleidoscopeJIT::Create());
InitializeModuleAndPassManager(); InitializeModuleAndManagers();
// Run the main "interpreter loop" now. // Run the main "interpreter loop" now.
MainLoop(); MainLoop();