【LLVM学习系列】(三)llvm新手教程(Toby Ho)P12-P13


欢迎来到《使用LLVM实现语言》教程的 第四章。前三章描述了一个简单语言的实现,并添加了生成LLVM IR的支持。本章将介绍两种新技术:为您的语言添加优化器支持,以及添加JIT编译器支持。这些增强将演示如何为Kaleidoscope语言获得优雅高效的代码。

4.1 Trivial Constant Folding (常量折叠)

我们在第三章的演示是简洁易懂且易于扩展的。然而,遗憾的是,它并不能生成出色的代码。然而,IRBuilder 在编译简单代码时确实为我们提供了明显的优化。

ready> def test(x) 1+2+x;
Read function definition:
define double @test(double %x) {
entry:
        %addtmp = fadd double 3.000000e+00, %x
        ret double %addtmp
}

常量折叠,如上所述,是一种非常常见且非常重要的优化技术:以至于许多语言实现者在其抽象语法树表示中都实现了常量折叠支持。

在 LLVM 中,你不需要在抽象语法树中实现这种支持。因为构建 LLVM IR 的所有调用都经过 LLVM IR 构建器,构建器本身在调用时会检查是否存在常量折叠的机会。如果存在,它会执行常量折叠,而不是创建指令。

好了,这很简单 😃. 在实践中,我们建议始终在生成代码时使用 IRBuilder。它在使用时没有“语法开销”(你不必在各处检查常量来使你的编译器变得丑陋),并且在某些情况下可以显著减少生成的 LLVM IR 的数量(特别是对于具有宏预处理器或大量使用常量的语言)。

另一方面,IRBuilder 的局限性在于它将所有分析内联到构建的代码中。如果考虑一个稍微复杂一些的示例:

ready> def test(x) (1+2+x)*(x+(1+2));
ready> Read function definition:
define double @test(double %x) {
entry:
        %addtmp = fadd double 3.000000e+00, %x
        %addtmp1 = fadd double %x, 3.000000e+00
        %multmp = fmul double %addtmp, %addtmp1
        ret double %multmp
}

在这种情况下,乘法的左右两侧是相同的值。我们真的希望看到这个生成“tmp = x+3; result = tmp*tmp;”而不是两次计算“x+3”。

很不幸,任何数量的局部分析都无法检测和纠正这个问题。这需要两个转换:表达式的重组(使 add 的词法相同)和公共子表达式消除(CSE)来删除多余的 add 指令。幸运的是,LLVM 提供了广泛的优化范围,你可以使用它们,形式上是“passes”。

4.2 LLVM Optimization Passes

LLVM提供了许多优化 passes,这些 passes 做着许多不同的事情,并且有不同的权衡。与其他系统不同,LLVM没有坚持一个错误的观念,即一个优化集适用于所有语言和所有情况。LLVM允许编译器实现者完全决定使用哪些优化、以什么顺序以及在什么情况下使用。

举个具体的例子,LLVM支持“整个模块”passes,它们尽可能地查看尽可能大的代码体(通常是整个文件,但如果在链接时运行,这可能是整个程序的一个实质性部分)。它还支持并包括“每个函数”passes,这些 passes 一次只对一个函数进行操作,而不查看其他函数。有关 passes 以及它们如何运行的更多信息,请参阅《如何编写一个 Pass 文档》《LLVM Pass 列表》

对于Kaleidoscope,我们目前是动态地逐个生成函数,因为用户输入它们。在这种设置中,我们不是在追求终极的优化体验,但我们也希望在可能的情况下尽早地捕获到简单和快速的东西。因此,我们将选择在用户输入函数时运行一些针对每个函数的优化。如果我们想要制作一个“静态的Kaleidoscope编译器”,我们将使用我们现在拥有的代码,只是将优化器的运行延迟到整个文件被解析完毕之后。

除了函数和模块 passes 之间的区别之外,passes 还可以分为 transform 和 analysis passes。Transform passes 变异 IR,而 analysis passes 计算其他 passes 可以使用的信息。为了添加 transform pass,必须预先注册它依赖的所有 analysis passes。

