Programming Language with LLVM

1 - Part 1 LLVM Basic constructs

1 - Introduction to LLVM IR and tools


将使用LLVM v14, 并主要涵盖通用部分
本课重点介绍AOT


clang download

clang++ -S -emit-llvm test.cpp

clang++ -o test test.ll
clang++ -o test.exe test.ll

# windows下安装llvm没有lli/llvm/llc
lli test.ll

使用@定义全局符号, LLVM的函数都是全局的, define是用来定义函数的

.bc文件内容是比特码


用ll生成本机汇编代码

2 - LLVM program structure Module

// src/EvaLLVM.h
/**
* Eva to LLVM IR compiler
*/

#ifndef EvaLLVM_h
#define EvaLLVM_h

#include <string>

#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h" 

using namespace std;

class EvaLLVM {
public:
    EvaLLVM() { moduleInit(); }

    /**
    * Executes a program
    */
    void exec(const std::string& program) {
        // 1. Parse the program
        // auto ast = parser->parser(program)

        // 2. Compile to LLVM IR
        // compile(ast);

        // Print generated code
        module->print(llvm::outs(), nullptr); // llvm�����������print

        // 3. Save module IR to file
        saveModuleToFile("./out.ll");
    }

private:

    /**
        Saves IR to file
    */
    void saveModuleToFile(const std::string& fileName) {
        std::error_code errorCode;
        llvm::raw_fd_ostream outLL(fileName, errorCode);
        module->print(outLL, nullptr);
    }

    /**
        Initialize the module
    */
    void moduleInit() {
        // Open a new context and module
        ctx = std::make_unique<llvm::LLVMContext>();
        module = std::make_unique<llvm::Module>("EvaLLVM", *ctx);

        // Create a new builder for the module
        builder = std::make_unique<llvm::IRBuilder<>>(*ctx);
    }

    /**
    * Global LLVM context
    * It owns and manages the core "global" data of LLVM's core
    * infrastructure, including the type and constant unique tables.
    */
    std::unique_ptr<llvm::LLVMContext> ctx;

    /**
        A Module instance is used to store all the information related to an
        LLVM module.Modules are the top level container of all other LLVM
        Intermediate Representation (IR)objects.Each module directly contains a
        list of globals variables,a list of functions,a list of libraries (or
        other modules)this module depends on,a symbol table,and various data
        about the target's characteristics.
        A module maintains a Globallist object that is used to hold all
        constant references to global variables in the module.When a global
        variable is destroyed,it should have no entries in the GlobalList.
        The main container class for the LLVM Intermediate Representation.
        */
    std::unique_ptr<llvm::Module> module;

    /**
    IR Builder.
    This provides a uniform API for creating instructions and inserting
    them into a basic block:either at the end of a BasicBlock,or at a
    specific iterator location in a block.
    */
    std::unique_ptr<llvm::IRBuilder<>> builder;
};

#endif
// src/eva-llvm.cpp
/**
    Eva LLVM executable
*/

#include "./EvaLLVM.h"

int main(int argc, char const* argv[]) {
     /**
        Program to execute
     */
    std::string program = R"(42)";

     /**
        Compiler instance
     */
    EvaLLVM vm;

    /**
        Generate LLVM IR
    */
    vm.exec(program);
    return 0;
}
clang++ -o eva-llvm `llvm-config --cxxflags --ldflags --system-libs --libs core` eva-llvm.cpp

3 - Basic numbers Main function

# src/compile-run.sh
# compile
clang++ -o eva-llvm `llvm-config --cxxflags --ldflags --system-libs --libs core` eva-llvm.cpp
# run
./eva-llvm
# execute generated IR
lli ./out.ll

main函数缺失

//src/EvaLLVM.h
/**
* Eva to LLVM IR compiler
*/

#ifndef EvaLLVM_h
#define EvaLLVM_h

#include <iostream>
#include <string>

#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"

using namespace std;

class EvaLLVM {
public:
    EvaLLVM() { moduleInit(); }

    /**
    * Executes a program
    */
    void exec(const std::string &program) {
        // 1. Parse the program
        // auto ast = parser->parser(program)

        // 2. Compile to LLVM IR
        // compile(ast);
        compile();

        // Print generated code
        module->print(llvm::outs(), nullptr);

        std::cout << "\n";
        /// 
    }

private:
    /**
      * Compiles an expression.
      */
    void compile(/* ast */) {
        // 1. Create main function:
        fn = createFunction("main", llvm::FunctionType::get(
                /* return type */ builder->getInt32Ty(),
                /* vararg可变长度 */ false
        ));
        // 2. Compile main body:
        auto result = gen(/* ast */);
        // Cast to i32 to return from main:
        auto i32Result =
                builder->CreateIntCast(result, builder->getInt32Ty(), true);
        builder->CreateRet(i32Result);
    }

    /**
     * Main compile loop.
     */
    llvm::Value *gen(/* exp */) {
        return builder->getInt32(42);
    }

    /**
     * Creates a function
     */
    llvm::Function *createFunction(const std::string &fnName,
                                   llvm::FunctionType *fnType) {
        // Function prototype might already be defined:
        auto fn = module->getFunction(fnName);
        // If not,allocate the function:
        if (fn == nullptr) {
            fn = createFunctionProto(fnName, fnType);
        }

        createFunctionBlock(fn);
        return fn;
    }

    /**
     * Creates function prototype (defines the function,but not the body)
     */
    llvm::Function *createFunctionProto(const std::string &fnName,
                                        llvm::FunctionType *fnType) {
        auto fn = llvm::Function::Create(fnType, llvm::Function::ExternalLinkage, fnName, *module);
        verifyFunction(*fn);
        return fn;
    }

    /**
     * Creates function block.
     */
    void createFunctionBlock(llvm::Function *fn) {
        auto entry = createBB("entry", fn);
        // 代码传递到入口
        builder->SetInsertPoint(entry);
    }

    /**
     * Creates a basic block.If the fn is passed,the block is
     * automatically appended to the parent function.Otherwise,
     * the block should later be appended manually via
     * fn->getBasicBlockList().push_back(block);
     */
    llvm::BasicBlock *createBB(std::string name, llvm::Function *fn = nullptr) {
        return llvm::BasicBlock::Create(*ctx, name, fn);
    }

    ///

    /**
     * Currently compiling function.
     */
    llvm::Function *fn;

    ///
};

#endif

# compile
clang++ -o eva-llvm `llvm-config --cxxflags --ldflags --system-libs --libs core` eva-llvm.cpp
# run
./eva-llvm
# execute generated IR
lli ./out.ll
# print result
echo $?
printf "\n"

4 - Strings Printf operator


 上一篇
技术大牛成长课,从0到1带你手写一个数据库系统(23年新课) 技术大牛成长课,从0到1带你手写一个数据库系统(23年新课)
第1章 课程介绍及学习指南 第2章 手写数据库系统的必要性,及系统的整体介绍2-1 为什么研究并实现一款数据库 2-2 我们希望设计一款怎样的数据库 2-3 如何快速实现原型,选择合适的语言 2-4 复杂项目的持续演进要点 2-5 学习提前
2023-12-30
下一篇 
【Rust】关于Rust数据科学和机器学习的介绍! 【Rust】关于Rust数据科学和机器学习的介绍!
创建项目 cargo new linfa_test cd linfa_test cargo add linfa cargo add linfa_trees # ndarray ~= python中的numpy cargo add ndarr
2023-12-29
  目录