1 - Part 1 LLVM Basic constructs
1 - Introduction to LLVM IR and tools
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文件内容是比特码
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
//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"