Kaleidoscope

LLVM Tutorial

chapter 1

  • Kaleidoscope语言介绍
  1. 面向过程
  2. 编译器支持JIT
  3. 只有double数据类型
  • 用Kaleidoscope来计算Fibonacci数列
# Compute the x'th fibonacci number
def fib(x)
	if x < 3 then
		1
	else
		fib(x-1) + fib(x-2)
# This expression will compute the 40th number.
fib(40)
  • 图灵完备

chapter 3

LLVMContext和IRBuilder声明

LLVMContext TheContext;
IRBuilder<> Builder(TheContext);

Module使用:

std::unique_ptr<Module> TheModule;
TheModule = llvm::make_unique<Module>("my cool jit", TheContext);

llvm Makefile

LLVM_DIR = /usr/lib/llvm-3.9
CXXFLAGS = -g -std=c++11 -Wall -Wno-deprecated -Wno-unused -fpermissive -Wno-write-strings
CXXFLAGS += `${LLVM_DIR}/bin/llvm-config --cxxflags`
LDFLAGS += `${LLVM_DIR}/bin/llvm-config --ldflags`
LLVMLIBS = `${LLVM_DIR}/bin/llvm-config --libs`
LLVMLIBS += `${LLVM_DIR}/bin/llvm-config --system-libs`
CXX = clang++

all:
	${CXX} llvm_test.cpp ${CXXFLAGS} ${LDFLAGS} ${LLVMLIBS} -o llvm_test

llvm demo

  • 创建函数,调用函数,运算
#include <iostream>
#include "llvm/IR/Function.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/ADT/APFloat.h"
#include <memory>
#include <vector>
#include <map>

using namespace llvm;

llvm::LLVMContext TheContext;
IRBuilder<> Builder(TheContext);
std::unique_ptr<Module> TheModule;
std::map<std::string, Value *> NamedValues;

int main() {
    TheModule = make_unique<Module>("llvm_test", TheContext);
    std::vector<Type*> Doubles(2, Type::getDoubleTy(TheContext));  // 形参类型声明
    Doubles.push_back(Type::getInt32Ty(TheContext));

    FunctionType *FT = FunctionType::get(Type::getDoubleTy(TheContext),
            Doubles, false);    // 创建函数类型,param2不能为NULL
    Function *F = Function::Create(FT, Function::ExternalLinkage,
            "add", TheModule.get());    // 函数声明,函数名为add

    // 声明形参,给形参标注变量名
    std::vector<std::string> name_vec = {"a", "b", "c"};
    unsigned idx = 0;
    for (auto &arg : F->args())
        arg.setName(name_vec[idx++]);

    // 创建一个基本块,名字为entry,属于函数F
    BasicBlock *BB = BasicBlock::Create(TheContext, "entry", F);
    BasicBlock *BB1 = BasicBlock::Create(TheContext, "label1", F);
    Builder.SetInsertPoint(BB);  // 要先设置InsertPoint,才能生成IR

    for (auto &Arg : F->args())
        NamedValues[Arg.getName()] = &Arg;

    // 创建返回值,返回值为Float Constant 0.0
    Builder.CreateRet(ConstantFP::get(TheContext, APFloat(0.0)));

    Builder.SetInsertPoint(BB1);
    Builder.CreateRet(ConstantFP::get(TheContext, APFloat(1.0)));

    // 运算
    Value *addtmp = Builder.CreateFAdd(NamedValues["a"], NamedValues["b"], "");
    Builder.CreateFSub(NamedValues["a"], addtmp, "");
    Builder.CreateFMul(NamedValues["a"], NamedValues["b"], "");
    Builder.CreateFDiv(NamedValues["a"], NamedValues["b"], "");
    Value *L = Builder.CreateFCmpULT(NamedValues["a"], NamedValues["b"], "");   // float-point less than
    Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "");     // uitofp:unsigned int convert to float-point value

    // 打印生成的llvmIR
    TheModule->print(errs(), nullptr);  // errs() from Verifier.h
    return 0;
}

生成的llvm IR:

define double @add(double %a, double %b, i32 %c) {
entry:
  ret double 0.000000e+00

label1:                                           ; No predecessors!
  ret double 1.000000e+00
  %0 = fadd double %a, %b
  %1 = fsub double %a, %0
  %2 = fmul double %a, %b
  %3 = fdiv double %a, %b
  %4 = fcmp ult double %a, %b
  %5 = uitofp i1 %4 to double
}

  • if-then-else
