Created
August 19, 2022 05:34
-
-
Save redraiment/107bdf403e9c1bd8e337dc990f6333b6 to your computer and use it in GitHub Desktop.
A compiler sample with LLVM C API: it create an executable file, which accept two integer from stdin, and output the result of sum.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <llvm-c/Core.h> | |
#include <llvm-c/Target.h> | |
#include <llvm-c/TargetMachine.h> | |
#define FALSE 0 | |
#define TRUE 1 | |
#define PROGRAM "sum" | |
#define SOURCE "sum.c" | |
#define OBJECT "sum.o" | |
#define LINKER "/bin/ld" | |
#define LOADER "/lib64/ld-linux-x86-64.so.2" | |
#define RUNTIME_START "/lib/Scrt1.o" | |
#define RUNTIME_INIT "/lib/crti.o" | |
#define RUNTIME_FINI "/lib/crtn.o" | |
#define safe(expression) do { \ | |
char* message = NULL; \ | |
if ((expression) != 0) { \ | |
fprintf(stderr, "%s\n", message); \ | |
LLVMDisposeMessage(message); \ | |
exit(EXIT_FAILURE); \ | |
} \ | |
} while(0) | |
typedef enum { | |
s_printf = 0, | |
s_scanf, | |
s_sum, | |
s_main, | |
s_size | |
} Symbol; | |
struct { | |
LLVMTypeRef types[s_size]; | |
LLVMValueRef values[s_size]; | |
} SymbolTable; | |
LLVMValueRef declare(LLVMModuleRef module, Symbol symbol, char* name, LLVMTypeRef type) { | |
LLVMValueRef fn = LLVMAddFunction(module, name, type); | |
SymbolTable.types[symbol] = type; | |
SymbolTable.values[symbol] = fn; | |
return fn; | |
} | |
LLVMValueRef call(LLVMBuilderRef builder, Symbol symbol, int count, LLVMValueRef parameters[]) { | |
LLVMTypeRef type = SymbolTable.types[symbol]; | |
LLVMValueRef fn = SymbolTable.values[symbol]; | |
return LLVMBuildCall2(builder, type, fn, parameters, count, ""); | |
} | |
LLVMTargetMachineRef create_target_machine() { | |
// Initialize target machine | |
LLVMInitializeNativeTarget(); | |
LLVMInitializeNativeAsmPrinter(); | |
LLVMInitializeNativeAsmParser(); | |
LLVMTargetRef target = NULL; | |
safe(LLVMGetTargetFromTriple(LLVMGetDefaultTargetTriple(), &target, &message)); | |
return LLVMCreateTargetMachine(target, LLVMGetDefaultTargetTriple(), LLVMGetHostCPUName(), LLVMGetHostCPUFeatures(), LLVMCodeGenLevelDefault, LLVMRelocDefault, LLVMCodeModelDefault); | |
} | |
LLVMModuleRef create_module(LLVMTargetDataRef layout) { | |
// Initialize Module | |
LLVMModuleRef module = LLVMModuleCreateWithName(PROGRAM); | |
LLVMSetSourceFileName(module, SOURCE, strlen(SOURCE)); | |
LLVMSetTarget(module, LLVMGetDefaultTargetTriple()); | |
LLVMSetDataLayout(module, LLVMCopyStringRepOfTargetData(layout)); | |
return module; | |
} | |
void declare_printf(LLVMModuleRef module) { | |
declare(module, s_printf, "printf", LLVMFunctionType(LLVMInt32Type(), (LLVMTypeRef[]){ | |
LLVMPointerType(LLVMInt8Type(), 0) | |
}, 1, 1)); | |
} | |
void declare_scanf(LLVMModuleRef module) { | |
declare(module, s_scanf, "scanf", LLVMFunctionType(LLVMInt32Type(), (LLVMTypeRef[]){ | |
LLVMPointerType(LLVMInt8Type(), 0) | |
}, 1, 1)); | |
} | |
void define_sum(LLVMModuleRef module, LLVMBuilderRef builder) { | |
LLVMValueRef sum = declare(module, s_sum, "sum", LLVMFunctionType(LLVMInt32Type(), (LLVMTypeRef[]){ | |
LLVMInt32Type(), | |
LLVMInt32Type() | |
}, 2, 0)); | |
LLVMBasicBlockRef body = LLVMAppendBasicBlock(sum, ""); | |
LLVMPositionBuilderAtEnd(builder, body); | |
LLVMValueRef result = LLVMBuildAdd(builder, LLVMGetParam(sum, 0), LLVMGetParam(sum, 1), ""); | |
LLVMBuildRet(builder, result); | |
} | |
void define_main( | |
LLVMModuleRef module, | |
LLVMBuilderRef builder | |
) { | |
LLVMValueRef main = declare(module, s_main, "main", LLVMFunctionType(LLVMInt32Type(), (LLVMTypeRef[]){}, 0, 0)); | |
LLVMBasicBlockRef body = LLVMAppendBasicBlock(main, ""); | |
LLVMPositionBuilderAtEnd(builder, body); | |
LLVMValueRef pa = LLVMBuildAlloca(builder, LLVMInt32Type(), ""); | |
LLVMValueRef pb = LLVMBuildAlloca(builder, LLVMInt32Type(), ""); | |
call(builder, s_scanf, 3, (LLVMValueRef[]){ | |
LLVMBuildGlobalStringPtr(builder, "%d %d", ""), | |
pa, pb | |
}); | |
LLVMValueRef a = LLVMBuildLoad2(builder, LLVMInt32Type(), pa, ""); | |
LLVMValueRef b = LLVMBuildLoad2(builder, LLVMInt32Type(), pb, ""); | |
LLVMValueRef result = call(builder, s_sum, 2, (LLVMValueRef[]){ | |
a, b | |
}); | |
call(builder, s_printf, 4, (LLVMValueRef[]){ | |
LLVMBuildGlobalStringPtr(builder, "sum of %d + %d = %d!\n", ""), | |
a, b, | |
result | |
}); | |
LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 0, FALSE)); | |
} | |
void emit_object_file(LLVMTargetMachineRef machine, LLVMModuleRef module) { | |
printf("%s", LLVMPrintModuleToString(module)); | |
safe(LLVMTargetMachineEmitToFile(machine, module, OBJECT, LLVMObjectFile, &message)); | |
} | |
void link() { | |
char cmd[512] = {0}; | |
sprintf(cmd, | |
"%s -dynamic-linker %s -lc %s %s %s %s -o %s", | |
LINKER, LOADER, | |
RUNTIME_START, RUNTIME_INIT, OBJECT, RUNTIME_FINI, | |
PROGRAM); | |
system(cmd); | |
} | |
int main(int argc, char* argv[]) { | |
// initialize | |
LLVMTargetMachineRef machine = create_target_machine(); | |
LLVMTargetDataRef layout = LLVMCreateTargetDataLayout(machine); | |
LLVMModuleRef module = create_module(layout); | |
LLVMBuilderRef builder = LLVMCreateBuilder(); | |
// build | |
declare_printf(module); | |
declare_scanf(module); | |
define_sum(module, builder); | |
define_main(module, builder); | |
// output | |
emit_object_file(machine, module); | |
link(); | |
// dispose | |
LLVMDisposeBuilder(builder); | |
LLVMDisposeModule(module); | |
LLVMDisposeTargetData(layout); | |
LLVMDisposeTargetMachine(machine); | |
LLVMShutdown(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment