LLVM Tutorial
chapter 1
- Kaleidoscope语言介绍
- 面向过程
- 编译器支持JIT
- 只有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;
}