#include <iostream>
#include "llvm/IR/Function.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/ADT/APFloat.h"
#include <memory>
#include <vector>
#include <map>

using namespace llvm;

llvm::LLVMContext TheContext;
IRBuilder<> Builder(TheContext);
std::unique_ptr<Module> TheModule;
std::map<std::string, Value *> NamedValues;

void llvm_test1() {
    TheModule = make_unique<Module>("llvm_test", TheContext);
    std::vector<Type*> Doubles(3, Type::getDoubleTy(TheContext));  // 形参类型声明

    FunctionType *FT = FunctionType::get(Type::getDoubleTy(TheContext),
            Doubles, false);    // 创建函数类型
    Function *F = Function::Create(FT, Function::ExternalLinkage,
            "func", TheModule.get());    // 函数声明,函数名为func

    // 声明形参,给形参标注变量名
    std::vector<std::string> name_vec = {"a", "b", "c"};
    unsigned idx = 0;
    for (auto &arg : F->args())
        arg.setName(name_vec[idx++]);

    for (auto &Arg : F->args())
        NamedValues[Arg.getName()] = &Arg;

    // 创建一个基本块,名字为entry,属于函数F
    BasicBlock *BB = BasicBlock::Create(TheContext, "entry", F);
    Builder.SetInsertPoint(BB);


    BasicBlock *then_block = BasicBlock::Create(TheContext, "then", F);
    BasicBlock *else_block = BasicBlock::Create(TheContext, "else", F);
    BasicBlock *merge_block = BasicBlock::Create(TheContext, "merge", F);

    Value *CondV = NamedValues["c"];
    CondV = Builder.CreateFCmpONE(ConstantFP::get(TheContext, APFloat(0.0)), CondV, "ifcond");
    Builder.CreateCondBr(CondV, then_block, else_block);

    Builder.SetInsertPoint(then_block);
    Value *then_val = Builder.CreateFAdd(NamedValues["a"], NamedValues["b"], "");
    Builder.CreateBr(merge_block);

    Builder.SetInsertPoint(else_block);
    Value *else_val = Builder.CreateFMul(NamedValues["a"], NamedValues["b"], "");
    Builder.CreateBr(merge_block);

    Builder.SetInsertPoint(merge_block);
    PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp");
    PN->addIncoming(then_val, then_block);
    PN->addIncoming(else_val, else_block);

    // 打印生成的llvmIR
    TheModule->print(errs(), nullptr);  // errs() from Verifier.h
}


int main() {
    llvm_test1();
}

生成的llvm ir

define double @func(double %a, double %b, double %c) {
entry:
  %ifcond = fcmp one double 0.000000e+00, %c
  br i1 %ifcond, label %then, label %else

then:                                             ; preds = %entry
  %0 = fadd double %a, %b
  br label %merge

else:                                             ; preds = %entry
  %1 = fmul double %a, %b
  br label %merge

merge:                                            ; preds = %else, %then
  %iftmp = phi double [ %0, %then ], [ %1, %else ]
}
  • alloca,load,store
#include <iostream>
#include "llvm/IR/Function.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/ADT/APFloat.h"
#include <memory>
#include <vector>
#include <map>

using namespace llvm;

llvm::LLVMContext TheContext;
IRBuilder<> Builder(TheContext);
std::unique_ptr<Module> TheModule;
std::map<std::string, AllocaInst*> NamedValues;

