11f5207b7SJohn Levon /*
21f5207b7SJohn Levon  * Example usage:
31f5207b7SJohn Levon  *	./sparse-llvm hello.c | llc | as -o hello.o
41f5207b7SJohn Levon  */
51f5207b7SJohn Levon 
61f5207b7SJohn Levon #include <llvm-c/Core.h>
71f5207b7SJohn Levon #include <llvm-c/BitWriter.h>
81f5207b7SJohn Levon #include <llvm-c/Analysis.h>
91f5207b7SJohn Levon #include <llvm-c/Target.h>
101f5207b7SJohn Levon 
111f5207b7SJohn Levon #include <stdbool.h>
121f5207b7SJohn Levon #include <stdio.h>
131f5207b7SJohn Levon #include <unistd.h>
141f5207b7SJohn Levon #include <string.h>
151f5207b7SJohn Levon #include <assert.h>
161f5207b7SJohn Levon 
171f5207b7SJohn Levon #include "symbol.h"
181f5207b7SJohn Levon #include "expression.h"
191f5207b7SJohn Levon #include "linearize.h"
201f5207b7SJohn Levon #include "flow.h"
211f5207b7SJohn Levon 
221f5207b7SJohn Levon struct function {
231f5207b7SJohn Levon 	LLVMBuilderRef			builder;
241f5207b7SJohn Levon 	LLVMValueRef			fn;
251f5207b7SJohn Levon 	LLVMModuleRef			module;
261f5207b7SJohn Levon };
271f5207b7SJohn Levon 
28*c85f09ccSJohn Levon static LLVMTypeRef symbol_type(struct symbol *sym);
291f5207b7SJohn Levon 
func_return_type(struct symbol * sym)30*c85f09ccSJohn Levon static LLVMTypeRef func_return_type(struct symbol *sym)
311f5207b7SJohn Levon {
32*c85f09ccSJohn Levon 	return symbol_type(sym->ctype.base_type);
331f5207b7SJohn Levon }
341f5207b7SJohn Levon 
sym_func_type(struct symbol * sym)35*c85f09ccSJohn Levon static LLVMTypeRef sym_func_type(struct symbol *sym)
361f5207b7SJohn Levon {
37*c85f09ccSJohn Levon 	int n_arg = symbol_list_size(sym->arguments);
38*c85f09ccSJohn Levon 	LLVMTypeRef *arg_type = calloc(n_arg, sizeof(LLVMTypeRef));
39*c85f09ccSJohn Levon 	LLVMTypeRef ret_type = func_return_type(sym);
401f5207b7SJohn Levon 	struct symbol *arg;
411f5207b7SJohn Levon 	int idx = 0;
42*c85f09ccSJohn Levon 
431f5207b7SJohn Levon 	FOR_EACH_PTR(sym->arguments, arg) {
441f5207b7SJohn Levon 		struct symbol *arg_sym = arg->ctype.base_type;
451f5207b7SJohn Levon 
46*c85f09ccSJohn Levon 		arg_type[idx++] = symbol_type(arg_sym);
471f5207b7SJohn Levon 	} END_FOR_EACH_PTR(arg);
481f5207b7SJohn Levon 
49*c85f09ccSJohn Levon 	return LLVMFunctionType(ret_type, arg_type, n_arg, sym->variadic);
501f5207b7SJohn Levon }
511f5207b7SJohn Levon 
sym_array_type(struct symbol * sym)52*c85f09ccSJohn Levon static LLVMTypeRef sym_array_type(struct symbol *sym)
531f5207b7SJohn Levon {
541f5207b7SJohn Levon 	LLVMTypeRef elem_type;
551f5207b7SJohn Levon 	struct symbol *base_type;
561f5207b7SJohn Levon 
571f5207b7SJohn Levon 	base_type = sym->ctype.base_type;
581f5207b7SJohn Levon 	/* empty struct is undefined [6.7.2.1(8)] */
591f5207b7SJohn Levon 	assert(base_type->bit_size > 0);
601f5207b7SJohn Levon 
61*c85f09ccSJohn Levon 	elem_type = symbol_type(base_type);
621f5207b7SJohn Levon 	if (!elem_type)
631f5207b7SJohn Levon 		return NULL;
641f5207b7SJohn Levon 
651f5207b7SJohn Levon 	return LLVMArrayType(elem_type, sym->bit_size / base_type->bit_size);
661f5207b7SJohn Levon }
671f5207b7SJohn Levon 
681f5207b7SJohn Levon #define MAX_STRUCT_MEMBERS 64
691f5207b7SJohn Levon 
sym_struct_type(struct symbol * sym)70*c85f09ccSJohn Levon static LLVMTypeRef sym_struct_type(struct symbol *sym)
711f5207b7SJohn Levon {
721f5207b7SJohn Levon 	LLVMTypeRef elem_types[MAX_STRUCT_MEMBERS];
731f5207b7SJohn Levon 	struct symbol *member;
741f5207b7SJohn Levon 	char buffer[256];
751f5207b7SJohn Levon 	LLVMTypeRef ret;
761f5207b7SJohn Levon 	unsigned nr = 0;
771f5207b7SJohn Levon 
781f5207b7SJohn Levon 	snprintf(buffer, sizeof(buffer), "struct.%s", sym->ident ? sym->ident->name : "anno");
791f5207b7SJohn Levon 	ret = LLVMStructCreateNamed(LLVMGetGlobalContext(), buffer);
801f5207b7SJohn Levon 	/* set ->aux to avoid recursion */
811f5207b7SJohn Levon 	sym->aux = ret;
821f5207b7SJohn Levon 
831f5207b7SJohn Levon 	FOR_EACH_PTR(sym->symbol_list, member) {
841f5207b7SJohn Levon 		LLVMTypeRef member_type;
851f5207b7SJohn Levon 
861f5207b7SJohn Levon 		assert(nr < MAX_STRUCT_MEMBERS);
871f5207b7SJohn Levon 
88*c85f09ccSJohn Levon 		member_type = symbol_type(member);
891f5207b7SJohn Levon 
901f5207b7SJohn Levon 		elem_types[nr++] = member_type;
911f5207b7SJohn Levon 	} END_FOR_EACH_PTR(member);
921f5207b7SJohn Levon 
931f5207b7SJohn Levon 	LLVMStructSetBody(ret, elem_types, nr, 0 /* packed? */);
941f5207b7SJohn Levon 	return ret;
951f5207b7SJohn Levon }
961f5207b7SJohn Levon 
sym_union_type(struct symbol * sym)97*c85f09ccSJohn Levon static LLVMTypeRef sym_union_type(struct symbol *sym)
981f5207b7SJohn Levon {
991f5207b7SJohn Levon 	LLVMTypeRef elements;
1001f5207b7SJohn Levon 	unsigned union_size;
1011f5207b7SJohn Levon 
1021f5207b7SJohn Levon 	/*
1031f5207b7SJohn Levon 	 * There's no union support in the LLVM API so we treat unions as
1041f5207b7SJohn Levon 	 * opaque structs. The downside is that we lose type information on the
1051f5207b7SJohn Levon 	 * members but as LLVM doesn't care, neither do we.
1061f5207b7SJohn Levon 	 */
1071f5207b7SJohn Levon 	union_size = sym->bit_size / 8;
1081f5207b7SJohn Levon 
1091f5207b7SJohn Levon 	elements = LLVMArrayType(LLVMInt8Type(), union_size);
1101f5207b7SJohn Levon 
1111f5207b7SJohn Levon 	return LLVMStructType(&elements, 1, 0 /* packed? */);
1121f5207b7SJohn Levon }
1131f5207b7SJohn Levon 
sym_ptr_type(struct symbol * sym)114*c85f09ccSJohn Levon static LLVMTypeRef sym_ptr_type(struct symbol *sym)
1151f5207b7SJohn Levon {
1161f5207b7SJohn Levon 	LLVMTypeRef type;
1171f5207b7SJohn Levon 
1181f5207b7SJohn Levon 	/* 'void *' is treated like 'char *' */
1191f5207b7SJohn Levon 	if (is_void_type(sym->ctype.base_type))
1201f5207b7SJohn Levon 		type = LLVMInt8Type();
1211f5207b7SJohn Levon 	else
122*c85f09ccSJohn Levon 		type = symbol_type(sym->ctype.base_type);
1231f5207b7SJohn Levon 
1241f5207b7SJohn Levon 	return LLVMPointerType(type, 0);
1251f5207b7SJohn Levon }
1261f5207b7SJohn Levon 
sym_basetype_type(struct symbol * sym)1271f5207b7SJohn Levon static LLVMTypeRef sym_basetype_type(struct symbol *sym)
1281f5207b7SJohn Levon {
1291f5207b7SJohn Levon 	LLVMTypeRef ret = NULL;
1301f5207b7SJohn Levon 
131*c85f09ccSJohn Levon 	if (is_float_type(sym)) {
1321f5207b7SJohn Levon 		switch (sym->bit_size) {
1331f5207b7SJohn Levon 		case 32:
1341f5207b7SJohn Levon 			ret = LLVMFloatType();
1351f5207b7SJohn Levon 			break;
1361f5207b7SJohn Levon 		case 64:
1371f5207b7SJohn Levon 			ret = LLVMDoubleType();
1381f5207b7SJohn Levon 			break;
1391f5207b7SJohn Levon 		case 80:
1401f5207b7SJohn Levon 			ret = LLVMX86FP80Type();
1411f5207b7SJohn Levon 			break;
1421f5207b7SJohn Levon 		default:
1431f5207b7SJohn Levon 			die("invalid bit size %d for type %d", sym->bit_size, sym->type);
1441f5207b7SJohn Levon 			break;
1451f5207b7SJohn Levon 		}
1461f5207b7SJohn Levon 	} else {
1471f5207b7SJohn Levon 		switch (sym->bit_size) {
1481f5207b7SJohn Levon 		case -1:
1491f5207b7SJohn Levon 			ret = LLVMVoidType();
1501f5207b7SJohn Levon 			break;
1511f5207b7SJohn Levon 		case 1:
1521f5207b7SJohn Levon 			ret = LLVMInt1Type();
1531f5207b7SJohn Levon 			break;
1541f5207b7SJohn Levon 		case 8:
1551f5207b7SJohn Levon 			ret = LLVMInt8Type();
1561f5207b7SJohn Levon 			break;
1571f5207b7SJohn Levon 		case 16:
1581f5207b7SJohn Levon 			ret = LLVMInt16Type();
1591f5207b7SJohn Levon 			break;
1601f5207b7SJohn Levon 		case 32:
1611f5207b7SJohn Levon 			ret = LLVMInt32Type();
1621f5207b7SJohn Levon 			break;
1631f5207b7SJohn Levon 		case 64:
1641f5207b7SJohn Levon 			ret = LLVMInt64Type();
1651f5207b7SJohn Levon 			break;
1661f5207b7SJohn Levon 		default:
1671f5207b7SJohn Levon 			die("invalid bit size %d for type %d", sym->bit_size, sym->type);
1681f5207b7SJohn Levon 			break;
1691f5207b7SJohn Levon 		}
1701f5207b7SJohn Levon 	}
1711f5207b7SJohn Levon 
1721f5207b7SJohn Levon 	return ret;
1731f5207b7SJohn Levon }
1741f5207b7SJohn Levon 
symbol_type(struct symbol * sym)175*c85f09ccSJohn Levon static LLVMTypeRef symbol_type(struct symbol *sym)
1761f5207b7SJohn Levon {
1771f5207b7SJohn Levon 	LLVMTypeRef ret = NULL;
1781f5207b7SJohn Levon 
1791f5207b7SJohn Levon 	/* don't cache the result for SYM_NODE */
1801f5207b7SJohn Levon 	if (sym->type == SYM_NODE)
181*c85f09ccSJohn Levon 		return symbol_type(sym->ctype.base_type);
1821f5207b7SJohn Levon 
1831f5207b7SJohn Levon 	if (sym->aux)
1841f5207b7SJohn Levon 		return sym->aux;
1851f5207b7SJohn Levon 
1861f5207b7SJohn Levon 	switch (sym->type) {
1871f5207b7SJohn Levon 	case SYM_BITFIELD:
188*c85f09ccSJohn Levon 		ret = LLVMIntType(sym->bit_size);
189*c85f09ccSJohn Levon 		break;
190*c85f09ccSJohn Levon 	case SYM_RESTRICT:
1911f5207b7SJohn Levon 	case SYM_ENUM:
192*c85f09ccSJohn Levon 		ret = symbol_type(sym->ctype.base_type);
1931f5207b7SJohn Levon 		break;
1941f5207b7SJohn Levon 	case SYM_BASETYPE:
1951f5207b7SJohn Levon 		ret = sym_basetype_type(sym);
1961f5207b7SJohn Levon 		break;
1971f5207b7SJohn Levon 	case SYM_PTR:
198*c85f09ccSJohn Levon 		ret = sym_ptr_type(sym);
1991f5207b7SJohn Levon 		break;
2001f5207b7SJohn Levon 	case SYM_UNION:
201*c85f09ccSJohn Levon 		ret = sym_union_type(sym);
2021f5207b7SJohn Levon 		break;
2031f5207b7SJohn Levon 	case SYM_STRUCT:
204*c85f09ccSJohn Levon 		ret = sym_struct_type(sym);
2051f5207b7SJohn Levon 		break;
2061f5207b7SJohn Levon 	case SYM_ARRAY:
207*c85f09ccSJohn Levon 		ret = sym_array_type(sym);
2081f5207b7SJohn Levon 		break;
2091f5207b7SJohn Levon 	case SYM_FN:
210*c85f09ccSJohn Levon 		ret = sym_func_type(sym);
2111f5207b7SJohn Levon 		break;
2121f5207b7SJohn Levon 	default:
2131f5207b7SJohn Levon 		assert(0);
2141f5207b7SJohn Levon 	}
2151f5207b7SJohn Levon 
2161f5207b7SJohn Levon 	/* cache the result */
2171f5207b7SJohn Levon 	sym->aux = ret;
2181f5207b7SJohn Levon 	return ret;
2191f5207b7SJohn Levon }
2201f5207b7SJohn Levon 
insn_symbol_type(struct instruction * insn)221*c85f09ccSJohn Levon static LLVMTypeRef insn_symbol_type(struct instruction *insn)
2221f5207b7SJohn Levon {
223*c85f09ccSJohn Levon 	if (insn->type)
224*c85f09ccSJohn Levon 		return symbol_type(insn->type);
225*c85f09ccSJohn Levon 
226*c85f09ccSJohn Levon 	switch (insn->size) {
2271f5207b7SJohn Levon 		case 8:		return LLVMInt8Type();
2281f5207b7SJohn Levon 		case 16:	return LLVMInt16Type();
2291f5207b7SJohn Levon 		case 32:	return LLVMInt32Type();
2301f5207b7SJohn Levon 		case 64:	return LLVMInt64Type();
2311f5207b7SJohn Levon 
2321f5207b7SJohn Levon 		default:
233*c85f09ccSJohn Levon 			die("invalid bit size %d", insn->size);
2341f5207b7SJohn Levon 			break;
2351f5207b7SJohn Levon 	}
2361f5207b7SJohn Levon 
237*c85f09ccSJohn Levon 	return NULL;	/* not reached */
2381f5207b7SJohn Levon }
2391f5207b7SJohn Levon 
data_linkage(struct symbol * sym)2401f5207b7SJohn Levon static LLVMLinkage data_linkage(struct symbol *sym)
2411f5207b7SJohn Levon {
2421f5207b7SJohn Levon 	if (sym->ctype.modifiers & MOD_STATIC)
2431f5207b7SJohn Levon 		return LLVMPrivateLinkage;
2441f5207b7SJohn Levon 
2451f5207b7SJohn Levon 	return LLVMExternalLinkage;
2461f5207b7SJohn Levon }
2471f5207b7SJohn Levon 
function_linkage(struct symbol * sym)2481f5207b7SJohn Levon static LLVMLinkage function_linkage(struct symbol *sym)
2491f5207b7SJohn Levon {
2501f5207b7SJohn Levon 	if (sym->ctype.modifiers & MOD_STATIC)
2511f5207b7SJohn Levon 		return LLVMInternalLinkage;
2521f5207b7SJohn Levon 
2531f5207b7SJohn Levon 	return LLVMExternalLinkage;
2541f5207b7SJohn Levon }
2551f5207b7SJohn Levon 
2561f5207b7SJohn Levon #define MAX_PSEUDO_NAME 64
2571f5207b7SJohn Levon 
pseudo_name(pseudo_t pseudo,char * buf)258*c85f09ccSJohn Levon static const char *pseudo_name(pseudo_t pseudo, char *buf)
2591f5207b7SJohn Levon {
2601f5207b7SJohn Levon 	switch (pseudo->type) {
2611f5207b7SJohn Levon 	case PSEUDO_REG:
262*c85f09ccSJohn Levon 		snprintf(buf, MAX_PSEUDO_NAME, "R%d.", pseudo->nr);
2631f5207b7SJohn Levon 		break;
264*c85f09ccSJohn Levon 	case PSEUDO_PHI:
265*c85f09ccSJohn Levon 		snprintf(buf, MAX_PSEUDO_NAME, "PHI%d.", pseudo->nr);
2661f5207b7SJohn Levon 		break;
267*c85f09ccSJohn Levon 	case PSEUDO_SYM:
2681f5207b7SJohn Levon 	case PSEUDO_VAL:
269*c85f09ccSJohn Levon 	case PSEUDO_ARG:
270*c85f09ccSJohn Levon 	case PSEUDO_VOID:
271*c85f09ccSJohn Levon 		buf[0] = '\0';
2721f5207b7SJohn Levon 		break;
273*c85f09ccSJohn Levon 	case PSEUDO_UNDEF:
2741f5207b7SJohn Levon 		assert(0);
2751f5207b7SJohn Levon 		break;
276*c85f09ccSJohn Levon 	default:
277*c85f09ccSJohn Levon 		assert(0);
2781f5207b7SJohn Levon 	}
279*c85f09ccSJohn Levon 
280*c85f09ccSJohn Levon 	return buf;
281*c85f09ccSJohn Levon }
282*c85f09ccSJohn Levon 
get_sym_value(LLVMModuleRef module,struct symbol * sym)283*c85f09ccSJohn Levon static LLVMValueRef get_sym_value(LLVMModuleRef module, struct symbol *sym)
284*c85f09ccSJohn Levon {
285*c85f09ccSJohn Levon 	const char *name = show_ident(sym->ident);
286*c85f09ccSJohn Levon 	LLVMTypeRef type = symbol_type(sym);
287*c85f09ccSJohn Levon 	LLVMValueRef result = NULL;
288*c85f09ccSJohn Levon 	struct expression *expr;
289*c85f09ccSJohn Levon 
290*c85f09ccSJohn Levon 	assert(sym->bb_target == NULL);
291*c85f09ccSJohn Levon 
292*c85f09ccSJohn Levon 	expr = sym->initializer;
293*c85f09ccSJohn Levon 	if (expr && !sym->ident) {
294*c85f09ccSJohn Levon 		switch (expr->type) {
295*c85f09ccSJohn Levon 		case EXPR_STRING: {
296*c85f09ccSJohn Levon 			const char *s = expr->string->data;
297*c85f09ccSJohn Levon 			LLVMValueRef indices[] = { LLVMConstInt(LLVMInt64Type(), 0, 0), LLVMConstInt(LLVMInt64Type(), 0, 0) };
298*c85f09ccSJohn Levon 			LLVMValueRef data;
299*c85f09ccSJohn Levon 
300*c85f09ccSJohn Levon 			data = LLVMAddGlobal(module, LLVMArrayType(LLVMInt8Type(), strlen(s) + 1), ".str");
301*c85f09ccSJohn Levon 			LLVMSetLinkage(data, LLVMPrivateLinkage);
302*c85f09ccSJohn Levon 			LLVMSetGlobalConstant(data, 1);
303*c85f09ccSJohn Levon 			LLVMSetInitializer(data, LLVMConstString(strdup(s), strlen(s) + 1, true));
304*c85f09ccSJohn Levon 
305*c85f09ccSJohn Levon 			result = LLVMConstGEP(data, indices, ARRAY_SIZE(indices));
306*c85f09ccSJohn Levon 			return result;
307*c85f09ccSJohn Levon 		}
308*c85f09ccSJohn Levon 		default:
309*c85f09ccSJohn Levon 			break;
310*c85f09ccSJohn Levon 		}
311*c85f09ccSJohn Levon 	}
312*c85f09ccSJohn Levon 
313*c85f09ccSJohn Levon 	if (LLVMGetTypeKind(type) == LLVMFunctionTypeKind) {
314*c85f09ccSJohn Levon 		result = LLVMGetNamedFunction(module, name);
315*c85f09ccSJohn Levon 		if (!result)
316*c85f09ccSJohn Levon 			result = LLVMAddFunction(module, name, type);
317*c85f09ccSJohn Levon 	} else {
318*c85f09ccSJohn Levon 		result = LLVMGetNamedGlobal(module, name);
319*c85f09ccSJohn Levon 		if (!result)
320*c85f09ccSJohn Levon 			result = LLVMAddGlobal(module, type, name);
321*c85f09ccSJohn Levon 	}
322*c85f09ccSJohn Levon 
323*c85f09ccSJohn Levon 	return result;
324*c85f09ccSJohn Levon }
325*c85f09ccSJohn Levon 
constant_value(unsigned long long val,LLVMTypeRef dtype)326*c85f09ccSJohn Levon static LLVMValueRef constant_value(unsigned long long val, LLVMTypeRef dtype)
327*c85f09ccSJohn Levon {
328*c85f09ccSJohn Levon 	LLVMValueRef result;
329*c85f09ccSJohn Levon 
330*c85f09ccSJohn Levon 	switch (LLVMGetTypeKind(dtype)) {
331*c85f09ccSJohn Levon 	case LLVMPointerTypeKind:
332*c85f09ccSJohn Levon 		if (val != 0) {	 // for example: ... = (void*) 0x123;
333*c85f09ccSJohn Levon 			LLVMTypeRef itype = LLVMIntType(bits_in_pointer);
334*c85f09ccSJohn Levon 			result = LLVMConstInt(itype, val, 1);
335*c85f09ccSJohn Levon 			result = LLVMConstIntToPtr(result, dtype);
336*c85f09ccSJohn Levon 		} else {
337*c85f09ccSJohn Levon 			result = LLVMConstPointerNull(dtype);
338*c85f09ccSJohn Levon 		}
339*c85f09ccSJohn Levon 		break;
340*c85f09ccSJohn Levon 	case LLVMIntegerTypeKind:
341*c85f09ccSJohn Levon 		result = LLVMConstInt(dtype, val, 1);
342*c85f09ccSJohn Levon 		break;
343*c85f09ccSJohn Levon 	case LLVMArrayTypeKind:
344*c85f09ccSJohn Levon 	case LLVMStructTypeKind:
345*c85f09ccSJohn Levon 		if (val != 0)
346*c85f09ccSJohn Levon 			return NULL;
347*c85f09ccSJohn Levon 		result = LLVMConstNull(dtype);
3481f5207b7SJohn Levon 		break;
3491f5207b7SJohn Levon 	default:
350*c85f09ccSJohn Levon 		return NULL;
3511f5207b7SJohn Levon 	}
352*c85f09ccSJohn Levon 	return result;
353*c85f09ccSJohn Levon }
354*c85f09ccSJohn Levon 
val_to_value(unsigned long long val,struct symbol * ctype)355*c85f09ccSJohn Levon static LLVMValueRef val_to_value(unsigned long long val, struct symbol *ctype)
356*c85f09ccSJohn Levon {
357*c85f09ccSJohn Levon 	LLVMValueRef result;
358*c85f09ccSJohn Levon 	LLVMTypeRef dtype;
359*c85f09ccSJohn Levon 
360*c85f09ccSJohn Levon 	assert(ctype);
361*c85f09ccSJohn Levon 	dtype = symbol_type(ctype);
362*c85f09ccSJohn Levon 	result = constant_value(val, dtype);
363*c85f09ccSJohn Levon 	if (result)
364*c85f09ccSJohn Levon 		return result;
365*c85f09ccSJohn Levon 	sparse_error(ctype->pos, "no value possible for %s", show_typename(ctype));
366*c85f09ccSJohn Levon 	return LLVMGetUndef(symbol_type(ctype));
3671f5207b7SJohn Levon }
3681f5207b7SJohn Levon 
pseudo_to_value(struct function * fn,struct symbol * ctype,pseudo_t pseudo)369*c85f09ccSJohn Levon static LLVMValueRef pseudo_to_value(struct function *fn, struct symbol *ctype, pseudo_t pseudo)
3701f5207b7SJohn Levon {
3711f5207b7SJohn Levon 	LLVMValueRef result = NULL;
3721f5207b7SJohn Levon 
3731f5207b7SJohn Levon 	switch (pseudo->type) {
3741f5207b7SJohn Levon 	case PSEUDO_REG:
3751f5207b7SJohn Levon 		result = pseudo->priv;
3761f5207b7SJohn Levon 		break;
377*c85f09ccSJohn Levon 	case PSEUDO_SYM:
378*c85f09ccSJohn Levon 		result = get_sym_value(fn->module, pseudo->sym);
3791f5207b7SJohn Levon 		break;
3801f5207b7SJohn Levon 	case PSEUDO_VAL:
381*c85f09ccSJohn Levon 		result = val_to_value(pseudo->value, ctype);
3821f5207b7SJohn Levon 		break;
3831f5207b7SJohn Levon 	case PSEUDO_ARG: {
3841f5207b7SJohn Levon 		result = LLVMGetParam(fn->fn, pseudo->nr - 1);
3851f5207b7SJohn Levon 		break;
3861f5207b7SJohn Levon 	}
3871f5207b7SJohn Levon 	case PSEUDO_PHI:
3881f5207b7SJohn Levon 		result = pseudo->priv;
3891f5207b7SJohn Levon 		break;
3901f5207b7SJohn Levon 	case PSEUDO_VOID:
3911f5207b7SJohn Levon 		result = NULL;
3921f5207b7SJohn Levon 		break;
393*c85f09ccSJohn Levon 	case PSEUDO_UNDEF:
394*c85f09ccSJohn Levon 		result = LLVMGetUndef(symbol_type(ctype));
395*c85f09ccSJohn Levon 		break;
3961f5207b7SJohn Levon 	default:
3971f5207b7SJohn Levon 		assert(0);
3981f5207b7SJohn Levon 	}
3991f5207b7SJohn Levon 
4001f5207b7SJohn Levon 	return result;
4011f5207b7SJohn Levon }
4021f5207b7SJohn Levon 
pseudo_to_rvalue(struct function * fn,struct symbol * ctype,pseudo_t pseudo)403*c85f09ccSJohn Levon static LLVMValueRef pseudo_to_rvalue(struct function *fn, struct symbol *ctype, pseudo_t pseudo)
404*c85f09ccSJohn Levon {
405*c85f09ccSJohn Levon 	LLVMValueRef val = pseudo_to_value(fn, ctype, pseudo);
406*c85f09ccSJohn Levon 	LLVMTypeRef dtype = symbol_type(ctype);
407*c85f09ccSJohn Levon 	char name[MAX_PSEUDO_NAME];
408*c85f09ccSJohn Levon 
409*c85f09ccSJohn Levon 	pseudo_name(pseudo, name);
410*c85f09ccSJohn Levon 	return LLVMBuildBitCast(fn->builder, val, dtype, name);
411*c85f09ccSJohn Levon }
412*c85f09ccSJohn Levon 
value_to_ivalue(struct function * fn,struct symbol * ctype,LLVMValueRef val)413*c85f09ccSJohn Levon static LLVMValueRef value_to_ivalue(struct function *fn, struct symbol *ctype, LLVMValueRef val)
414*c85f09ccSJohn Levon {
415*c85f09ccSJohn Levon 	const char *name = LLVMGetValueName(val);
416*c85f09ccSJohn Levon 	LLVMTypeRef dtype = symbol_type(ctype);
417*c85f09ccSJohn Levon 
418*c85f09ccSJohn Levon 	if (LLVMGetTypeKind(LLVMTypeOf(val)) == LLVMPointerTypeKind) {
419*c85f09ccSJohn Levon 		LLVMTypeRef dtype = LLVMIntType(bits_in_pointer);
420*c85f09ccSJohn Levon 		val = LLVMBuildPtrToInt(fn->builder, val, dtype, name);
421*c85f09ccSJohn Levon 	}
422*c85f09ccSJohn Levon 	if (ctype && is_int_type(ctype)) {
423*c85f09ccSJohn Levon 		val = LLVMBuildIntCast(fn->builder, val, dtype, name);
424*c85f09ccSJohn Levon 	}
425*c85f09ccSJohn Levon 	return val;
426*c85f09ccSJohn Levon }
427*c85f09ccSJohn Levon 
value_to_pvalue(struct function * fn,struct symbol * ctype,LLVMValueRef val)428*c85f09ccSJohn Levon static LLVMValueRef value_to_pvalue(struct function *fn, struct symbol *ctype, LLVMValueRef val)
429*c85f09ccSJohn Levon {
430*c85f09ccSJohn Levon 	const char *name = LLVMGetValueName(val);
431*c85f09ccSJohn Levon 	LLVMTypeRef dtype = symbol_type(ctype);
432*c85f09ccSJohn Levon 
433*c85f09ccSJohn Levon 	assert(is_ptr_type(ctype));
434*c85f09ccSJohn Levon 	switch (LLVMGetTypeKind(LLVMTypeOf(val))) {
435*c85f09ccSJohn Levon 	case LLVMIntegerTypeKind:
436*c85f09ccSJohn Levon 		val = LLVMBuildIntToPtr(fn->builder, val, dtype, name);
437*c85f09ccSJohn Levon 		break;
438*c85f09ccSJohn Levon 	case LLVMPointerTypeKind:
439*c85f09ccSJohn Levon 		val = LLVMBuildBitCast(fn->builder, val, dtype, name);
440*c85f09ccSJohn Levon 		break;
441*c85f09ccSJohn Levon 	default:
442*c85f09ccSJohn Levon 		break;
443*c85f09ccSJohn Levon 	}
444*c85f09ccSJohn Levon 	return val;
445*c85f09ccSJohn Levon }
446*c85f09ccSJohn Levon 
adjust_type(struct function * fn,struct symbol * ctype,LLVMValueRef val)447*c85f09ccSJohn Levon static LLVMValueRef adjust_type(struct function *fn, struct symbol *ctype, LLVMValueRef val)
448*c85f09ccSJohn Levon {
449*c85f09ccSJohn Levon 	if (is_int_type(ctype))
450*c85f09ccSJohn Levon 		return value_to_ivalue(fn, ctype, val);
451*c85f09ccSJohn Levon 	if (is_ptr_type(ctype))
452*c85f09ccSJohn Levon 		return value_to_pvalue(fn, ctype, val);
453*c85f09ccSJohn Levon 	return val;
454*c85f09ccSJohn Levon }
455*c85f09ccSJohn Levon 
456*c85f09ccSJohn Levon /*
457*c85f09ccSJohn Levon  * Get the LLVMValue corresponding to the pseudo
458*c85f09ccSJohn Levon  * and force the type corresponding to ctype.
459*c85f09ccSJohn Levon  */
get_operand(struct function * fn,struct symbol * ctype,pseudo_t pseudo)460*c85f09ccSJohn Levon static LLVMValueRef get_operand(struct function *fn, struct symbol *ctype, pseudo_t pseudo)
461*c85f09ccSJohn Levon {
462*c85f09ccSJohn Levon 	LLVMValueRef target = pseudo_to_value(fn, ctype, pseudo);
463*c85f09ccSJohn Levon 	return adjust_type(fn, ctype, target);
464*c85f09ccSJohn Levon }
465*c85f09ccSJohn Levon 
466*c85f09ccSJohn Levon /*
467*c85f09ccSJohn Levon  * Get the LLVMValue corresponding to the pseudo
468*c85f09ccSJohn Levon  * and force the type corresponding to ctype but
469*c85f09ccSJohn Levon  * map all pointers to intptr_t.
470*c85f09ccSJohn Levon  */
get_ioperand(struct function * fn,struct symbol * ctype,pseudo_t pseudo)471*c85f09ccSJohn Levon static LLVMValueRef get_ioperand(struct function *fn, struct symbol *ctype, pseudo_t pseudo)
472*c85f09ccSJohn Levon {
473*c85f09ccSJohn Levon 	LLVMValueRef target = pseudo_to_value(fn, ctype, pseudo);
474*c85f09ccSJohn Levon 	return value_to_ivalue(fn, ctype, target);
475*c85f09ccSJohn Levon }
476*c85f09ccSJohn Levon 
calc_gep(LLVMBuilderRef builder,LLVMValueRef base,LLVMValueRef off)4771f5207b7SJohn Levon static LLVMValueRef calc_gep(LLVMBuilderRef builder, LLVMValueRef base, LLVMValueRef off)
4781f5207b7SJohn Levon {
4791f5207b7SJohn Levon 	LLVMTypeRef type = LLVMTypeOf(base);
4801f5207b7SJohn Levon 	unsigned int as = LLVMGetPointerAddressSpace(type);
4811f5207b7SJohn Levon 	LLVMTypeRef bytep = LLVMPointerType(LLVMInt8Type(), as);
4821f5207b7SJohn Levon 	LLVMValueRef addr;
483*c85f09ccSJohn Levon 	const char *name = LLVMGetValueName(off);
4841f5207b7SJohn Levon 
4851f5207b7SJohn Levon 	/* convert base to char* type */
486*c85f09ccSJohn Levon 	base = LLVMBuildPointerCast(builder, base, bytep, name);
4871f5207b7SJohn Levon 	/* addr = base + off */
488*c85f09ccSJohn Levon 	addr = LLVMBuildInBoundsGEP(builder, base, &off, 1, name);
4891f5207b7SJohn Levon 	/* convert back to the actual pointer type */
490*c85f09ccSJohn Levon 	addr = LLVMBuildPointerCast(builder, addr, type, name);
4911f5207b7SJohn Levon 	return addr;
4921f5207b7SJohn Levon }
4931f5207b7SJohn Levon 
translate_fop(int opcode)4941f5207b7SJohn Levon static LLVMRealPredicate translate_fop(int opcode)
4951f5207b7SJohn Levon {
4961f5207b7SJohn Levon 	static const LLVMRealPredicate trans_tbl[] = {
497*c85f09ccSJohn Levon 		[OP_FCMP_ORD]	= LLVMRealORD,
498*c85f09ccSJohn Levon 		[OP_FCMP_OEQ]	= LLVMRealOEQ,
499*c85f09ccSJohn Levon 		[OP_FCMP_ONE]	= LLVMRealONE,
500*c85f09ccSJohn Levon 		[OP_FCMP_OLE]	= LLVMRealOLE,
501*c85f09ccSJohn Levon 		[OP_FCMP_OGE]	= LLVMRealOGE,
502*c85f09ccSJohn Levon 		[OP_FCMP_OLT]	= LLVMRealOLT,
503*c85f09ccSJohn Levon 		[OP_FCMP_OGT]	= LLVMRealOGT,
504*c85f09ccSJohn Levon 		[OP_FCMP_UEQ]	= LLVMRealUEQ,
505*c85f09ccSJohn Levon 		[OP_FCMP_UNE]	= LLVMRealUNE,
506*c85f09ccSJohn Levon 		[OP_FCMP_ULE]	= LLVMRealULE,
507*c85f09ccSJohn Levon 		[OP_FCMP_UGE]	= LLVMRealUGE,
508*c85f09ccSJohn Levon 		[OP_FCMP_ULT]	= LLVMRealULT,
509*c85f09ccSJohn Levon 		[OP_FCMP_UGT]	= LLVMRealUGT,
510*c85f09ccSJohn Levon 		[OP_FCMP_UNO]	= LLVMRealUNO,
5111f5207b7SJohn Levon 	};
5121f5207b7SJohn Levon 
5131f5207b7SJohn Levon 	return trans_tbl[opcode];
5141f5207b7SJohn Levon }
5151f5207b7SJohn Levon 
translate_op(int opcode)5161f5207b7SJohn Levon static LLVMIntPredicate translate_op(int opcode)
5171f5207b7SJohn Levon {
5181f5207b7SJohn Levon 	static const LLVMIntPredicate trans_tbl[] = {
5191f5207b7SJohn Levon 		[OP_SET_EQ]	= LLVMIntEQ,
5201f5207b7SJohn Levon 		[OP_SET_NE]	= LLVMIntNE,
5211f5207b7SJohn Levon 		[OP_SET_LE]	= LLVMIntSLE,
5221f5207b7SJohn Levon 		[OP_SET_GE]	= LLVMIntSGE,
5231f5207b7SJohn Levon 		[OP_SET_LT]	= LLVMIntSLT,
5241f5207b7SJohn Levon 		[OP_SET_GT]	= LLVMIntSGT,
5251f5207b7SJohn Levon 		[OP_SET_B]	= LLVMIntULT,
5261f5207b7SJohn Levon 		[OP_SET_A]	= LLVMIntUGT,
5271f5207b7SJohn Levon 		[OP_SET_BE]	= LLVMIntULE,
5281f5207b7SJohn Levon 		[OP_SET_AE]	= LLVMIntUGE,
5291f5207b7SJohn Levon 	};
5301f5207b7SJohn Levon 
5311f5207b7SJohn Levon 	return trans_tbl[opcode];
5321f5207b7SJohn Levon }
5331f5207b7SJohn Levon 
output_op_binary(struct function * fn,struct instruction * insn)5341f5207b7SJohn Levon static void output_op_binary(struct function *fn, struct instruction *insn)
5351f5207b7SJohn Levon {
5361f5207b7SJohn Levon 	LLVMValueRef lhs, rhs, target;
5371f5207b7SJohn Levon 	char target_name[64];
5381f5207b7SJohn Levon 
539*c85f09ccSJohn Levon 	lhs = get_ioperand(fn, insn->type, insn->src1);
540*c85f09ccSJohn Levon 	rhs = get_ioperand(fn, insn->type, insn->src2);
5411f5207b7SJohn Levon 
5421f5207b7SJohn Levon 	pseudo_name(insn->target, target_name);
5431f5207b7SJohn Levon 
5441f5207b7SJohn Levon 	switch (insn->opcode) {
5451f5207b7SJohn Levon 	/* Binary */
5461f5207b7SJohn Levon 	case OP_ADD:
547*c85f09ccSJohn Levon 		target = LLVMBuildAdd(fn->builder, lhs, rhs, target_name);
5481f5207b7SJohn Levon 		break;
5491f5207b7SJohn Levon 	case OP_SUB:
550*c85f09ccSJohn Levon 		target = LLVMBuildSub(fn->builder, lhs, rhs, target_name);
5511f5207b7SJohn Levon 		break;
552*c85f09ccSJohn Levon 	case OP_MUL:
5531f5207b7SJohn Levon 		target = LLVMBuildMul(fn->builder, lhs, rhs, target_name);
5541f5207b7SJohn Levon 		break;
5551f5207b7SJohn Levon 	case OP_DIVU:
556*c85f09ccSJohn Levon 		target = LLVMBuildUDiv(fn->builder, lhs, rhs, target_name);
5571f5207b7SJohn Levon 		break;
5581f5207b7SJohn Levon 	case OP_DIVS:
559*c85f09ccSJohn Levon 		assert(!is_float_type(insn->type));
5601f5207b7SJohn Levon 		target = LLVMBuildSDiv(fn->builder, lhs, rhs, target_name);
5611f5207b7SJohn Levon 		break;
5621f5207b7SJohn Levon 	case OP_MODU:
563*c85f09ccSJohn Levon 		assert(!is_float_type(insn->type));
5641f5207b7SJohn Levon 		target = LLVMBuildURem(fn->builder, lhs, rhs, target_name);
5651f5207b7SJohn Levon 		break;
5661f5207b7SJohn Levon 	case OP_MODS:
567*c85f09ccSJohn Levon 		assert(!is_float_type(insn->type));
5681f5207b7SJohn Levon 		target = LLVMBuildSRem(fn->builder, lhs, rhs, target_name);
5691f5207b7SJohn Levon 		break;
5701f5207b7SJohn Levon 	case OP_SHL:
571*c85f09ccSJohn Levon 		assert(!is_float_type(insn->type));
5721f5207b7SJohn Levon 		target = LLVMBuildShl(fn->builder, lhs, rhs, target_name);
5731f5207b7SJohn Levon 		break;
5741f5207b7SJohn Levon 	case OP_LSR:
575*c85f09ccSJohn Levon 		assert(!is_float_type(insn->type));
5761f5207b7SJohn Levon 		target = LLVMBuildLShr(fn->builder, lhs, rhs, target_name);
5771f5207b7SJohn Levon 		break;
5781f5207b7SJohn Levon 	case OP_ASR:
579*c85f09ccSJohn Levon 		assert(!is_float_type(insn->type));
5801f5207b7SJohn Levon 		target = LLVMBuildAShr(fn->builder, lhs, rhs, target_name);
5811f5207b7SJohn Levon 		break;
582*c85f09ccSJohn Levon 
583*c85f09ccSJohn Levon 	/* floating-point */
584*c85f09ccSJohn Levon 	case OP_FADD:
585*c85f09ccSJohn Levon 		target = LLVMBuildFAdd(fn->builder, lhs, rhs, target_name);
586*c85f09ccSJohn Levon 		break;
587*c85f09ccSJohn Levon 	case OP_FSUB:
588*c85f09ccSJohn Levon 		target = LLVMBuildFSub(fn->builder, lhs, rhs, target_name);
589*c85f09ccSJohn Levon 		break;
590*c85f09ccSJohn Levon 	case OP_FMUL:
591*c85f09ccSJohn Levon 		target = LLVMBuildFMul(fn->builder, lhs, rhs, target_name);
592*c85f09ccSJohn Levon 		break;
593*c85f09ccSJohn Levon 	case OP_FDIV:
594*c85f09ccSJohn Levon 		target = LLVMBuildFDiv(fn->builder, lhs, rhs, target_name);
595*c85f09ccSJohn Levon 		break;
5961f5207b7SJohn Levon 
5971f5207b7SJohn Levon 	/* Logical */
5981f5207b7SJohn Levon 	case OP_AND:
599*c85f09ccSJohn Levon 		assert(!is_float_type(insn->type));
6001f5207b7SJohn Levon 		target = LLVMBuildAnd(fn->builder, lhs, rhs, target_name);
6011f5207b7SJohn Levon 		break;
6021f5207b7SJohn Levon 	case OP_OR:
603*c85f09ccSJohn Levon 		assert(!is_float_type(insn->type));
6041f5207b7SJohn Levon 		target = LLVMBuildOr(fn->builder, lhs, rhs, target_name);
6051f5207b7SJohn Levon 		break;
6061f5207b7SJohn Levon 	case OP_XOR:
607*c85f09ccSJohn Levon 		assert(!is_float_type(insn->type));
6081f5207b7SJohn Levon 		target = LLVMBuildXor(fn->builder, lhs, rhs, target_name);
6091f5207b7SJohn Levon 		break;
6101f5207b7SJohn Levon 	default:
6111f5207b7SJohn Levon 		assert(0);
6121f5207b7SJohn Levon 		break;
6131f5207b7SJohn Levon 	}
6141f5207b7SJohn Levon 
615*c85f09ccSJohn Levon 	target = adjust_type(fn, insn->type, target);
6161f5207b7SJohn Levon 	insn->target->priv = target;
6171f5207b7SJohn Levon }
6181f5207b7SJohn Levon 
output_op_compare(struct function * fn,struct instruction * insn)6191f5207b7SJohn Levon static void output_op_compare(struct function *fn, struct instruction *insn)
6201f5207b7SJohn Levon {
6211f5207b7SJohn Levon 	LLVMValueRef lhs, rhs, target;
6221f5207b7SJohn Levon 	char target_name[64];
6231f5207b7SJohn Levon 
624*c85f09ccSJohn Levon 	lhs = pseudo_to_value(fn, NULL, insn->src1);
6251f5207b7SJohn Levon 	if (insn->src2->type == PSEUDO_VAL)
626*c85f09ccSJohn Levon 		rhs = constant_value(insn->src2->value, LLVMTypeOf(lhs));
6271f5207b7SJohn Levon 	else
628*c85f09ccSJohn Levon 		rhs = pseudo_to_value(fn, NULL, insn->src2);
629*c85f09ccSJohn Levon 	if (!rhs)
630*c85f09ccSJohn Levon 		rhs = LLVMGetUndef(symbol_type(insn->type));
6311f5207b7SJohn Levon 
6321f5207b7SJohn Levon 	pseudo_name(insn->target, target_name);
6331f5207b7SJohn Levon 
634*c85f09ccSJohn Levon 	LLVMTypeRef dst_type = insn_symbol_type(insn);
6351f5207b7SJohn Levon 
636*c85f09ccSJohn Levon 	switch  (LLVMGetTypeKind(LLVMTypeOf(lhs))) {
637*c85f09ccSJohn Levon 	case LLVMPointerTypeKind:
638*c85f09ccSJohn Levon 		lhs = value_to_pvalue(fn, &ptr_ctype, lhs);
639*c85f09ccSJohn Levon 		rhs = value_to_pvalue(fn, &ptr_ctype, rhs);
640*c85f09ccSJohn Levon 		/* fall through */
641*c85f09ccSJohn Levon 
642*c85f09ccSJohn Levon 	case LLVMIntegerTypeKind: {
6431f5207b7SJohn Levon 		LLVMIntPredicate op = translate_op(insn->opcode);
6441f5207b7SJohn Levon 
645*c85f09ccSJohn Levon 		if (LLVMGetTypeKind(LLVMTypeOf(rhs)) == LLVMPointerTypeKind) {
646*c85f09ccSJohn Levon 			LLVMTypeRef ltype = LLVMTypeOf(lhs);
647*c85f09ccSJohn Levon 			rhs = LLVMBuildPtrToInt(fn->builder, rhs, ltype, "");
648*c85f09ccSJohn Levon 		}
6491f5207b7SJohn Levon 		target = LLVMBuildICmp(fn->builder, op, lhs, rhs, target_name);
650*c85f09ccSJohn Levon 		break;
651*c85f09ccSJohn Levon 	}
652*c85f09ccSJohn Levon 	case LLVMHalfTypeKind:
653*c85f09ccSJohn Levon 	case LLVMFloatTypeKind:
654*c85f09ccSJohn Levon 	case LLVMDoubleTypeKind:
655*c85f09ccSJohn Levon 	case LLVMX86_FP80TypeKind:
656*c85f09ccSJohn Levon 	case LLVMFP128TypeKind:
657*c85f09ccSJohn Levon 	case LLVMPPC_FP128TypeKind: {
6581f5207b7SJohn Levon 		LLVMRealPredicate op = translate_fop(insn->opcode);
6591f5207b7SJohn Levon 
6601f5207b7SJohn Levon 		target = LLVMBuildFCmp(fn->builder, op, lhs, rhs, target_name);
661*c85f09ccSJohn Levon 		break;
662*c85f09ccSJohn Levon 	}
663*c85f09ccSJohn Levon 	default:
664*c85f09ccSJohn Levon 		assert(0);
6651f5207b7SJohn Levon 	}
6661f5207b7SJohn Levon 
6671f5207b7SJohn Levon 	target = LLVMBuildZExt(fn->builder, target, dst_type, target_name);
6681f5207b7SJohn Levon 
6691f5207b7SJohn Levon 	insn->target->priv = target;
6701f5207b7SJohn Levon }
6711f5207b7SJohn Levon 
output_op_ret(struct function * fn,struct instruction * insn)6721f5207b7SJohn Levon static void output_op_ret(struct function *fn, struct instruction *insn)
6731f5207b7SJohn Levon {
6741f5207b7SJohn Levon 	pseudo_t pseudo = insn->src;
6751f5207b7SJohn Levon 
6761f5207b7SJohn Levon 	if (pseudo && pseudo != VOID) {
677*c85f09ccSJohn Levon 		LLVMValueRef result = get_operand(fn, insn->type, pseudo);
6781f5207b7SJohn Levon 		LLVMBuildRet(fn->builder, result);
6791f5207b7SJohn Levon 	} else
6801f5207b7SJohn Levon 		LLVMBuildRetVoid(fn->builder);
6811f5207b7SJohn Levon }
6821f5207b7SJohn Levon 
calc_memop_addr(struct function * fn,struct instruction * insn)6831f5207b7SJohn Levon static LLVMValueRef calc_memop_addr(struct function *fn, struct instruction *insn)
6841f5207b7SJohn Levon {
6851f5207b7SJohn Levon 	LLVMTypeRef int_type, addr_type;
6861f5207b7SJohn Levon 	LLVMValueRef src, off, addr;
6871f5207b7SJohn Levon 	unsigned int as;
6881f5207b7SJohn Levon 
6891f5207b7SJohn Levon 	/* int type large enough to hold a pointer */
6901f5207b7SJohn Levon 	int_type = LLVMIntType(bits_in_pointer);
6911f5207b7SJohn Levon 	off = LLVMConstInt(int_type, insn->offset, 0);
6921f5207b7SJohn Levon 
6931f5207b7SJohn Levon 	/* convert src to the effective pointer type */
694*c85f09ccSJohn Levon 	src = pseudo_to_value(fn, insn->type, insn->src);
6951f5207b7SJohn Levon 	as = LLVMGetPointerAddressSpace(LLVMTypeOf(src));
696*c85f09ccSJohn Levon 	addr_type = LLVMPointerType(insn_symbol_type(insn), as);
697*c85f09ccSJohn Levon 	src = LLVMBuildPointerCast(fn->builder, src, addr_type, LLVMGetValueName(src));
6981f5207b7SJohn Levon 
6991f5207b7SJohn Levon 	/* addr = src + off */
7001f5207b7SJohn Levon 	addr = calc_gep(fn->builder, src, off);
7011f5207b7SJohn Levon 	return addr;
7021f5207b7SJohn Levon }
7031f5207b7SJohn Levon 
7041f5207b7SJohn Levon 
output_op_load(struct function * fn,struct instruction * insn)7051f5207b7SJohn Levon static void output_op_load(struct function *fn, struct instruction *insn)
7061f5207b7SJohn Levon {
7071f5207b7SJohn Levon 	LLVMValueRef addr, target;
708*c85f09ccSJohn Levon 	char name[MAX_PSEUDO_NAME];
7091f5207b7SJohn Levon 
7101f5207b7SJohn Levon 	addr = calc_memop_addr(fn, insn);
7111f5207b7SJohn Levon 
7121f5207b7SJohn Levon 	/* perform load */
713*c85f09ccSJohn Levon 	pseudo_name(insn->target, name);
714*c85f09ccSJohn Levon 	target = LLVMBuildLoad(fn->builder, addr, name);
7151f5207b7SJohn Levon 
7161f5207b7SJohn Levon 	insn->target->priv = target;
7171f5207b7SJohn Levon }
7181f5207b7SJohn Levon 
output_op_store(struct function * fn,struct instruction * insn)7191f5207b7SJohn Levon static void output_op_store(struct function *fn, struct instruction *insn)
7201f5207b7SJohn Levon {
721*c85f09ccSJohn Levon 	LLVMValueRef addr, target_in;
7221f5207b7SJohn Levon 
7231f5207b7SJohn Levon 	addr = calc_memop_addr(fn, insn);
7241f5207b7SJohn Levon 
725*c85f09ccSJohn Levon 	target_in = pseudo_to_rvalue(fn, insn->type, insn->target);
7261f5207b7SJohn Levon 
7271f5207b7SJohn Levon 	/* perform store */
728*c85f09ccSJohn Levon 	LLVMBuildStore(fn->builder, target_in, addr);
7291f5207b7SJohn Levon }
7301f5207b7SJohn Levon 
bool_value(struct function * fn,LLVMValueRef value)7311f5207b7SJohn Levon static LLVMValueRef bool_value(struct function *fn, LLVMValueRef value)
7321f5207b7SJohn Levon {
7331f5207b7SJohn Levon 	if (LLVMTypeOf(value) != LLVMInt1Type())
734*c85f09ccSJohn Levon 		value = LLVMBuildIsNotNull(fn->builder, value, LLVMGetValueName(value));
7351f5207b7SJohn Levon 
7361f5207b7SJohn Levon 	return value;
7371f5207b7SJohn Levon }
7381f5207b7SJohn Levon 
output_op_cbr(struct function * fn,struct instruction * br)7391f5207b7SJohn Levon static void output_op_cbr(struct function *fn, struct instruction *br)
7401f5207b7SJohn Levon {
7411f5207b7SJohn Levon 	LLVMValueRef cond = bool_value(fn,
742*c85f09ccSJohn Levon 			pseudo_to_value(fn, NULL, br->cond));
7431f5207b7SJohn Levon 
7441f5207b7SJohn Levon 	LLVMBuildCondBr(fn->builder, cond,
7451f5207b7SJohn Levon 			br->bb_true->priv,
7461f5207b7SJohn Levon 			br->bb_false->priv);
7471f5207b7SJohn Levon }
7481f5207b7SJohn Levon 
output_op_br(struct function * fn,struct instruction * br)7491f5207b7SJohn Levon static void output_op_br(struct function *fn, struct instruction *br)
7501f5207b7SJohn Levon {
7511f5207b7SJohn Levon 	LLVMBuildBr(fn->builder, br->bb_true->priv);
7521f5207b7SJohn Levon }
7531f5207b7SJohn Levon 
output_op_sel(struct function * fn,struct instruction * insn)7541f5207b7SJohn Levon static void output_op_sel(struct function *fn, struct instruction *insn)
7551f5207b7SJohn Levon {
7561f5207b7SJohn Levon 	LLVMValueRef target, src1, src2, src3;
757*c85f09ccSJohn Levon 	char name[MAX_PSEUDO_NAME];
7581f5207b7SJohn Levon 
759*c85f09ccSJohn Levon 	src1 = bool_value(fn, pseudo_to_value(fn, NULL, insn->src1));
760*c85f09ccSJohn Levon 	src2 = get_operand(fn, insn->type, insn->src2);
761*c85f09ccSJohn Levon 	src3 = get_operand(fn, insn->type, insn->src3);
7621f5207b7SJohn Levon 
763*c85f09ccSJohn Levon 	pseudo_name(insn->target, name);
764*c85f09ccSJohn Levon 	target = LLVMBuildSelect(fn->builder, src1, src2, src3, name);
7651f5207b7SJohn Levon 
766*c85f09ccSJohn Levon 	insn->target->priv = adjust_type(fn, insn->type, target);
7671f5207b7SJohn Levon }
7681f5207b7SJohn Levon 
output_op_switch(struct function * fn,struct instruction * insn)7691f5207b7SJohn Levon static void output_op_switch(struct function *fn, struct instruction *insn)
7701f5207b7SJohn Levon {
7711f5207b7SJohn Levon 	LLVMValueRef sw_val, target;
7721f5207b7SJohn Levon 	struct basic_block *def = NULL;
7731f5207b7SJohn Levon 	struct multijmp *jmp;
7741f5207b7SJohn Levon 	int n_jmp = 0;
7751f5207b7SJohn Levon 
7761f5207b7SJohn Levon 	FOR_EACH_PTR(insn->multijmp_list, jmp) {
777*c85f09ccSJohn Levon 		if (jmp->begin <= jmp->end) {
778*c85f09ccSJohn Levon 			n_jmp += (jmp->end - jmp->begin) + 1;
7791f5207b7SJohn Levon 		} else					/* default case */
7801f5207b7SJohn Levon 			def = jmp->target;
7811f5207b7SJohn Levon 	} END_FOR_EACH_PTR(jmp);
7821f5207b7SJohn Levon 
783*c85f09ccSJohn Levon 	sw_val = get_ioperand(fn, insn->type, insn->cond);
7841f5207b7SJohn Levon 	target = LLVMBuildSwitch(fn->builder, sw_val,
7851f5207b7SJohn Levon 				 def ? def->priv : NULL, n_jmp);
7861f5207b7SJohn Levon 
7871f5207b7SJohn Levon 	FOR_EACH_PTR(insn->multijmp_list, jmp) {
788*c85f09ccSJohn Levon 		long long val;
789*c85f09ccSJohn Levon 
790*c85f09ccSJohn Levon 		for (val = jmp->begin; val <= jmp->end; val++) {
791*c85f09ccSJohn Levon 			LLVMValueRef Val = val_to_value(val, insn->type);
792*c85f09ccSJohn Levon 			LLVMAddCase(target, Val, jmp->target->priv);
7931f5207b7SJohn Levon 		}
7941f5207b7SJohn Levon 	} END_FOR_EACH_PTR(jmp);
7951f5207b7SJohn Levon }
7961f5207b7SJohn Levon 
output_op_call(struct function * fn,struct instruction * insn)7971f5207b7SJohn Levon static void output_op_call(struct function *fn, struct instruction *insn)
7981f5207b7SJohn Levon {
7991f5207b7SJohn Levon 	LLVMValueRef target, func;
800*c85f09ccSJohn Levon 	struct symbol *ctype;
8011f5207b7SJohn Levon 	int n_arg = 0, i;
8021f5207b7SJohn Levon 	struct pseudo *arg;
8031f5207b7SJohn Levon 	LLVMValueRef *args;
804*c85f09ccSJohn Levon 	char name[64];
8051f5207b7SJohn Levon 
806*c85f09ccSJohn Levon 	n_arg = pseudo_list_size(insn->arguments);
8071f5207b7SJohn Levon 	args = calloc(n_arg, sizeof(LLVMValueRef));
8081f5207b7SJohn Levon 
809*c85f09ccSJohn Levon 	PREPARE_PTR_LIST(insn->fntypes, ctype);
810*c85f09ccSJohn Levon 	if (insn->func->type == PSEUDO_REG || insn->func->type == PSEUDO_PHI)
811*c85f09ccSJohn Levon 		func = get_operand(fn, ctype, insn->func);
812*c85f09ccSJohn Levon 	else
813*c85f09ccSJohn Levon 		func = pseudo_to_value(fn, ctype, insn->func);
8141f5207b7SJohn Levon 	i = 0;
8151f5207b7SJohn Levon 	FOR_EACH_PTR(insn->arguments, arg) {
816*c85f09ccSJohn Levon 		NEXT_PTR_LIST(ctype);
817*c85f09ccSJohn Levon 		args[i++] = pseudo_to_rvalue(fn, ctype, arg);
8181f5207b7SJohn Levon 	} END_FOR_EACH_PTR(arg);
819*c85f09ccSJohn Levon 	FINISH_PTR_LIST(ctype);
8201f5207b7SJohn Levon 
821*c85f09ccSJohn Levon 	pseudo_name(insn->target, name);
822*c85f09ccSJohn Levon 	target = LLVMBuildCall(fn->builder, func, args, n_arg, name);
8231f5207b7SJohn Levon 
8241f5207b7SJohn Levon 	insn->target->priv = target;
8251f5207b7SJohn Levon }
8261f5207b7SJohn Levon 
output_op_phisrc(struct function * fn,struct instruction * insn)8271f5207b7SJohn Levon static void output_op_phisrc(struct function *fn, struct instruction *insn)
8281f5207b7SJohn Levon {
8291f5207b7SJohn Levon 	LLVMValueRef v;
8301f5207b7SJohn Levon 	struct instruction *phi;
8311f5207b7SJohn Levon 
8321f5207b7SJohn Levon 	assert(insn->target->priv == NULL);
8331f5207b7SJohn Levon 
8341f5207b7SJohn Levon 	/* target = src */
835*c85f09ccSJohn Levon 	v = get_operand(fn, insn->type, insn->phi_src);
8361f5207b7SJohn Levon 
8371f5207b7SJohn Levon 	FOR_EACH_PTR(insn->phi_users, phi) {
8381f5207b7SJohn Levon 		LLVMValueRef load, ptr;
8391f5207b7SJohn Levon 
8401f5207b7SJohn Levon 		assert(phi->opcode == OP_PHI);
8411f5207b7SJohn Levon 		/* phi must be load from alloca */
8421f5207b7SJohn Levon 		load = phi->target->priv;
8431f5207b7SJohn Levon 		assert(LLVMGetInstructionOpcode(load) == LLVMLoad);
8441f5207b7SJohn Levon 		ptr = LLVMGetOperand(load, 0);
8451f5207b7SJohn Levon 		/* store v to alloca */
8461f5207b7SJohn Levon 		LLVMBuildStore(fn->builder, v, ptr);
8471f5207b7SJohn Levon 	} END_FOR_EACH_PTR(phi);
8481f5207b7SJohn Levon }
8491f5207b7SJohn Levon 
output_op_phi(struct function * fn,struct instruction * insn)8501f5207b7SJohn Levon static void output_op_phi(struct function *fn, struct instruction *insn)
8511f5207b7SJohn Levon {
8521f5207b7SJohn Levon 	LLVMValueRef load = insn->target->priv;
8531f5207b7SJohn Levon 
8541f5207b7SJohn Levon 	/* forward load */
8551f5207b7SJohn Levon 	assert(LLVMGetInstructionOpcode(load) == LLVMLoad);
8561f5207b7SJohn Levon 	/* forward load has no parent block */
8571f5207b7SJohn Levon 	assert(!LLVMGetInstructionParent(load));
8581f5207b7SJohn Levon 	/* finalize load in current block  */
8591f5207b7SJohn Levon 	LLVMInsertIntoBuilder(fn->builder, load);
8601f5207b7SJohn Levon }
8611f5207b7SJohn Levon 
output_op_ptrcast(struct function * fn,struct instruction * insn)8621f5207b7SJohn Levon static void output_op_ptrcast(struct function *fn, struct instruction *insn)
8631f5207b7SJohn Levon {
8641f5207b7SJohn Levon 	LLVMValueRef src, target;
865*c85f09ccSJohn Levon 	LLVMTypeRef dtype;
866*c85f09ccSJohn Levon 	struct symbol *otype = insn->orig_type;
867*c85f09ccSJohn Levon 	LLVMOpcode op;
8681f5207b7SJohn Levon 	char target_name[64];
8691f5207b7SJohn Levon 
870*c85f09ccSJohn Levon 	src = get_operand(fn, otype, insn->src);
8711f5207b7SJohn Levon 	pseudo_name(insn->target, target_name);
8721f5207b7SJohn Levon 
873*c85f09ccSJohn Levon 	dtype = symbol_type(insn->type);
874*c85f09ccSJohn Levon 	switch (insn->opcode) {
875*c85f09ccSJohn Levon 	case OP_UTPTR:
876*c85f09ccSJohn Levon 	case OP_SEXT:			// FIXME
877*c85f09ccSJohn Levon 		assert(is_int_type(otype));
878*c85f09ccSJohn Levon 		assert(is_ptr_type(insn->type));
879*c85f09ccSJohn Levon 		op = LLVMIntToPtr;
880*c85f09ccSJohn Levon 		break;
881*c85f09ccSJohn Levon 	case OP_PTRTU:
882*c85f09ccSJohn Levon 		assert(is_ptr_type(otype));
883*c85f09ccSJohn Levon 		assert(is_int_type(insn->type));
884*c85f09ccSJohn Levon 		op = LLVMPtrToInt;
885*c85f09ccSJohn Levon 		break;
886*c85f09ccSJohn Levon 	case OP_PTRCAST:
887*c85f09ccSJohn Levon 	case OP_ZEXT:			// FIXME
888*c85f09ccSJohn Levon 		assert(is_ptr_type(otype));
889*c85f09ccSJohn Levon 		assert(is_ptr_type(insn->type));
890*c85f09ccSJohn Levon 		op = LLVMBitCast;
891*c85f09ccSJohn Levon 		break;
892*c85f09ccSJohn Levon 	default:
893*c85f09ccSJohn Levon 		assert(0);
894*c85f09ccSJohn Levon 	}
8951f5207b7SJohn Levon 
896*c85f09ccSJohn Levon 	target = LLVMBuildCast(fn->builder, op, src, dtype, target_name);
8971f5207b7SJohn Levon 	insn->target->priv = target;
8981f5207b7SJohn Levon }
8991f5207b7SJohn Levon 
output_op_cast(struct function * fn,struct instruction * insn,LLVMOpcode op)9001f5207b7SJohn Levon static void output_op_cast(struct function *fn, struct instruction *insn, LLVMOpcode op)
9011f5207b7SJohn Levon {
9021f5207b7SJohn Levon 	LLVMValueRef src, target;
903*c85f09ccSJohn Levon 	LLVMTypeRef dtype;
904*c85f09ccSJohn Levon 	struct symbol *otype = insn->orig_type;
9051f5207b7SJohn Levon 	char target_name[64];
9061f5207b7SJohn Levon 
907*c85f09ccSJohn Levon 	if (is_ptr_type(insn->type))	// cast to void* is OP_CAST ...
908*c85f09ccSJohn Levon 		return output_op_ptrcast(fn, insn);
9091f5207b7SJohn Levon 
910*c85f09ccSJohn Levon 	assert(is_int_type(insn->type));
911*c85f09ccSJohn Levon 
912*c85f09ccSJohn Levon 	src = get_operand(fn, otype, insn->src);
9131f5207b7SJohn Levon 	pseudo_name(insn->target, target_name);
9141f5207b7SJohn Levon 
915*c85f09ccSJohn Levon 	dtype = symbol_type(insn->type);
916*c85f09ccSJohn Levon 	if (is_ptr_type(otype)) {
917*c85f09ccSJohn Levon 		op = LLVMPtrToInt;
918*c85f09ccSJohn Levon 	} else if (is_float_type(otype)) {
919*c85f09ccSJohn Levon 		assert(op == LLVMFPToUI || op == LLVMFPToSI);
920*c85f09ccSJohn Levon 	} else if (is_int_type(otype)) {
921*c85f09ccSJohn Levon 		unsigned int width = otype->bit_size;
922*c85f09ccSJohn Levon 		if (insn->size < width)
923*c85f09ccSJohn Levon 			op = LLVMTrunc;
924*c85f09ccSJohn Levon 		else if (insn->size == width)
925*c85f09ccSJohn Levon 			op = LLVMBitCast;
926*c85f09ccSJohn Levon 	} else {
927*c85f09ccSJohn Levon 		assert(0);
928*c85f09ccSJohn Levon 	}
9291f5207b7SJohn Levon 
930*c85f09ccSJohn Levon 	target = LLVMBuildCast(fn->builder, op, src, dtype, target_name);
931*c85f09ccSJohn Levon 	insn->target->priv = target;
932*c85f09ccSJohn Levon }
933*c85f09ccSJohn Levon 
output_op_fpcast(struct function * fn,struct instruction * insn)934*c85f09ccSJohn Levon static void output_op_fpcast(struct function *fn, struct instruction *insn)
935*c85f09ccSJohn Levon {
936*c85f09ccSJohn Levon 	LLVMTypeRef dtype = symbol_type(insn->type);
937*c85f09ccSJohn Levon 	LLVMValueRef src, target;
938*c85f09ccSJohn Levon 	struct symbol *otype = insn->orig_type;
939*c85f09ccSJohn Levon 	char name[64];
940*c85f09ccSJohn Levon 
941*c85f09ccSJohn Levon 	assert(is_float_type(insn->type));
942*c85f09ccSJohn Levon 
943*c85f09ccSJohn Levon 	pseudo_name(insn->target, name);
944*c85f09ccSJohn Levon 	src = get_operand(fn, otype, insn->src);
945*c85f09ccSJohn Levon 	switch (insn->opcode) {
946*c85f09ccSJohn Levon 	case OP_FCVTF:
947*c85f09ccSJohn Levon 		target = LLVMBuildFPCast(fn->builder, src, dtype, name);
948*c85f09ccSJohn Levon 		break;
949*c85f09ccSJohn Levon 	case OP_SCVTF:
950*c85f09ccSJohn Levon 		target = LLVMBuildSIToFP(fn->builder, src, dtype, name);
951*c85f09ccSJohn Levon 		break;
952*c85f09ccSJohn Levon 	case OP_UCVTF:
953*c85f09ccSJohn Levon 		target = LLVMBuildUIToFP(fn->builder, src, dtype, name);
954*c85f09ccSJohn Levon 		break;
955*c85f09ccSJohn Levon 	default:
956*c85f09ccSJohn Levon 		assert(0);
957*c85f09ccSJohn Levon 	}
958*c85f09ccSJohn Levon 	insn->target->priv = target;
959*c85f09ccSJohn Levon }
960*c85f09ccSJohn Levon 
output_op_setval(struct function * fn,struct instruction * insn)961*c85f09ccSJohn Levon static void output_op_setval(struct function *fn, struct instruction *insn)
962*c85f09ccSJohn Levon {
963*c85f09ccSJohn Levon 	struct expression *val = insn->val;
964*c85f09ccSJohn Levon 	LLVMValueRef target;
965*c85f09ccSJohn Levon 
966*c85f09ccSJohn Levon 	switch (val->type) {
967*c85f09ccSJohn Levon 	case EXPR_LABEL:
968*c85f09ccSJohn Levon 		target = LLVMBlockAddress(fn->fn, val->symbol->bb_target->priv);
969*c85f09ccSJohn Levon 		break;
970*c85f09ccSJohn Levon 	default:
971*c85f09ccSJohn Levon 		assert(0);
972*c85f09ccSJohn Levon 	}
9731f5207b7SJohn Levon 
9741f5207b7SJohn Levon 	insn->target->priv = target;
9751f5207b7SJohn Levon }
9761f5207b7SJohn Levon 
output_op_setfval(struct function * fn,struct instruction * insn)977*c85f09ccSJohn Levon static void output_op_setfval(struct function *fn, struct instruction *insn)
978*c85f09ccSJohn Levon {
979*c85f09ccSJohn Levon 	LLVMTypeRef dtype = symbol_type(insn->type);
980*c85f09ccSJohn Levon 	LLVMValueRef target;
981*c85f09ccSJohn Levon 
982*c85f09ccSJohn Levon 	target = LLVMConstReal(dtype, insn->fvalue);
983*c85f09ccSJohn Levon 	insn->target->priv = target;
984*c85f09ccSJohn Levon }
985*c85f09ccSJohn Levon 
output_insn(struct function * fn,struct instruction * insn)9861f5207b7SJohn Levon static void output_insn(struct function *fn, struct instruction *insn)
9871f5207b7SJohn Levon {
9881f5207b7SJohn Levon 	switch (insn->opcode) {
9891f5207b7SJohn Levon 	case OP_RET:
9901f5207b7SJohn Levon 		output_op_ret(fn, insn);
9911f5207b7SJohn Levon 		break;
9921f5207b7SJohn Levon 	case OP_BR:
9931f5207b7SJohn Levon 		output_op_br(fn, insn);
9941f5207b7SJohn Levon 		break;
9951f5207b7SJohn Levon 	case OP_CBR:
9961f5207b7SJohn Levon 		output_op_cbr(fn, insn);
9971f5207b7SJohn Levon 		break;
9981f5207b7SJohn Levon 	case OP_SYMADDR:
9991f5207b7SJohn Levon 		assert(0);
10001f5207b7SJohn Levon 		break;
10011f5207b7SJohn Levon 	case OP_SETVAL:
1002*c85f09ccSJohn Levon 		output_op_setval(fn, insn);
1003*c85f09ccSJohn Levon 		break;
1004*c85f09ccSJohn Levon 	case OP_SETFVAL:
1005*c85f09ccSJohn Levon 		output_op_setfval(fn, insn);
10061f5207b7SJohn Levon 		break;
10071f5207b7SJohn Levon 	case OP_SWITCH:
10081f5207b7SJohn Levon 		output_op_switch(fn, insn);
10091f5207b7SJohn Levon 		break;
10101f5207b7SJohn Levon 	case OP_COMPUTEDGOTO:
10111f5207b7SJohn Levon 		assert(0);
10121f5207b7SJohn Levon 		break;
10131f5207b7SJohn Levon 	case OP_PHISOURCE:
10141f5207b7SJohn Levon 		output_op_phisrc(fn, insn);
10151f5207b7SJohn Levon 		break;
10161f5207b7SJohn Levon 	case OP_PHI:
10171f5207b7SJohn Levon 		output_op_phi(fn, insn);
10181f5207b7SJohn Levon 		break;
10191f5207b7SJohn Levon 	case OP_LOAD:
10201f5207b7SJohn Levon 		output_op_load(fn, insn);
10211f5207b7SJohn Levon 		break;
10221f5207b7SJohn Levon 	case OP_STORE:
10231f5207b7SJohn Levon 		output_op_store(fn, insn);
10241f5207b7SJohn Levon 		break;
10251f5207b7SJohn Levon 	case OP_INLINED_CALL:
10261f5207b7SJohn Levon 		break;
10271f5207b7SJohn Levon 	case OP_CALL:
10281f5207b7SJohn Levon 		output_op_call(fn, insn);
10291f5207b7SJohn Levon 		break;
1030*c85f09ccSJohn Levon 	case OP_ZEXT:
10311f5207b7SJohn Levon 		output_op_cast(fn, insn, LLVMZExt);
10321f5207b7SJohn Levon 		break;
1033*c85f09ccSJohn Levon 	case OP_SEXT:
10341f5207b7SJohn Levon 		output_op_cast(fn, insn, LLVMSExt);
10351f5207b7SJohn Levon 		break;
1036*c85f09ccSJohn Levon 	case OP_TRUNC:
1037*c85f09ccSJohn Levon 		output_op_cast(fn, insn, LLVMTrunc);
10381f5207b7SJohn Levon 		break;
1039*c85f09ccSJohn Levon 	case OP_FCVTU:
1040*c85f09ccSJohn Levon 		output_op_cast(fn, insn, LLVMFPToUI);
1041*c85f09ccSJohn Levon 		break;
1042*c85f09ccSJohn Levon 	case OP_FCVTS:
1043*c85f09ccSJohn Levon 		output_op_cast(fn, insn, LLVMFPToSI);
1044*c85f09ccSJohn Levon 		break;
1045*c85f09ccSJohn Levon 	case OP_UCVTF: case OP_SCVTF:
1046*c85f09ccSJohn Levon 	case OP_FCVTF:
1047*c85f09ccSJohn Levon 		output_op_fpcast(fn, insn);
1048*c85f09ccSJohn Levon 		break;
1049*c85f09ccSJohn Levon 	case OP_UTPTR:
1050*c85f09ccSJohn Levon 	case OP_PTRTU:
10511f5207b7SJohn Levon 	case OP_PTRCAST:
10521f5207b7SJohn Levon 		output_op_ptrcast(fn, insn);
10531f5207b7SJohn Levon 		break;
10541f5207b7SJohn Levon 	case OP_BINARY ... OP_BINARY_END:
10551f5207b7SJohn Levon 		output_op_binary(fn, insn);
10561f5207b7SJohn Levon 		break;
1057*c85f09ccSJohn Levon 	case OP_FPCMP ... OP_BINCMP_END:
10581f5207b7SJohn Levon 		output_op_compare(fn, insn);
10591f5207b7SJohn Levon 		break;
10601f5207b7SJohn Levon 	case OP_SEL:
10611f5207b7SJohn Levon 		output_op_sel(fn, insn);
10621f5207b7SJohn Levon 		break;
10631f5207b7SJohn Levon 	case OP_SLICE:
10641f5207b7SJohn Levon 		assert(0);
10651f5207b7SJohn Levon 		break;
10661f5207b7SJohn Levon 	case OP_NOT: {
10671f5207b7SJohn Levon 		LLVMValueRef src, target;
10681f5207b7SJohn Levon 		char target_name[64];
10691f5207b7SJohn Levon 
1070*c85f09ccSJohn Levon 		src = pseudo_to_value(fn, insn->type, insn->src);
10711f5207b7SJohn Levon 
10721f5207b7SJohn Levon 		pseudo_name(insn->target, target_name);
10731f5207b7SJohn Levon 
10741f5207b7SJohn Levon 		target = LLVMBuildNot(fn->builder, src, target_name);
10751f5207b7SJohn Levon 
10761f5207b7SJohn Levon 		insn->target->priv = target;
10771f5207b7SJohn Levon 		break;
10781f5207b7SJohn Levon 	}
1079*c85f09ccSJohn Levon 	case OP_FNEG:
1080*c85f09ccSJohn Levon 	case OP_NEG: {
1081*c85f09ccSJohn Levon 		LLVMValueRef src, target;
1082*c85f09ccSJohn Levon 		char target_name[64];
1083*c85f09ccSJohn Levon 
1084*c85f09ccSJohn Levon 		src = pseudo_to_value(fn, insn->type, insn->src);
1085*c85f09ccSJohn Levon 
1086*c85f09ccSJohn Levon 		pseudo_name(insn->target, target_name);
1087*c85f09ccSJohn Levon 
1088*c85f09ccSJohn Levon 		if (insn->opcode == OP_FNEG)
1089*c85f09ccSJohn Levon 			target = LLVMBuildFNeg(fn->builder, src, target_name);
1090*c85f09ccSJohn Levon 		else
1091*c85f09ccSJohn Levon 			target = LLVMBuildNeg(fn->builder, src, target_name);
1092*c85f09ccSJohn Levon 
1093*c85f09ccSJohn Levon 		insn->target->priv = target;
10941f5207b7SJohn Levon 		break;
1095*c85f09ccSJohn Levon 	}
10961f5207b7SJohn Levon 	case OP_CONTEXT:
10971f5207b7SJohn Levon 		assert(0);
10981f5207b7SJohn Levon 		break;
10991f5207b7SJohn Levon 	case OP_RANGE:
11001f5207b7SJohn Levon 		assert(0);
11011f5207b7SJohn Levon 		break;
11021f5207b7SJohn Levon 	case OP_NOP:
11031f5207b7SJohn Levon 		assert(0);
11041f5207b7SJohn Levon 		break;
11051f5207b7SJohn Levon 	case OP_DEATHNOTE:
11061f5207b7SJohn Levon 		break;
11071f5207b7SJohn Levon 	case OP_ASM:
11081f5207b7SJohn Levon 		assert(0);
11091f5207b7SJohn Levon 		break;
11101f5207b7SJohn Levon 	case OP_COPY:
11111f5207b7SJohn Levon 		assert(0);
11121f5207b7SJohn Levon 		break;
11131f5207b7SJohn Levon 	default:
11141f5207b7SJohn Levon 		break;
11151f5207b7SJohn Levon 	}
11161f5207b7SJohn Levon }
11171f5207b7SJohn Levon 
output_bb(struct function * fn,struct basic_block * bb)1118*c85f09ccSJohn Levon static void output_bb(struct function *fn, struct basic_block *bb)
11191f5207b7SJohn Levon {
11201f5207b7SJohn Levon 	struct instruction *insn;
11211f5207b7SJohn Levon 
11221f5207b7SJohn Levon 	FOR_EACH_PTR(bb->insns, insn) {
11231f5207b7SJohn Levon 		if (!insn->bb)
11241f5207b7SJohn Levon 			continue;
11251f5207b7SJohn Levon 
11261f5207b7SJohn Levon 		output_insn(fn, insn);
11271f5207b7SJohn Levon 	}
11281f5207b7SJohn Levon 	END_FOR_EACH_PTR(insn);
11291f5207b7SJohn Levon }
11301f5207b7SJohn Levon 
11311f5207b7SJohn Levon #define MAX_ARGS	64
11321f5207b7SJohn Levon 
output_fn(LLVMModuleRef module,struct entrypoint * ep)11331f5207b7SJohn Levon static void output_fn(LLVMModuleRef module, struct entrypoint *ep)
11341f5207b7SJohn Levon {
11351f5207b7SJohn Levon 	struct symbol *sym = ep->name;
11361f5207b7SJohn Levon 	struct symbol *base_type = sym->ctype.base_type;
11371f5207b7SJohn Levon 	struct function function = { .module = module };
11381f5207b7SJohn Levon 	struct basic_block *bb;
11391f5207b7SJohn Levon 	int nr_args = 0;
1140*c85f09ccSJohn Levon 	int i;
11411f5207b7SJohn Levon 
1142*c85f09ccSJohn Levon 	function.fn = get_sym_value(module, sym);
11431f5207b7SJohn Levon 	LLVMSetFunctionCallConv(function.fn, LLVMCCallConv);
11441f5207b7SJohn Levon 	LLVMSetLinkage(function.fn, function_linkage(sym));
11451f5207b7SJohn Levon 
11461f5207b7SJohn Levon 	function.builder = LLVMCreateBuilder();
11471f5207b7SJohn Levon 
1148*c85f09ccSJohn Levon 	/* give a name to each argument */
1149*c85f09ccSJohn Levon 	nr_args = symbol_list_size(base_type->arguments);
1150*c85f09ccSJohn Levon 	for (i = 0; i < nr_args; i++) {
1151*c85f09ccSJohn Levon 		char name[MAX_PSEUDO_NAME];
1152*c85f09ccSJohn Levon 		LLVMValueRef arg;
11531f5207b7SJohn Levon 
1154*c85f09ccSJohn Levon 		arg = LLVMGetParam(function.fn, i);
1155*c85f09ccSJohn Levon 		snprintf(name, sizeof(name), "ARG%d.", i+1);
1156*c85f09ccSJohn Levon 		LLVMSetValueName(arg, name);
1157*c85f09ccSJohn Levon 	}
11581f5207b7SJohn Levon 
1159*c85f09ccSJohn Levon 	/* create the BBs */
1160*c85f09ccSJohn Levon 	FOR_EACH_PTR(ep->bbs, bb) {
1161*c85f09ccSJohn Levon 		static int nr_bb;
11621f5207b7SJohn Levon 		LLVMBasicBlockRef bbr;
11631f5207b7SJohn Levon 		char bbname[32];
11641f5207b7SJohn Levon 		struct instruction *insn;
11651f5207b7SJohn Levon 
11661f5207b7SJohn Levon 		sprintf(bbname, "L%d", nr_bb++);
11671f5207b7SJohn Levon 		bbr = LLVMAppendBasicBlock(function.fn, bbname);
11681f5207b7SJohn Levon 
11691f5207b7SJohn Levon 		bb->priv = bbr;
11701f5207b7SJohn Levon 
11711f5207b7SJohn Levon 		/* allocate alloca for each phi */
11721f5207b7SJohn Levon 		FOR_EACH_PTR(bb->insns, insn) {
11731f5207b7SJohn Levon 			LLVMBasicBlockRef entrybbr;
11741f5207b7SJohn Levon 			LLVMTypeRef phi_type;
11751f5207b7SJohn Levon 			LLVMValueRef ptr;
11761f5207b7SJohn Levon 
11771f5207b7SJohn Levon 			if (!insn->bb || insn->opcode != OP_PHI)
11781f5207b7SJohn Levon 				continue;
11791f5207b7SJohn Levon 			/* insert alloca into entry block */
11801f5207b7SJohn Levon 			entrybbr = LLVMGetEntryBasicBlock(function.fn);
11811f5207b7SJohn Levon 			LLVMPositionBuilderAtEnd(function.builder, entrybbr);
1182*c85f09ccSJohn Levon 			phi_type = insn_symbol_type(insn);
11831f5207b7SJohn Levon 			ptr = LLVMBuildAlloca(function.builder, phi_type, "");
11841f5207b7SJohn Levon 			/* emit forward load for phi */
11851f5207b7SJohn Levon 			LLVMClearInsertionPosition(function.builder);
11861f5207b7SJohn Levon 			insn->target->priv = LLVMBuildLoad(function.builder, ptr, "phi");
11871f5207b7SJohn Levon 		} END_FOR_EACH_PTR(insn);
11881f5207b7SJohn Levon 	}
11891f5207b7SJohn Levon 	END_FOR_EACH_PTR(bb);
11901f5207b7SJohn Levon 
11911f5207b7SJohn Levon 	FOR_EACH_PTR(ep->bbs, bb) {
11921f5207b7SJohn Levon 		LLVMPositionBuilderAtEnd(function.builder, bb->priv);
11931f5207b7SJohn Levon 
1194*c85f09ccSJohn Levon 		output_bb(&function, bb);
11951f5207b7SJohn Levon 	}
11961f5207b7SJohn Levon 	END_FOR_EACH_PTR(bb);
11971f5207b7SJohn Levon }
11981f5207b7SJohn Levon 
output_data(LLVMModuleRef module,struct symbol * sym)11991f5207b7SJohn Levon static LLVMValueRef output_data(LLVMModuleRef module, struct symbol *sym)
12001f5207b7SJohn Levon {
12011f5207b7SJohn Levon 	struct expression *initializer = sym->initializer;
12021f5207b7SJohn Levon 	LLVMValueRef initial_value;
12031f5207b7SJohn Levon 	LLVMValueRef data;
12041f5207b7SJohn Levon 	const char *name;
12051f5207b7SJohn Levon 
12061f5207b7SJohn Levon 	if (initializer) {
12071f5207b7SJohn Levon 		switch (initializer->type) {
12081f5207b7SJohn Levon 		case EXPR_VALUE:
1209*c85f09ccSJohn Levon 			initial_value = LLVMConstInt(symbol_type(sym), initializer->value, 1);
1210*c85f09ccSJohn Levon 			break;
1211*c85f09ccSJohn Levon 		case EXPR_FVALUE:
1212*c85f09ccSJohn Levon 			initial_value = LLVMConstReal(symbol_type(sym), initializer->fvalue);
12131f5207b7SJohn Levon 			break;
12141f5207b7SJohn Levon 		case EXPR_SYMBOL: {
12151f5207b7SJohn Levon 			struct symbol *sym = initializer->symbol;
12161f5207b7SJohn Levon 
12171f5207b7SJohn Levon 			initial_value = LLVMGetNamedGlobal(module, show_ident(sym->ident));
12181f5207b7SJohn Levon 			if (!initial_value)
12191f5207b7SJohn Levon 				initial_value = output_data(module, sym);
12201f5207b7SJohn Levon 			break;
12211f5207b7SJohn Levon 		}
12221f5207b7SJohn Levon 		case EXPR_STRING: {
12231f5207b7SJohn Levon 			const char *s = initializer->string->data;
12241f5207b7SJohn Levon 
12251f5207b7SJohn Levon 			initial_value = LLVMConstString(strdup(s), strlen(s) + 1, true);
12261f5207b7SJohn Levon 			break;
12271f5207b7SJohn Levon 		}
12281f5207b7SJohn Levon 		default:
1229*c85f09ccSJohn Levon 			warning(initializer->pos, "can't initialize type: %s", show_typename(sym));
1230*c85f09ccSJohn Levon 			initial_value = NULL;
1231*c85f09ccSJohn Levon 			break;
12321f5207b7SJohn Levon 		}
12331f5207b7SJohn Levon 	} else {
1234*c85f09ccSJohn Levon 		LLVMTypeRef type = symbol_type(sym);
12351f5207b7SJohn Levon 
12361f5207b7SJohn Levon 		initial_value = LLVMConstNull(type);
12371f5207b7SJohn Levon 	}
12381f5207b7SJohn Levon 
1239*c85f09ccSJohn Levon 	if (!initial_value)
1240*c85f09ccSJohn Levon 		return NULL;
1241*c85f09ccSJohn Levon 
1242*c85f09ccSJohn Levon 	name = sym->ident ? show_ident(sym->ident) : "" ;
12431f5207b7SJohn Levon 
12441f5207b7SJohn Levon 	data = LLVMAddGlobal(module, LLVMTypeOf(initial_value), name);
12451f5207b7SJohn Levon 
12461f5207b7SJohn Levon 	LLVMSetLinkage(data, data_linkage(sym));
12471f5207b7SJohn Levon 	if (sym->ctype.modifiers & MOD_CONST)
12481f5207b7SJohn Levon 		LLVMSetGlobalConstant(data, 1);
12491f5207b7SJohn Levon 	if (sym->ctype.modifiers & MOD_TLS)
12501f5207b7SJohn Levon 		LLVMSetThreadLocal(data, 1);
12511f5207b7SJohn Levon 	if (sym->ctype.alignment)
12521f5207b7SJohn Levon 		LLVMSetAlignment(data, sym->ctype.alignment);
12531f5207b7SJohn Levon 
12541f5207b7SJohn Levon 	if (!(sym->ctype.modifiers & MOD_EXTERN))
12551f5207b7SJohn Levon 		LLVMSetInitializer(data, initial_value);
12561f5207b7SJohn Levon 
12571f5207b7SJohn Levon 	return data;
12581f5207b7SJohn Levon }
12591f5207b7SJohn Levon 
is_prototype(struct symbol * sym)12601f5207b7SJohn Levon static int is_prototype(struct symbol *sym)
12611f5207b7SJohn Levon {
12621f5207b7SJohn Levon 	if (sym->type == SYM_NODE)
12631f5207b7SJohn Levon 		sym = sym->ctype.base_type;
12641f5207b7SJohn Levon 	return sym && sym->type == SYM_FN && !sym->stmt;
12651f5207b7SJohn Levon }
12661f5207b7SJohn Levon 
compile(LLVMModuleRef module,struct symbol_list * list)12671f5207b7SJohn Levon static int compile(LLVMModuleRef module, struct symbol_list *list)
12681f5207b7SJohn Levon {
12691f5207b7SJohn Levon 	struct symbol *sym;
12701f5207b7SJohn Levon 
12711f5207b7SJohn Levon 	FOR_EACH_PTR(list, sym) {
12721f5207b7SJohn Levon 		struct entrypoint *ep;
12731f5207b7SJohn Levon 		expand_symbol(sym);
12741f5207b7SJohn Levon 
1275*c85f09ccSJohn Levon 		if (is_prototype(sym)) {
1276*c85f09ccSJohn Levon 			// this will do the LLVMAddFunction() we want
1277*c85f09ccSJohn Levon 			get_sym_value(module, sym);
12781f5207b7SJohn Levon 			continue;
1279*c85f09ccSJohn Levon 		}
12801f5207b7SJohn Levon 
12811f5207b7SJohn Levon 		ep = linearize_symbol(sym);
12821f5207b7SJohn Levon 		if (ep)
12831f5207b7SJohn Levon 			output_fn(module, ep);
12841f5207b7SJohn Levon 		else
12851f5207b7SJohn Levon 			output_data(module, sym);
12861f5207b7SJohn Levon 	}
12871f5207b7SJohn Levon 	END_FOR_EACH_PTR(sym);
12881f5207b7SJohn Levon 
12891f5207b7SJohn Levon 	return 0;
12901f5207b7SJohn Levon }
12911f5207b7SJohn Levon 
12921f5207b7SJohn Levon #ifndef LLVM_DEFAULT_TARGET_TRIPLE
12931f5207b7SJohn Levon #define LLVM_DEFAULT_TARGET_TRIPLE LLVM_HOSTTRIPLE
12941f5207b7SJohn Levon #endif
12951f5207b7SJohn Levon 
12961f5207b7SJohn Levon #define X86_LINUX_LAYOUT \
12971f5207b7SJohn Levon 	"e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" \
12981f5207b7SJohn Levon 	"i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-" \
12991f5207b7SJohn Levon 	"a0:0:64-f80:32:32-n8:16:32-S128"
13001f5207b7SJohn Levon 
13011f5207b7SJohn Levon #define X86_64_LINUX_LAYOUT \
13021f5207b7SJohn Levon 	"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" \
13031f5207b7SJohn Levon 	"i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-" \
13041f5207b7SJohn Levon 	"a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
13051f5207b7SJohn Levon 
set_target(LLVMModuleRef module)13061f5207b7SJohn Levon static void set_target(LLVMModuleRef module)
13071f5207b7SJohn Levon {
13081f5207b7SJohn Levon 	char target[] = LLVM_DEFAULT_TARGET_TRIPLE;
13091f5207b7SJohn Levon 	const char *arch, *vendor, *os, *env, *layout = NULL;
13101f5207b7SJohn Levon 	char triple[256];
13111f5207b7SJohn Levon 
13121f5207b7SJohn Levon 	arch = strtok(target, "-");
13131f5207b7SJohn Levon 	vendor = strtok(NULL, "-");
13141f5207b7SJohn Levon 	os = strtok(NULL, "-");
13151f5207b7SJohn Levon 	env = strtok(NULL, "-");
13161f5207b7SJohn Levon 
13171f5207b7SJohn Levon 	if (!os)
13181f5207b7SJohn Levon 		return;
13191f5207b7SJohn Levon 	if (!env)
13201f5207b7SJohn Levon 		env = "unknown";
13211f5207b7SJohn Levon 
13221f5207b7SJohn Levon 	if (!strcmp(arch, "x86_64") && !strcmp(os, "linux")) {
13231f5207b7SJohn Levon 		if (arch_m64) {
13241f5207b7SJohn Levon 			layout = X86_64_LINUX_LAYOUT;
13251f5207b7SJohn Levon 		} else {
13261f5207b7SJohn Levon 			arch = "i386";
13271f5207b7SJohn Levon 			layout = X86_LINUX_LAYOUT;
13281f5207b7SJohn Levon 		}
13291f5207b7SJohn Levon 	}
13301f5207b7SJohn Levon 
13311f5207b7SJohn Levon 	/* unsupported target */
13321f5207b7SJohn Levon 	if (!layout)
13331f5207b7SJohn Levon 		return;
13341f5207b7SJohn Levon 
13351f5207b7SJohn Levon 	snprintf(triple, sizeof(triple), "%s-%s-%s-%s", arch, vendor, os, env);
13361f5207b7SJohn Levon 	LLVMSetTarget(module, triple);
13371f5207b7SJohn Levon 	LLVMSetDataLayout(module, layout);
13381f5207b7SJohn Levon }
13391f5207b7SJohn Levon 
main(int argc,char ** argv)13401f5207b7SJohn Levon int main(int argc, char **argv)
13411f5207b7SJohn Levon {
13421f5207b7SJohn Levon 	struct string_list *filelist = NULL;
13431f5207b7SJohn Levon 	struct symbol_list *symlist;
13441f5207b7SJohn Levon 	LLVMModuleRef module;
13451f5207b7SJohn Levon 	char *file;
13461f5207b7SJohn Levon 
13471f5207b7SJohn Levon 	symlist = sparse_initialize(argc, argv, &filelist);
13481f5207b7SJohn Levon 
13491f5207b7SJohn Levon 	module = LLVMModuleCreateWithName("sparse");
13501f5207b7SJohn Levon 	set_target(module);
13511f5207b7SJohn Levon 
13521f5207b7SJohn Levon 	compile(module, symlist);
13531f5207b7SJohn Levon 
13541f5207b7SJohn Levon 	/* need ->phi_users */
13551f5207b7SJohn Levon 	dbg_dead = 1;
1356*c85f09ccSJohn Levon 	FOR_EACH_PTR(filelist, file) {
13571f5207b7SJohn Levon 		symlist = sparse(file);
13581f5207b7SJohn Levon 		if (die_if_error)
13591f5207b7SJohn Levon 			return 1;
13601f5207b7SJohn Levon 		compile(module, symlist);
1361*c85f09ccSJohn Levon 	} END_FOR_EACH_PTR(file);
13621f5207b7SJohn Levon 
13631f5207b7SJohn Levon 	LLVMVerifyModule(module, LLVMPrintMessageAction, NULL);
13641f5207b7SJohn Levon 
13651f5207b7SJohn Levon 	LLVMWriteBitcodeToFD(module, STDOUT_FILENO, 0, 0);
13661f5207b7SJohn Levon 
13671f5207b7SJohn Levon 	LLVMDisposeModule(module);
13681f5207b7SJohn Levon 
13691f5207b7SJohn Levon 	report_stats();
13701f5207b7SJohn Levon 	return 0;
13711f5207b7SJohn Levon }
1372