llvm_tutorial :Kaleidoscope_toyComplier_OptPass

如何添加优化器支持和添加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

可以看到达到了我们想要的优化效果,这个加法只定义了一次
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值