void llvm_test1() {
    TheModule = make_unique<Module>("llvm_test", TheContext);
    FunctionType *FT = FunctionType::get(Type::getVoidTy(TheContext), std::vector<Type*>(), false);
    Function *F = Function::Create(FT, Function::ExternalLinkage, "main", TheModule.get());
    BasicBlock *entry_block = BasicBlock::Create(TheContext, "entry", F);
    Builder.SetInsertPoint(entry_block);
    AllocaInst *a_ptr = Builder.CreateAlloca(Type::getDoubleTy(TheContext), nullptr, "a");
    AllocaInst *b_ptr = Builder.CreateAlloca(Type::getDoubleTy(TheContext), nullptr, "b");
    Builder.CreateStore(ConstantFP::get(TheContext, APFloat(1.0)), a_ptr);	// store 1.0 a_ptr
    Builder.CreateStore(ConstantFP::get(TheContext, APFloat(2.0)), b_ptr);	// store 2.0 b_ptr

    Value *tmp1 = Builder.CreateLoad(a_ptr, "");	// %1 = load a_ptr 
    Value *tmp2 = Builder.CreateLoad(b_ptr, "");  // %2 = load b_ptr

    Builder.CreateStore(tmp1, b_ptr);
    Builder.CreateStore(tmp2, a_ptr);

    AllocaInst *c_ptr = Builder.CreateAlloca(Type::getInt32Ty(TheContext), nullptr, "c");
    AllocaInst *d_ptr = Builder.CreateAlloca(Type::getInt32Ty(TheContext), nullptr, "d");
    Builder.CreateStore(ConstantInt::get(TheContext, APInt(32, 1)), c_ptr);   // APInt第一个参数为整数的位数
    Builder.CreateStore(ConstantInt::get(TheContext, APInt(32, 1)), d_ptr);
    Value *tmp3 = Builder.CreateLoad(c_ptr, "");
    Value *tmp4 = Builder.CreateLoad(d_ptr, "");
    Value *tmp5 = Builder.CreateAdd(tmp3, tmp4);
    Builder.CreateStore(tmp5, c_ptr);

    // 打印生成的llvmIR
    TheModule->print(errs(), nullptr);  // errs() from Verifier.h
}


int main() {
    llvm_test1();
}

输出的llvm ir

define void @main() {
entry:
  %a = alloca double
  %b = alloca double
  store double 1.000000e+00, double* %a
  store double 2.000000e+00, double* %b
  %0 = load double, double* %a
  %1 = load double, double* %b
  store double %0, double* %b
  store double %1, double* %a
  %c = alloca i32
  %d = alloca i32
  store i32 1, i32* %c
  store i32 1, i32* %d
  %2 = load i32, i32* %c
  %3 = load i32, i32* %d
  %4 = add i32 %2, %3
  store i32 %4, i32* %c
}
  • 将生成的llvm ir输出到一个文件中
 std::ofstream fs("output.txt");
std::ostream& os = fs;
 llvm::raw_os_ostream llvm_os(os);  // 需要#include "llvm/Support/raw_os_ostream"
TheModule->print(llvm_os, nullptr);
  • 显示"hello wrold!"
#include <iostream>
#include "llvm/IR/Function.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/Support/raw_os_ostream.h"
#include <memory>
#include <vector>
#include <map>
#include <fstream>
#include <ostream>
using namespace llvm;

llvm::LLVMContext TheContext;
IRBuilder<> Builder(TheContext);
std::unique_ptr<Module> TheModule = make_unique<Module>("llvm_test", TheContext);
std::map<std::string, AllocaInst*> NamedValues;

void llvm_test1() {
    //TheModule = make_unique<Module>("llvm_test", TheContext);
    FunctionType *FT = FunctionType::get(Type::getVoidTy(TheContext), std::vector<Type*>(), false);
    Function *F = Function::Create(FT, Function::ExternalLinkage, "main", TheModule.get());
    BasicBlock *entry_block = BasicBlock::Create(TheContext, "entry", F);
    Builder.SetInsertPoint(entry_block);
    Value* helloworld_str = Builder.CreateGlobalStringPtr("hello world!\n");  // 创建字符常量
    std::vector<Type*> puts_args; 
    puts_args.push_back(Builder.getInt8Ty()->getPointerTo());
    ArrayRef<Type*> args_ref(puts_args);
    FunctionType * puts_type = FunctionType::get(Builder.getInt32Ty(), args_ref, false);
    Function* puts_func = Function::Create(puts_type, Function::ExternalLinkage, "puts", TheModule.get());   //声明puts函数
    Builder.CreateCall(puts_func, helloworld_str); // 调用puts函数
    Builder.CreateRetVoid();	
    outs() << *TheModule;
}

int main() {
    llvm_test1();
}

生成的llvm ir,指令lli命令后直接运行

; ModuleID = 'llvm_test'
source_filename = "llvm_test"

@0 = private unnamed_addr constant [14 x i8] c"hello world!\0A\00"

define void @main() {
entry:
  %0 = call i32 @puts(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @0, i32 0, i32 0))
  ret void
}

declare i32 @puts(i8*)
  • StructType, getelementptr, bitcast(将类型A转换为类型B,转换的过程中不改变原本的数据,相当于只是改变读的方式)
