如何添加优化器支持和添加JIT支持
可以看到,这里IRBuidler有帮我们做一些优化,例如常量折叠。
由于构建 LLVM IR 的所有调用都通过 LLVM IR 构建器,因此构建器本身会检查您调用它时是否存在持续的折叠机会。如果是这样,它只是进行常量折叠并返回常量而不是创建指令。
这个复杂一点的例子,BuilderIR在构建代码时,会将所有分析都与代码内联。
在这种情况下,乘法的 LHS 和 RHS 是相同的值。我们希望,生成一次,计算两次。像这样:tmp = x+3; result = tmp*tmp;x+3
但是,没有多少本地分析能够检测和纠正这一点。这需要两个转换:表达式的重新关联(使 add 的词法相同)和公共子表达式消除 (CSE) 以删除冗余的 add 指令。
幸运的是,LLVM 以“pass”的形式提供了广泛的优化供我们使用。
LLVM提供了许多的优化通道,这些通道做许多不同类型的优化并且有不同的权衡。LLVM并不认为一组优化适用于所有语言和所有情况。LLVM允许编译器使用者在不同情况下以不同顺序使用不同优化
see the How to Write a Pass document and the List of LLVM Passes.
为了进行每个功能的优化,我们需要设置一个 FunctionPassManager来保存和组织我们想要运行的 LLVM 优化。一旦我们有了它,我们就可以添加一组优化来运行。对于要优化的每个模块,我们都需要一个新的 FunctionPassManager,因此我们将编写一个函数来为我们创建和初始化module和pass管理器
添加相应的头文件和这些全局模块
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/InstCombine/InstCombine.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Scalar/GVN.h"
#include <algorithm>
#include <cassert>
#include <cctype>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <map>
#include <memory>
#include <string>
#include <vector>
using namespace llvm;
module和pass管理器
static void InitializeModuleAndPassManager() {
// Open a new context and module.
TheContext = std::make_unique<LLVMContext>();
TheModule = std::make_unique<Module>("my cool jit", *TheContext);
// TheModule->setDataLayout(TheJIT->getDataLayout());
// Create a new builder for the module.
Builder = std::make_unique<IRBuilder<>>(*TheContext);
// Create a new pass manager attached to it.
TheFPM = std::make_unique<legacy::FunctionPassManager>(TheModule.get());
//在这里选择添加四个优化pass,这里的pass是一组非常标准的“清理”优化
// Do simple "peephole" optimizations and bit-twiddling optzns.
/*
指令组合-将指令组合成更少、更简单的形式
指令。这一遍不修改CFG,并有趋势使
指令失效,因此后续的DCE传递是有用的。
这个pass包含如下内容:
%Y = add int 1, %X
%Z = add int 1, %Y
成:
%Z = add int 2, %X
*/
TheFPM->add(createInstructionCombiningPass());
// Reassociate expressions.
/*
重新关联-这个传递将交换表达式按照如下顺序进行重新关联
旨在促进更好的恒定传播,GCSE, LICM, PRE…
例如:4 + (x + 5) -> x + (4 + 5)
*/
TheFPM->add(createReassociatePass());
// Eliminate Common SubExpressions.
TheFPM->add(createGVNPass());
// Simplify the control flow graph (deleting unreachable blocks, etc).
/*
合并基本块,消除不可达块,简化终止符指令,转换开关到查找表,等等。
*/
TheFPM->add(createCFGSimplificationPass());
//Run all of the initializers for the function passes.
TheFPM->doInitialization();
}
在FunctionAST::codegen()使用优化pass
Function *FunctionAST::codegen() {
// First, check for an existing function from a previous 'extern' declaration.
Function *TheFunction = TheModule->getFunction(Proto->getName());
if (!TheFunction)
TheFunction = Proto->codegen();
if (!TheFunction)
return nullptr;
// Create a new basic block to start insertion into.
BasicBlock *BB = BasicBlock::Create(*TheContext, "entry", TheFunction);
Builder->SetInsertPoint(BB);
// Record the function arguments in the NamedValues map.
NamedValues.clear();
for (auto &Arg : TheFunction->args())
NamedValues[std::string(Arg.getName())] = &Arg;
if (Value *RetVal = Body->codegen()) {
// Finish off the function.
Builder->CreateRet(RetVal);
// Validate the generated code, checking for consistency.
verifyFunction(*TheFunction);
//优化这个function
TheFPM->run(*TheFunction);
return TheFunction;
}
// Error reading body, remove function.
TheFunction->eraseFromParent();
return nullptr;
}片
在主函数中使用InitializeModuleAndPassManager()
int main() {
InitializeNativeTarget();
InitializeNativeTargetAsmPrinter();
InitializeNativeTargetAsmParser();
// Install standard binary operators.
// 1 is lowest precedence.
BinopPrecedence['<'] = 10;
BinopPrecedence['+'] = 20;
BinopPrecedence['-'] = 20;
BinopPrecedence['*'] = 40; // highest.
// Prime the first token.
fprintf(stderr, "ready> ");
getNextToken();
TheJIT = ExitOnErr(KaleidoscopeJIT::Create());
InitializeModuleAndPassManager();
// Run the main "interpreter loop" now.
MainLoop();
return 0;
}
重新编译看看:
g++ -g -O3 toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core` -std=c++14 -o toy
可以看到达到了我们想要的优化效果,这个加法只定义了一次