- 自分のメモも兼ねて、LLVMのAPI(C++)についてまとめていきます。
- LLVM 3.5 での話です(古い
- 順次更新中
コンパイル
- Ubuntu, Debian の場合は
apt-get
で以下を実行 (コンパイルするだけならopt
とかいらないかな)
$ apt-get install clang-3.5 clang-3.5-doc libclang-common-3.5-dev libclang-3.5-dev libclang1-3.5 libclang1-3.5-dbg libllvm3.5v5 libllvm3.5-dbg lldb-3.5 llvm-3.5 llvm-3.5-dev llvm-3.5-doc llvm-3.5-examples llvm-3.5-runtime clang-modernize-3.5 clang-format-3.5 python-clang-3.5 lldb-3.5-dev opt libedit-dev
-
source.cpp
をコンパイル (llvm-config のオプションは適当)
$ clang++-3.5 source.cpp -o source -std=c++11 `llvm-config-3.5 --system-libs --cppflags --ldflags --libs all`
関数生成
- こんな感じの、特に何もしない関数を作っていきます
int func(char *s) {
return 0;
}
プロトタイプ
- 戻り値が
int
, 引数がchar *
のfunc
という名前の関数のプロトタイプを作る
#include "llvm/Analysis/Passes.h"
#include "llvm/IR/Verifier.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Linker/Linker.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/PassManager.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_ostream.h"
llvm::LLVMContext &context(llvm::getGlobalContext());
llvm::IRBuilder<> builder(context);
llvm::Module *mod;
int main() {
// Moduleを作る
mod = new llvm::Module("sample", context);
// 関数の名前
std::string func_name = "func";
// 戻り値の型
llvm::Type *func_ret_type = builder.getInt32Ty();
// 引数の型
std::vector<llvm::Type *> func_args_type;
func_args_type.push_back(builder.getInt8Ty()->getPointerTo());
llvm::FunctionType *llvm_func_type =
llvm::FunctionType::get(func_ret_type, func_args_type, /*可変長引数=*/false);
llvm::Function *llvm_func = llvm::Function::Create(llvm_func_type, llvm::Function::ExternalLinkage, func_name, mod);
llvm_func->dump(); // 作った関数を表示 (LLVM-IR)
}
- ちょっと補足
-
builder.getXXX
で型を得られますが
builder.getInt8Ty()
builder.getInt16Ty()
builder.getIntNTy()
- とか、ある程度規則的に名前が付いているのでわかりやすいと思います
- あと、
getPointerTo
はその名の通り、その型のポインタを得られるようです - 8ビットの整数に限り、(多分よく使うから)
getInt8PtrTy()
ってのも用意されてます
// int *
builder.getInt32Ty()->getPointerTo()
// char **
builder.getInt8Ty()->getPointerTo()->getPointerTo()
builder.getInt8PtrTy()->getPointerTo()
本体
- 次に、関数の本体を作る
- 特に何もしないで、
0
を返してみます -
create_func_body
という関数を作ってその中で処理させましょうか
// 省略
void create_func_body(llvm::Function *llvm_func) {
llvm::BasicBlock *entry = llvm::BasicBlock::Create(
context,
"entry", // BasicBlockの名前
llvm_func);
builder.SetInsertPoint(entry); // entryの開始
builder.CreateRet( // return
llvm::ConstantInt::get(builder.getInt32Ty(), 0, true) // i32 0
);
}
- 一つのBasicBlockに、一つの return があります。
void
を返す?関数ならCreateRetVoid
を使います