#include <iostream>
#include "llvm/IR/Function.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/Support/raw_os_ostream.h"
#include <memory>
#include <vector>
#include <map>
#include <fstream>
#include <ostream>
using namespace llvm;

llvm::LLVMContext TheContext;
IRBuilder<> Builder(TheContext);
std::unique_ptr<Module> TheModule = make_unique<Module>("llvm_test", TheContext);
std::map<std::string, AllocaInst*> NamedValues;

void llvm_test1() {
    //TheModule = make_unique<Module>("llvm_test", TheContext);

    FunctionType *FT = FunctionType::get(Type::getVoidTy(TheContext), std::vector<Type*>(), false);
    Function *F = Function::Create(FT, Function::ExternalLinkage, "main", TheModule.get());
    BasicBlock *entry_block = BasicBlock::Create(TheContext, "entry", F);
    Builder.SetInsertPoint(entry_block);

    std::vector<Type*> types;
    types.push_back(Type::getDoubleTy(TheContext));
    types.push_back(Type::getInt32Ty(TheContext));
    StructType *st = StructType::create(TheContext, types, "A");
    AllocaInst *a_ptr = Builder.CreateAlloca(st);
    Value *dest = Builder.CreateGEP(a_ptr, ConstantInt::get(Type::getInt32Ty(TheContext), APInt(32, 1)));
    Builder.CreateBitCast(a_ptr, Type::getInt32Ty(TheContext)->getPointerTo());
    Builder.CreateRetVoid();
    outs() << *TheModule;
}


int main() {
    llvm_test1();
}

生成的llvm ir

; ModuleID = 'llvm_test'
source_filename = "llvm_test"

%A = type { double, i32 }

define void @main() {
entry:
  %0 = alloca %A
  %1 = getelementptr %A, %A* %0, i32 1
  %2 = bitcast %A* %0 to i32*
  ret void
}
  • 创建vable(创建未定义类型的指针)
void define_vtable() {
    StructType *foo = StructType::create(TheContext, "Foo");   // 注意一定要用create不能用get,否则后面无法调用setBody()
    StructType *vtable = StructType::create(TheContext, "vtable");
    auto *foo_ptr = foo->getPointerTo();

    std::vector<Type*> fields({vtable->getPointerTo(), Type::getInt32Ty(TheContext), Type::getInt32Ty(TheContext)});
    FunctionType *foo_create_default_type = FunctionType::get(Type::getVoidTy(TheContext), {foo_ptr},
                                                              false);
    Function *foo_create_default = Function::Create(foo_create_default_type, Function::ExternalLinkage,
                                                    "Foo_Create_Default", TheModule.get());
    func_map["Foo_Create_Default"] = foo_create_default;
    for (auto &arg : foo_create_default->args())
        arg.setName("this");
    Function *func_ptr = TheModule->getFunction("Foo_Create_Default");
    BasicBlock *entry_block = BasicBlock::Create(TheContext, "entry", func_ptr);
    Builder.SetInsertPoint(entry_block);


    Builder.CreateAlloca(foo->getPointerTo());
    //foo->setBody({Type::getInt32Ty(TheContext), Type::getInt32Ty(TheContext)});
    foo->setBody(fields);
    vtable->setBody({foo_create_default_type});
    outs() << *TheModule;
}

生成的llvm ir:

%Foo = type { %vtable*, i32, i32 }
%vtable = type { void (%Foo*) }

define void @Foo_Create_Default(%Foo* %this) {
entry:
  %0 = alloca %Foo*
}
  • 内置的printf函数使用
void print_test() {
    Function *print_func = get_printf(TheModule.get());
    FunctionType *func_type = FunctionType::get(Type::getVoidTy(TheContext), std::vector<Type*>(), false);
    Function *main = Function::Create(func_type, Function::ExternalLinkage, "main", TheModule.get());
    BasicBlock *entry_block = BasicBlock::Create(TheContext, "entry", main);
    Builder.SetInsertPoint(entry_block);
    Value *print_arg = ConstantInt::get(Type::getInt32Ty(TheContext), APInt(32, 1));
    Builder.CreateCall(print_func, {Builder.CreateGlobalStringPtr("in llvm fun, value = %d\n"), print_arg});
    Builder.CreateCall(print_func, {Builder.CreateGlobalStringPtr("%s\n"), Builder.CreateGlobalStringPtr("hello world!")});
    outs() << *TheModule;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值