sparse, llvm: Introduce 'struct function' to clean up code
[smatch.git] / sparse-llvm.c
blobb0aef3a510149187faf3c13936584f4382dae491
1 /*
2 * Example usage:
3 * ./sparse-llvm hello.c | llc | as -o hello.o
4 */
6 #include <llvm-c/Core.h>
7 #include <llvm-c/BitWriter.h>
9 #include <stdio.h>
10 #include <unistd.h>
11 #include <assert.h>
13 #include "symbol.h"
14 #include "expression.h"
15 #include "linearize.h"
16 #include "flow.h"
18 struct function {
19 LLVMBuilderRef builder;
20 LLVMTypeRef type;
21 LLVMValueRef fn;
24 static LLVMTypeRef symbol_type(struct symbol *sym)
26 LLVMTypeRef ret = NULL;
28 switch (sym->bit_size) {
29 case -1:
30 ret = LLVMVoidType();
31 break;
32 case 8:
33 ret = LLVMInt8Type();
34 break;
35 case 16:
36 ret = LLVMInt16Type();
37 break;
38 case 32:
39 ret = LLVMInt32Type();
40 break;
41 case 64:
42 ret = LLVMInt64Type();
43 break;
44 default:
45 die("invalid bit size %d for type %d", sym->bit_size, sym->type);
46 break;
49 return ret;
52 static LLVMLinkage data_linkage(struct symbol *sym)
54 if (sym->ctype.modifiers & MOD_STATIC)
55 return LLVMPrivateLinkage;
57 return LLVMExternalLinkage;
60 static LLVMLinkage function_linkage(struct symbol *sym)
62 if (sym->ctype.modifiers & MOD_STATIC)
63 return LLVMInternalLinkage;
65 return LLVMExternalLinkage;
68 static void output_op_ret(struct function *fn, struct instruction *insn)
70 pseudo_t pseudo = insn->src;
72 if (pseudo && pseudo != VOID) {
73 switch (pseudo->type) {
74 case PSEUDO_REG:
75 assert(0);
76 break;
77 case PSEUDO_SYM:
78 assert(0);
79 break;
80 case PSEUDO_VAL:
81 LLVMBuildRet(fn->builder, LLVMConstInt(LLVMGetReturnType(fn->type), pseudo->value, 1));
82 break;
83 case PSEUDO_ARG: {
84 LLVMValueRef param = LLVMGetParam(fn->fn, pseudo->nr - 1);
85 LLVMBuildRet(fn->builder, param);
86 break;
88 case PSEUDO_PHI:
89 assert(0);
90 break;
91 default:
92 assert(0);
94 } else
95 LLVMBuildRetVoid(fn->builder);
98 static void output_insn(struct function *fn, struct instruction *insn)
100 switch (insn->opcode) {
101 case OP_RET:
102 output_op_ret(fn, insn);
103 break;
104 case OP_BR:
105 break;
106 case OP_SYMADDR:
107 break;
108 case OP_SETVAL:
109 break;
110 case OP_SWITCH:
111 break;
112 case OP_COMPUTEDGOTO:
113 break;
114 case OP_PHISOURCE:
115 break;
116 case OP_PHI:
117 break;
118 case OP_LOAD: case OP_LNOP:
119 break;
120 case OP_STORE: case OP_SNOP:
121 break;
122 case OP_INLINED_CALL:
123 case OP_CALL:
124 break;
125 case OP_CAST:
126 case OP_SCAST:
127 case OP_FPCAST:
128 case OP_PTRCAST:
129 break;
130 case OP_BINARY ... OP_BINARY_END:
131 case OP_BINCMP ... OP_BINCMP_END:
132 break;
133 case OP_SEL:
134 break;
135 case OP_SLICE:
136 break;
137 case OP_NOT: case OP_NEG:
138 break;
139 case OP_CONTEXT:
140 break;
141 case OP_RANGE:
142 break;
143 case OP_NOP:
144 break;
145 case OP_DEATHNOTE:
146 break;
147 case OP_ASM:
148 break;
149 case OP_COPY:
150 break;
151 default:
152 break;
156 static void output_bb(struct function *fn, struct basic_block *bb, unsigned long generation)
158 struct instruction *insn;
160 bb->generation = generation;
162 FOR_EACH_PTR(bb->insns, insn) {
163 if (!insn->bb)
164 continue;
166 output_insn(fn, insn);
168 END_FOR_EACH_PTR(insn);
171 #define MAX_ARGS 64
173 static void output_fn(LLVMModuleRef module, struct entrypoint *ep)
175 unsigned long generation = ++bb_generation;
176 struct symbol *sym = ep->name;
177 struct symbol *base_type = sym->ctype.base_type;
178 struct symbol *ret_type = sym->ctype.base_type->ctype.base_type;
179 LLVMTypeRef arg_types[MAX_ARGS];
180 LLVMTypeRef return_type;
181 struct function function;
182 struct basic_block *bb;
183 struct symbol *arg;
184 const char *name;
185 int nr_args = 0;
187 FOR_EACH_PTR(base_type->arguments, arg) {
188 struct symbol *arg_base_type = arg->ctype.base_type;
190 arg_types[nr_args++] = symbol_type(arg_base_type);
191 } END_FOR_EACH_PTR(arg);
193 name = show_ident(sym->ident);
195 return_type = symbol_type(ret_type);
197 function.type = LLVMFunctionType(return_type, arg_types, nr_args, 0);
199 function.fn = LLVMAddFunction(module, name, function.type);
201 LLVMSetLinkage(function.fn, function_linkage(sym));
203 unssa(ep);
205 function.builder = LLVMCreateBuilder();
207 LLVMBasicBlockRef entry = LLVMAppendBasicBlock(function.fn, "entry");
209 LLVMPositionBuilderAtEnd(function.builder, entry);
211 FOR_EACH_PTR(ep->bbs, bb) {
212 if (bb->generation == generation)
213 continue;
215 output_bb(&function, bb, generation);
217 END_FOR_EACH_PTR(bb);
220 static int output_data(LLVMModuleRef module, struct symbol *sym)
222 struct expression *initializer = sym->initializer;
223 unsigned long long initial_value = 0;
224 LLVMValueRef data;
225 const char *name;
227 if (initializer) {
228 if (initializer->type == EXPR_VALUE)
229 initial_value = initializer->value;
230 else
231 assert(0);
234 name = show_ident(sym->ident);
236 data = LLVMAddGlobal(module, symbol_type(sym->ctype.base_type), name);
238 LLVMSetLinkage(data, data_linkage(sym));
240 LLVMSetInitializer(data, LLVMConstInt(symbol_type(sym), initial_value, 1));
242 return 0;
245 static int compile(LLVMModuleRef module, struct symbol_list *list)
247 struct symbol *sym;
249 FOR_EACH_PTR(list, sym) {
250 struct entrypoint *ep;
251 expand_symbol(sym);
252 ep = linearize_symbol(sym);
253 if (ep)
254 output_fn(module, ep);
255 else
256 output_data(module, sym);
258 END_FOR_EACH_PTR(sym);
260 return 0;
263 int main(int argc, char **argv)
265 struct string_list * filelist = NULL;
266 char *file;
268 LLVMModuleRef module = LLVMModuleCreateWithName("sparse");
270 compile(module, sparse_initialize(argc, argv, &filelist));
272 FOR_EACH_PTR_NOTAG(filelist, file) {
273 compile(module, sparse(file));
274 } END_FOR_EACH_PTR_NOTAG(file);
276 #if 1
277 LLVMWriteBitcodeToFD(module, STDOUT_FILENO, 0, 0);
278 #else
279 LLVMDumpModule(module);
280 #endif
282 LLVMDisposeModule(module);
284 return 0;