为了启动每个函数的优化,我们需要设置一个 FunctionPassManager 来保存和组织我们想要运行的LLVM优化。一旦我们有了这个,我们就可以添加一组要运行的优化。

4.2.1 What PassManager does

PassManager 类接受一系列的 passes,并确保它们的先决条件被正确设置,然后安排 passes 以高效地运行。所有运行 passes 的LLVM工具都使用 PassManager 来执行这些 passes。

PassManager 主要通过两种方式尝试减少一系列 passes 的执行时间:

  1. 共享分析结果。PassManager 试图尽可能避免重新计算分析结果。这意味着跟踪哪些分析结果已经可用,哪些分析结果被使无效,以及哪些分析结果需要被运行。工作的一个重要部分是 PassManager 跟踪所有分析结果的确切生命周期,使其能够在不再需要时释放分配给保存分析结果的内存。

  2. 在程序上管道化 passes 的执行。PassManager 试图通过将 passes 管道化在一起来获得更好的缓存和内存使用行为。这意味着,给定一系列连续的 FunctionPass,它将在第一个函数上执行所有 FunctionPass,然后在第二个函数上执行所有 FunctionPasses,依此类推,直到整个程序通过了 passes。

这改善了编译器的缓存行为,因为它每次只操作一个函数的LLVM程序表示,而不是遍历整个程序。它减少了编译器的内存消耗,因为例如,一次只需要计算一个支配者集。这也使得未来可以实现一些有趣的增强功能成为可能。

在开始之前,我们需要额外注意引用的llvm版本与文档的一致性。因为Toby Ho的视频录制于2020年,至今日llvm10.0的官方文档已经与当时有很大的差异,目前llvm10.0官方给出的文档已经改为配置文件形式了。为了尽快地对llvm有个整体地把握,本文选择了按照视频中给出的代码版本进行实现。编译过程确定会遇到版本不一致带来的接口使用问题,可参考Toby Ho的视频进行适配。

我们需要为我们想要优化的每个模块添加一个新的 FunctionPassManager,因此我们将为上一章创建的一个函数(InitializeModule())添加一些内容:

// top-level parsing and jit driver
static void InitializeModule(){
    //Open a new context and module
    TheContext = std::make_unique<LLVMContext>();
    // TheModule = std::make_unique<Module>("my cool jit", *TheContext);

    //create a new builder for the module
    Builder = std::make_unique<IRBuilder<>>(*TheContext);
}

void InitializeModuleAndManagers(void){
    // open a new context and module
    TheModule = std::make_unique<Module>("my cool jit", *TheContext);
   
}

初始化全局模块TheModule和FunctionPassManager后,我们需要初始化框架的其他部分。四个AnalysisManagers允许我们添加跨IR层次结构的四个级别的分析passes。PassInstrumentationCallbacks和StandardInstrumentations是pass仪器框架所必需的,它允许开发人员自定义passes之间发生的事情。

一旦这些管理器设置好了,我们就可以使用一系列“addPass”调用来添加一堆LLVM转换passes:

    // create new pass and analysis managers
    TheFPM = std::make_unique<legacy::FunctionPassManager>(TheModule.get());
    // add transform passes
    //do simple "peephole" optimizations and bit-twiddling optzns.
    TheFPM->add(createInstructionCombiningPass()); 

    // reassociate expression
    TheFPM->add(createReassociatePass());

    // eliminate common subexpressions
    TheFPM->add(createGVNPass()); 

    // simplifu the control flow graph (deletng unreachable blocks)
    TheFPM->add(createCFGSimplificationPass()); 

    TheFPM->doInitialization();

在这种情况下,我们选择添加四个优化 passes。我们在这里选择的 passes 是一组非常标准的“清理”优化 passes,适用于各种类型的代码。我不会详细解释它们的作用,但请相信我,它们是一个很好的起点 :)。

一旦 PassManager 设置完成,我们就需要利用它。我们通过在新创建的函数构建完成后(在 FunctionAST::codegen() 中)运行它,但在将其返回给客户端之前来实现这一点:

    if (RetVal){
        //finish off the function
        Builder->CreateRet(RetVal);

        //velidate the generated code, checking for consistency
        verifyFunction(*TheFunction);

        // optimize the function
        TheFPM->run(*TheFunciton);

        return TheFunction;
    }

