LLVM-C API でやる hello world
対象読者
LLVM-C API 初学者
解決すること
LLVM-C API の簡単な実行例
内容
LLVM-C API を使った hello world をメモしておく。
C のコード。main.c として保存して下の makefile でコンパイル。
#include <llvm-c/Core.h>
#include <stdio.h>
LLVMModuleRef module = NULL;
LLVMBuilderRef builder = NULL;
LLVMValueRef gen_main() {
// main() definition
LLVMTypeRef type_main_params[] = {};
LLVMTypeRef type_main =
LLVMFunctionType(LLVMInt32Type(), type_main_params, 0, 0);
LLVMValueRef main = LLVMAddFunction(module, "main", type_main);
// add block in main
LLVMBasicBlockRef entry = LLVMAppendBasicBlock(main, "entry");
LLVMPositionBuilderAtEnd(builder, entry);
// declaration of int printf(char *fmt, ...);
LLVMTypeRef type_fmt =
LLVMPointerType(LLVMPointerType(LLVMInt8Type(), 0), 0);
LLVMTypeRef type_printf_params[] = {type_fmt};
LLVMTypeRef type_printf =
LLVMFunctionType(LLVMInt32Type(), type_printf_params, 1, 1);
LLVMValueRef func = LLVMAddFunction(module, "printf", type_printf);
// define "char *fmt = "hello world!\n";
LLVMValueRef fmt =
LLVMBuildGlobalStringPtr(builder, "hello world!\n", "hello_world");
// call printf()
LLVMValueRef args[] = {fmt};
LLVMBuildCall2(builder, type_printf, func, args, 1, "printf");
// return from main()
return LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 0, 0));
}
int main(int ac, char *av[]) {
// initilize llvm
module = LLVMModuleCreateWithName("my_module");
builder = LLVMCreateBuilder();
// generate main ir
gen_main();
// dump llvm ir to stdout
printf("%s", LLVMPrintModuleToString(module));
// dispose llvm builder and module
LLVMDisposeBuilder(builder);
LLVMDisposeModule(module);
return 0;
}makefile は以下の様に。
all: a.out
a.out: a.s
clang -no-pie -o $@ $^
a.s: a.ll
llc -o $@ $^
a.ll: main.out
./main.out > $@
main.out: main.c
gcc -g -o ${@:%.out=%.o} -c $^ `llvm-config --cflags` ;\
g++ -g ${@:%.out=%.o} -o $@ `llvm-config --cxxflags --ldflags --libs all`
clean:
rm -f *.s *.out *.o *.ll
.PHONY: clean
.PRECIOUS: %.ll %.s %.out
途中で出力される IR(a.ll)は、以下のように。
; ModuleID = 'my_module'
source_filename = "my_module"
@hello_world = private unnamed_addr constant [14 x i8] c"hello world!\0A\00", align 1
define i32 @main() {
entry:
%printf = call i32 (ptr, ...) @printf(ptr @hello_world)
ret i32 0
}
declare i32 @printf(ptr, ...)make をそのまま実行して、./a.out とすると、hello world! が出力される。
hello world のわりには長め。型の定義に多少手間がかかる。