-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathllvm.c
100 lines (83 loc) · 3.07 KB
/
llvm.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// Headers required by LLVM
#include <llvm-c/Core.h>
#include <llvm-c/Analysis.h>
#include <llvm-c/ExecutionEngine.h>
#include <llvm-c/Target.h>
#include <llvm-c/Transforms/Scalar.h>
#include <stdio.h>
#include <stdlib.h>
#include "llvm.h"
static inline LLVMValueRef LLVM_visit(ASTNode *node, LLVMBuilderRef builder) {
switch(node->type) {
case AST_BINARY_OP: {
ASTBinaryOp *binary_op = (ASTBinaryOp*)node;
LLVMValueRef a = LLVM_visit(binary_op->lhs, builder);
LLVMValueRef b = LLVM_visit(binary_op->rhs, builder);
switch(binary_op->op) {
case '+': return LLVMBuildAdd(builder, a, b, "a + b");
case '-': return LLVMBuildSub(builder, a, b, "a - b");
case '*': return LLVMBuildMul(builder, a, b, "a * b");
case '/': return LLVMBuildSDiv(builder, a, b, "a / b");
}
}
case AST_INT: {
return LLVMConstInt(LLVMInt32Type(), ((ASTInt*)node)->value, 0);
}
}
}
LLVMCompiledProgram LLVM_compile(ASTNode *node)
{
char *error = NULL; // Used to retrieve messages from functions
LLVMLinkInJIT();
LLVMInitializeNativeTarget();
LLVMModuleRef mod = LLVMModuleCreateWithName("calc_module");
LLVMTypeRef program_args[] = { };
LLVMValueRef program = LLVMAddFunction(mod, "program", LLVMFunctionType(LLVMInt32Type(), program_args, 0, 0));
LLVMSetFunctionCallConv(program, LLVMCCallConv);
LLVMBuilderRef builder = LLVMCreateBuilder();
LLVMBasicBlockRef entry = LLVMAppendBasicBlock(program, "entry");
LLVMPositionBuilderAtEnd(builder, entry);
LLVMValueRef res = LLVM_visit(node, builder);
LLVMBuildRet(builder, res);
LLVMVerifyModule(mod, LLVMAbortProcessAction, &error);
LLVMDisposeMessage(error); // Handler == LLVMAbortProcessAction -> No need to check errors
LLVMDisposeBuilder(builder);
return (LLVMCompiledProgram) { .module = mod, .function = program };
}
int LLVM_execute(LLVMCompiledProgram program)
{
LLVMModuleRef module = program.module;
LLVMValueRef function = program.function;
char *error = NULL; // Used to retrieve messages from functions
LLVMExecutionEngineRef engine;
LLVMModuleProviderRef provider = LLVMCreateModuleProviderForExistingModule(module);
error = NULL;
if(LLVMCreateJITCompiler(&engine, provider, 2, &error) != 0) {
fprintf(stderr, "%s\n", error);
LLVMDisposeMessage(error);
abort();
}
LLVMPassManagerRef pass = LLVMCreatePassManager();
LLVMAddTargetData(LLVMGetExecutionEngineTargetData(engine), pass);
LLVMAddConstantPropagationPass(pass);
LLVMAddInstructionCombiningPass(pass);
LLVMAddPromoteMemoryToRegisterPass(pass);
LLVMAddGVNPass(pass);
LLVMAddCFGSimplificationPass(pass);
LLVMRunPassManager(pass, module);
#ifdef NDEBUG
#else
LLVMDumpModule(module);
#endif
LLVMGenericValueRef exec_args[] = {};
LLVMGenericValueRef exec_res = LLVMRunFunction(engine, function, 0, exec_args);
int result = LLVMGenericValueToInt(exec_res, 0);
LLVMDisposePassManager(pass);
LLVMDisposeExecutionEngine(engine);
return result;
}
int LLVM_evaluate(ASTNode *node)
{
LLVMCompiledProgram program = LLVM_compile(node);
return LLVM_execute(program);
}