4.3 编译命令

clang++ -g -O0 my-lang.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core  native` -o my-lang.bin

额外链接了llvm lib库 native,其中包含了以下子库:

-lLLVMX86Disassembler -lLLVMX86AsmParser -lLLVMX86CodeGen -lLLVMCFGuard -lLLVMGlobalISel -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMDebugInfoDWARF -lLLVMCodeGen -lLLVMTarget -lLLVMScalarOpts -lLLVMInstCombine -lLLVMAggressiveInstCombine -lLLVMTransformUtils -lLLVMBitWriter -lLLVMAnalysis -lLLVMProfileData -lLLVMX86Desc -lLLVMObject -lLLVMTextAPI -lLLVMMCParser -lLLVMBitReader -lLLVMCore -lLLVMRemarks -lLLVMBitstreamReader -lLLVMMCDisassembler -lLLVMMC -lLLVMDebugInfoCodeView -lLLVMDebugInfoMSF -lLLVMBinaryFormat -lLLVMX86Utils -lLLVMX86Info -lLLVMSupport -lLLVMDemangle

4.4 常量折叠优化效果

在这里插入图片描述

4.5 full code

#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/Module.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Verifier.h"
// #include "llvm/Passes/PassBuilder.h"
// #include "llvm/Passes/StandardInstrumentations.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 "llvm/Transforms/Scalar/Reassociate.h"
// #include "llvm/Transforms/Scalar/SimplifyCFG.h"
#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include <iostream>

using namespace llvm;
// using namespace llvm::orc;

enum Token{
    tok_eof=-1,

    tok_def=-2,
    tok_extern=-3,

    tok_identifier=-4,
    tok_number=-5
};

static std::unique_ptr<LLVMContext> TheContext;
static std::unique_ptr<IRBuilder<>> Builder;
static std::unique_ptr<Module> TheModule;

static std::unique_ptr<legacy::FunctionPassManager> TheFPM;
// static std::unique_ptr<LoopAnalysisManager> TheLAM;
// static std::unique_ptr<FunctionAnalysisManager> TheFAM;
// static std::unique_ptr<CGSCCAnalysisManager> TheCGAM;
// static std::unique_ptr<ModuleAnalysisManager> TheMAM;
// static std::unique_ptr<PassInstrumentationCallbacks> ThePIC;
// static std::unique_ptr<StandardInstrumentations> TheSI;
// static std::unique_ptr<KaleidoscopeJIT> TheJIT;

static std::map<std::string, Value *> NamedValues;

// 在编程语言的词法分析器(lexer)中,标识符通常是指用来标识变量、函数、类、模块等命名实体的字符序列。
static std::string IdentifierStr="";  // filled in if tok_identifier
static double NumVal;        // filled in if tok_number

// gettok
static int gettok(){
    static int LastChar = ' ';
    
    // skip space
    while(isspace(LastChar)){
        LastChar = getchar();
    }

    // get identifier
    if (isalpha(LastChar)){ // identifier: [a-zA-z][a-zA-Z0-9]*
        IdentifierStr = LastChar;
        while (isalnum(LastChar=getchar()))
            IdentifierStr += LastChar;

        if (IdentifierStr == "def")
            return tok_def;

        if (IdentifierStr == "extern")
            return tok_extern;

        return tok_identifier;
    }

    // get number
    if (isdigit(LastChar) || LastChar == '.'){ // Number: [0-9.]+
        std::string NumStr;
        do{
            NumStr += LastChar;
            LastChar = getchar();
        }while (isdigit(LastChar) || LastChar == '.');

        // 这行代码的功能是将一个字符串转换为双精度浮点数
        // .c_str() 方法将 NumStr 转换为以空字符结尾的 C 风格字符串(即以 const char* 的形式返回字符串的指针)
        // strtod() 是一个 C 标准库函数,用于将字符串转换为双精度浮点数。两个参数:第一个参数是要转换的字符串的指针,第二个参数是一个指向字符指针的指针,用于存储第一个无法转换的字符的地址。在这里第二个参数为 0,表示不需要获取无法转换的字符的地址。
        NumVal = strtod(NumStr.c_str(), 0);
        return tok_number;
    }

    // fill comments
    if(LastChar == '#'){
        // comments until end of line
        do
            LastChar = getchar();
        while(LastChar !=EOF && LastChar != '\n' && LastChar != '\r');

        if (LastChar != EOF)
        return gettok();
    }

    if (LastChar == EOF)
        return tok_eof;

    // otherwise, just return the character as its ascii value
    int ThisChar = LastChar;
    LastChar = getchar();
    return ThisChar;
}


// 2.2. The Abstract Syntax Tree (AST)

// ExprAST- base class
class ExprAST{
public:
    virtual ~ExprAST() = default;
    //基类中使用 = 0 表示纯虚函数。纯虚函数是在基类中声明但没有提供实现的虚函数。派生类必须提供实现以使基类变得可实例化
    virtual Value *codegen() = 0;
};

// NumberExprAST - for numeric literals like "1.0"
class NumberExprAST: public ExprAST{
    double Val;

public:
    NumberExprAST(double Val) : Val(Val){}
    Value *codegen() override;
};



class VariableExprAST: public ExprAST{
    std::string Name;

public: 
    VariableExprAST(const std::string &Name): Name(Name){}

    Value *codegen() override;
};


class BinaryExprAST: public ExprAST{ // 2+3
    char Op; // + - * \ < > 
    std::unique_ptr<ExprAST> LHS, RHS;

// smart pointer: c++ doesn't have garbage collector
public:
    BinaryExprAST(char Op, std::unique_ptr<ExprAST> LHS, std::unique_ptr<ExprAST> RHS):
    Op(Op), LHS(move(LHS)), RHS(move(RHS)){}

    Value *codegen() override;
};


class CallExprAST: public ExprAST{
    std::string Callee;
    std::vector<std::unique_ptr<ExprAST>> Args;

public:
    CallExprAST(const std::string &Callee, std::vector<std::unique_ptr<ExprAST>> Args):
    Callee(Callee), Args(move(Args)){}

    Value *codegen() override;
};


//Function Code Generation

class PrototypeAST{ // func(string xxx,)
    std::string Name;
    std::vector<std::string> Args;

public: 
    PrototypeAST(const std::string&Name, std::vector<std::string> Args):
    Name(Name), Args(move(Args)){}

    //getName() 后面加上 const 关键字的原因是为了表明这个成员函数是一个常量成员函数。在C++中,常量成员函数是指那些在函数体内不会修改类的成员变量的成员函数
    const std::string &getName() const{
        return Name;
    }

    Function *codegen();
};

class FunctionAST{ // def func(string xxx,){}
    std::unique_ptr<PrototypeAST> Proto;
    std::unique_ptr<ExprAST> Body;

public:
    FunctionAST(std::unique_ptr<PrototypeAST> Proto, std::unique_ptr<ExprAST> Body):
    Proto(move(Proto)), Body(move(Body)){}

    Function *codegen();
};

// Basic Expression Parsing

// LogError
std::unique_ptr<ExprAST> LogError(const char *Str){
    fprintf(stderr, "Error: %s\n", Str);
    return nullptr;
}

std::unique_ptr<PrototypeAST> LogErrorP(const char *Str){
    LogError(Str);
    return nullptr;
}

// CurTok/getNextToken - 提供一个简单的token缓冲区。CurTok是解析器当前正在查看的令牌。
// getNextToken从词法分析器中读取另一个令牌,并使用其结果更新CurTok。

static int CurTok;
static int getNextToken(){
    return CurTok = gettok();
}

static std::unique_ptr<ExprAST> ParseExpression();
// 这个例子吃掉了与产生式相对应的所有令牌,并返回词法分析器缓冲区中的下一个令牌
// 这是递归下降解析器的一种相当标准的做法。
// numberexpr ::=number
static std::unique_ptr<ExprAST> ParseNumberExpr(){
    auto Result  = std::make_unique<NumberExprAST>(NumVal);
    getNextToken(); // consume the number
    return move(Result);
}

// 括号运算符的定义如下:
// parenexpr ::= '(' expression')'
static std::unique_ptr<ExprAST> ParseParenExpr(){
    getNextToken(); // eat (
    auto V = ParseExpression();

    if (!V)
        return nullptr;
    if (CurTok != ')')
        return LogError("expected ')");

    getNextToken(); // eat ')'
    return V;
}

// 用于处理变量引用和函数调用
// IdentifierExpr 
// :: identifier
// :: identifier '(' expression* ')'
static std::unique_ptr<ExprAST> ParseIdentifierExpr() {
    std::string IdName = IdentifierStr;

    getNextToken(); // eat identifier

    if (CurTok == '('){ // call
        getNextToken(); // eat (
        std::vector<std::unique_ptr<ExprAST>> Args;
        while(true){
            auto Arg = ParseExpression();
            if (Arg)
                Args.push_back(move(Arg));
            else
                return nullptr;

            if (CurTok == ')'){
                getNextToken(); // eat )
                break;
            }else if (CurTok == ','){
                getNextToken(); // eat ,
                continue;
            }else{
                return LogError("Expected ')' or ',' in argument list");
            }
        }

        return std::make_unique<CallExprAST>(IdName, move(Args));

    }else{ // simple variable ref
        return std::make_unique<VariableExprAST>(IdName);
    }

}

// 已经把所有简单表达式解析逻辑放到了一起,可以定义一个辅助函数将它们封装到一个入口点中
// primary 

static std::unique_ptr<ExprAST> ParsePrimary(){
    switch(CurTok){
    default:
        return LogError("unknown token when expecting an expression");
    case tok_identifier:
        return ParseIdentifierExpr();
    case tok_number:
        return ParseNumberExpr();
    case '(':
        return ParseParenExpr();
    }
}

//  Binary Expression Parsing
// 2+2  I +( 2*3 )

static int GetTokPrecedence(){
    switch(CurTok){
        case '<':
        case '>':
            return 10;
        case '+':
        case '-':
            return 20;
        case '*':
        case '/':
            return 40;
        default:
            return -1;
    }
}


// binoprhs
// :: = ( + primary  ) *
static std::unique_ptr<ExprAST> ParseBinOpRHS(
    int ExprPrec, std::unique_ptr<ExprAST> LHS){
        while(true){
            int TokPrec = GetTokPrecedence(); // binop prec

            if (TokPrec < ExprPrec){
                return LHS;
            }else {
                int BinOp = CurTok;
                getNextToken(); // eat binop
                auto RHS = ParsePrimary();
                if (RHS){
                    int NextPrec = GetTokPrecedence();
                    if(TokPrec < NextPrec){ // + VS *
                        // ExprPrec is (TokPrec + RHS_Prec)
                        RHS = ParseBinOpRHS(TokPrec+1, move(RHS));
                        if (!RHS)
                            return nullptr;
                    }
                    LHS = std::make_unique<BinaryExprAST>(BinOp, move(LHS), move(RHS));
                } else {
                    return nullptr;
                }
            }
        }
}
 


 
// expression
static std::unique_ptr<ExprAST> ParseExpression(){
    auto LHS = ParsePrimary();
    if (LHS)
        return ParseBinOpRHS(0, move(LHS));
    else
        return nullptr;
}

// parse the rest

//prototype
// foobar(n m)
static std::unique_ptr<PrototypeAST> ParsePrototype(){
    if (CurTok != tok_identifier)
        return LogErrorP("Expected function name in prototype");

    std::string FnName = IdentifierStr;
    getNextToken();

    if (CurTok != '(')
        return LogErrorP("Expected '(' in prototype");

    // read args
    std::vector<std::string> ArgNames;
    while (getNextToken() == tok_identifier)
        ArgNames.push_back(IdentifierStr);
    if (CurTok != ')')
        return LogErrorP("Expected ')' in prototype");

    getNextToken();
    return std::make_unique<PrototypeAST>(FnName, move(ArgNames));
}

// parse definition, body
static std::unique_ptr<FunctionAST> ParseDefinition(){
    getNextToken();
    auto Proto = ParsePrototype();
    if (!Proto)
        return nullptr;
    
    if (auto E = ParseExpression())
        return std::make_unique<FunctionAST>(move(Proto), move(E));

    return nullptr;
}

// extern prototype
static std::unique_ptr<PrototypeAST> ParseExtern(){
    getNextToken(); // eat extern
    return ParsePrototype();
}

//topevelexpr expression
static std::unique_ptr<FunctionAST> ParseTopLevelExpr(){
    if (auto E = ParseExpression()){
        // make an anonymous proto
        auto Proto = std::make_unique<PrototypeAST>("__anon_expr", std::vector<std::string>());
        return std::make_unique<FunctionAST>(move(Proto), move(E));
    }
    return nullptr;
}

//===----------------------------------------------------------------------===//
// Code Generation
//===----------------------------------------------------------------------===//


Value *LogErrorV(const char *Str){
    LogError(Str);
    return nullptr;
}

Value *NumberExprAST::codegen(){
    return ConstantFP::get(*TheContext, APFloat(Val));
}


Value *VariableExprAST::codegen(){
    // look this variable up in the function
    Value *V = NamedValues[Name];
    std::cout<<"VariableExprAST::codegen - Name:   "<<Name<<std::endl;
    if (!V)
        LogErrorV("Unknown variable name");

    return V;
}


Value *BinaryExprAST::codegen(){
    Value *L = LHS->codegen();
    Value *R = RHS->codegen();
    if (!L || !R)
        return nullptr;

    switch(Op){
    case '+':
        return Builder->CreateFAdd(L, R, "addtmp");
    case '-':
        return Builder->CreateFAdd(L, R, "subtmp");
    case '*':
        return Builder->CreateFMul(L, R, "multmp");
    case '<':
        L = Builder->CreateFCmpULT(L, R, "cmptmp");
        return Builder->CreateUIToFP(L, Type::getDoubleTy(*TheContext), "booltmp");

    default:
        return LogErrorV("invalid binary operator");
    }
}


Value *CallExprAST::codegen(){
    // look up the name in the global module table
    Function *CalleeF = TheModule->getFunction(Callee);
    if (!CalleeF)
        return LogErrorV("Unknown function referenced");

    // if argument mismatch error
    if (CalleeF->arg_size() != Args.size())
        return LogErrorV("Incorrect # arguments passed");

    std::vector<Value *> ArgsV;
    for (unsigned i=0, e=Args.size();i!=e;++i){
        ArgsV.push_back(Args[i]->codegen());
        if (!ArgsV.back()) // the last element
            return nullptr;
    }

    return Builder->CreateCall(CalleeF, ArgsV, "calltmp");
}


Function *PrototypeAST::codegen(){
    // make the function type: double(double, double) etc.
    std::vector<Type *> Doubles(Args.size(),Type::getDoubleTy(*TheContext));

    FunctionType *FT = FunctionType::get(Type::getDoubleTy(*TheContext), Doubles, false);

    Function *F = Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get());


    //Set names for all arguments
    unsigned Idx = 0;
    for (auto &Arg: F->args())
        Arg.setName(Args[Idx++]);

    return F;
}


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;

    if (!TheFunction->empty())
        return (Function*)LogErrorV("Function cannot be redefined");


    // create a new bb 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;

    Value *RetVal = Body->codegen();
    if (RetVal){
        //finish off the function
        Builder->CreateRet(RetVal);

        //velidate the generated code, checking for consistency
        verifyFunction(*TheFunction);

        // optimize the function
        TheFPM->run(*TheFunction);//, *TheFAM);

        return TheFunction;
    }

    //error reading body ,remove funciton
    TheFunction->eraseFromParent();
    return nullptr;
}




// top-level parsing and jit driver
static void InitializeModule(){
    //Open a new context and module
    TheContext = std::make_unique<LLVMContext>();
    // TheModule = std::make_unique<Module>("my cool jit", *TheContext);

    //create a new builder for the module
    Builder = std::make_unique<IRBuilder<>>(*TheContext);
}

void InitializeModuleAndManagers(void){
    // open a new context and module
    TheModule = std::make_unique<Module>("my cool jit", *TheContext);
   
    // create new pass and analysis managers
    TheFPM = std::make_unique<legacy::FunctionPassManager>(TheModule.get());
    // add transform passes
    //do simple "peephole" optimizations and bit-twiddling optzns.
    TheFPM->add(createInstructionCombiningPass()); 

    // reassociate expression
    TheFPM->add(createReassociatePass());

    // eliminate common subexpressions
    TheFPM->add(createGVNPass()); 

    // simplifu the control flow graph (deletng unreachable blocks)
    TheFPM->add(createCFGSimplificationPass()); 

    TheFPM->doInitialization();
}


// void InitializeModuleAndManagers(void){
//     // open a new context and module
//     TheContext = std::make_unique<LLVMContext>();
//     TheModule = std::make_unique<Module>("KaleidoscopeJIT", *TheContext);
//     // TheModule->setDataLayout(TheJIT->getDataLayout());

//     // create a new builder for the module
//     Builder = std::make_unique<IRBuilder<>>(*TheContext);

//     // create new pass and analysis managers
//     TheFPM = std::make_unique<FunctionPassManager>();
//     TheLAM = std::make_unique<LoopAnalysisManager>();
//     TheFAM = std::make_unique<FunctionAnalysisManager>();
//     TheCGAM = std::make_unique<CGSCCAnalysisManager>();
//     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.
//     TheFPM->addPass(InstCombinePass()); //(createInstructionCombiningPass());//

//     // reassociate expression
//     TheFPM->addPass(ReassociatePass()); //(createReassociatePass());//

//     // eliminate common subexpressions
//     TheFPM->addPass(GVNPass()); //(createGVNPass());//

//     // simplifu the control flow graph (deletng unreachable blocks)
//     TheFPM->addPass(SimplifyCFGPass()); //(createCFGSimplificationPass());//

//     // TheFPM->doInitialization();

//     // // register analysis passes used in these transform passes
//     PassBuilder PB;
//     PB.registerModuleAnalyses(*TheMAM);
//     PB.registerFunctionAnalyses(*TheFAM);
//     PB.crossRegisterProxies(*TheLAM, *TheFAM, *TheCGAM, *TheMAM);
// }

static void HandleDefinition(){
    if(auto FnAST = ParseDefinition()){
        if (auto *FnIR = FnAST->codegen()){
            fprintf(stderr, "Read function definition: ");
            FnIR->print(errs());
            fprintf(stderr, "\n");
        }
    }
    else //skip token for error recovery
        getNextToken();
}

static void HandleExtern(){
    if (auto ProtoAST = ParseExtern()){
        if (auto *FnIR = ProtoAST->codegen()){
            fprintf(stderr, "Read extern: ");
            FnIR->print(errs());
            fprintf(stderr, "\n");
        }
    }
    else //skip token for error recovery
        getNextToken();
}

static void  HandleTopLevelExpression(){
    // evaluate a top-level expression into an anonymous function
    if (auto FnAST = ParseTopLevelExpr()){
        if (auto *FnIR = FnAST->codegen()){
            fprintf(stderr, "Read top-level expression: ");
            FnIR->print(errs());
            fprintf(stderr, "\n");

            // remove token for error recovery
            FnIR->eraseFromParent();
        }
    }
    else
        getNextToken();
}

// the driver
static void MainLoop(){
    while(true){
        fprintf(stderr, "read> ");
        switch(CurTok){
        case tok_eof:
            return;
        case ';': // ignore top-level semicolons
            getNextToken();
            break;
        case tok_def:
            HandleDefinition();
            break;
        case tok_extern:
            HandleExtern();
            break;
        default:
            HandleTopLevelExpression();
            break;
        }
    }
}


int main(){
    fprintf(stderr, "ready> ");

    InitializeModule();
    getNextToken();

    InitializeModuleAndManagers();
    MainLoop();

    // Print out all of the generated code.
    TheModule->print(errs(), nullptr);


    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值