Print this page
new smatch
@@ -19,84 +19,57 @@
#include "linearize.h"
#include "flow.h"
struct function {
LLVMBuilderRef builder;
- LLVMTypeRef type;
LLVMValueRef fn;
LLVMModuleRef module;
};
-static inline bool symbol_is_fp_type(struct symbol *sym)
-{
- if (!sym)
- return false;
+static LLVMTypeRef symbol_type(struct symbol *sym);
- return sym->ctype.base_type == &fp_type;
-}
-
-static LLVMTypeRef symbol_type(LLVMModuleRef module, struct symbol *sym);
-
-static LLVMTypeRef func_return_type(LLVMModuleRef module, struct symbol *sym)
+static LLVMTypeRef func_return_type(struct symbol *sym)
{
- return symbol_type(module, sym->ctype.base_type);
+ return symbol_type(sym->ctype.base_type);
}
-static LLVMTypeRef sym_func_type(LLVMModuleRef module, struct symbol *sym)
+static LLVMTypeRef sym_func_type(struct symbol *sym)
{
- LLVMTypeRef *arg_type;
- LLVMTypeRef func_type;
- LLVMTypeRef ret_type;
+ int n_arg = symbol_list_size(sym->arguments);
+ LLVMTypeRef *arg_type = calloc(n_arg, sizeof(LLVMTypeRef));
+ LLVMTypeRef ret_type = func_return_type(sym);
struct symbol *arg;
- int n_arg = 0;
+ int idx = 0;
- /* to avoid strangeness with varargs [for now], we build
- * the function and type anew, for each call. This
- * is probably wrong. We should look up the
- * symbol declaration info.
- */
-
- ret_type = func_return_type(module, sym);
-
- /* count args, build argument type information */
FOR_EACH_PTR(sym->arguments, arg) {
- n_arg++;
- } END_FOR_EACH_PTR(arg);
-
- arg_type = calloc(n_arg, sizeof(LLVMTypeRef));
-
- int idx = 0;
- FOR_EACH_PTR(sym->arguments, arg) {
struct symbol *arg_sym = arg->ctype.base_type;
- arg_type[idx++] = symbol_type(module, arg_sym);
+ arg_type[idx++] = symbol_type(arg_sym);
} END_FOR_EACH_PTR(arg);
- func_type = LLVMFunctionType(ret_type, arg_type, n_arg,
- sym->variadic);
- return func_type;
+ return LLVMFunctionType(ret_type, arg_type, n_arg, sym->variadic);
}
-static LLVMTypeRef sym_array_type(LLVMModuleRef module, struct symbol *sym)
+static LLVMTypeRef sym_array_type(struct symbol *sym)
{
LLVMTypeRef elem_type;
struct symbol *base_type;
base_type = sym->ctype.base_type;
/* empty struct is undefined [6.7.2.1(8)] */
assert(base_type->bit_size > 0);
- elem_type = symbol_type(module, base_type);
+ elem_type = symbol_type(base_type);
if (!elem_type)
return NULL;
return LLVMArrayType(elem_type, sym->bit_size / base_type->bit_size);
}
#define MAX_STRUCT_MEMBERS 64
-static LLVMTypeRef sym_struct_type(LLVMModuleRef module, struct symbol *sym)
+static LLVMTypeRef sym_struct_type(struct symbol *sym)
{
LLVMTypeRef elem_types[MAX_STRUCT_MEMBERS];
struct symbol *member;
char buffer[256];
LLVMTypeRef ret;
@@ -110,20 +83,20 @@
FOR_EACH_PTR(sym->symbol_list, member) {
LLVMTypeRef member_type;
assert(nr < MAX_STRUCT_MEMBERS);
- member_type = symbol_type(module, member);
+ member_type = symbol_type(member);
elem_types[nr++] = member_type;
} END_FOR_EACH_PTR(member);
LLVMStructSetBody(ret, elem_types, nr, 0 /* packed? */);
return ret;
}
-static LLVMTypeRef sym_union_type(LLVMModuleRef module, struct symbol *sym)
+static LLVMTypeRef sym_union_type(struct symbol *sym)
{
LLVMTypeRef elements;
unsigned union_size;
/*
@@ -136,28 +109,28 @@
elements = LLVMArrayType(LLVMInt8Type(), union_size);
return LLVMStructType(&elements, 1, 0 /* packed? */);
}
-static LLVMTypeRef sym_ptr_type(LLVMModuleRef module, struct symbol *sym)
+static LLVMTypeRef sym_ptr_type(struct symbol *sym)
{
LLVMTypeRef type;
/* 'void *' is treated like 'char *' */
if (is_void_type(sym->ctype.base_type))
type = LLVMInt8Type();
else
- type = symbol_type(module, sym->ctype.base_type);
+ type = symbol_type(sym->ctype.base_type);
return LLVMPointerType(type, 0);
}
static LLVMTypeRef sym_basetype_type(struct symbol *sym)
{
LLVMTypeRef ret = NULL;
- if (symbol_is_fp_type(sym)) {
+ if (is_float_type(sym)) {
switch (sym->bit_size) {
case 32:
ret = LLVMFloatType();
break;
case 64:
@@ -197,43 +170,46 @@
}
return ret;
}
-static LLVMTypeRef symbol_type(LLVMModuleRef module, struct symbol *sym)
+static LLVMTypeRef symbol_type(struct symbol *sym)
{
LLVMTypeRef ret = NULL;
/* don't cache the result for SYM_NODE */
if (sym->type == SYM_NODE)
- return symbol_type(module, sym->ctype.base_type);
+ return symbol_type(sym->ctype.base_type);
if (sym->aux)
return sym->aux;
switch (sym->type) {
case SYM_BITFIELD:
+ ret = LLVMIntType(sym->bit_size);
+ break;
+ case SYM_RESTRICT:
case SYM_ENUM:
- ret = symbol_type(module, sym->ctype.base_type);
+ ret = symbol_type(sym->ctype.base_type);
break;
case SYM_BASETYPE:
ret = sym_basetype_type(sym);
break;
case SYM_PTR:
- ret = sym_ptr_type(module, sym);
+ ret = sym_ptr_type(sym);
break;
case SYM_UNION:
- ret = sym_union_type(module, sym);
+ ret = sym_union_type(sym);
break;
case SYM_STRUCT:
- ret = sym_struct_type(module, sym);
+ ret = sym_struct_type(sym);
break;
case SYM_ARRAY:
- ret = sym_array_type(module, sym);
+ ret = sym_array_type(sym);
break;
case SYM_FN:
- ret = sym_func_type(module, sym);
+ ret = sym_func_type(sym);
break;
default:
assert(0);
}
@@ -240,34 +216,29 @@
/* cache the result */
sym->aux = ret;
return ret;
}
-static LLVMTypeRef int_type_by_size(int size)
+static LLVMTypeRef insn_symbol_type(struct instruction *insn)
{
- switch (size) {
- case 1: return LLVMInt1Type();
+ if (insn->type)
+ return symbol_type(insn->type);
+
+ switch (insn->size) {
case 8: return LLVMInt8Type();
case 16: return LLVMInt16Type();
case 32: return LLVMInt32Type();
case 64: return LLVMInt64Type();
default:
- die("invalid bit size %d", size);
+ die("invalid bit size %d", insn->size);
break;
}
+
return NULL; /* not reached */
}
-static LLVMTypeRef insn_symbol_type(LLVMModuleRef module, struct instruction *insn)
-{
- if (insn->type)
- return symbol_type(module, insn->type);
-
- return int_type_by_size(insn->size);
-}
-
static LLVMLinkage data_linkage(struct symbol *sym)
{
if (sym->ctype.modifiers & MOD_STATIC)
return LLVMPrivateLinkage;
@@ -282,92 +253,134 @@
return LLVMExternalLinkage;
}
#define MAX_PSEUDO_NAME 64
-static void pseudo_name(pseudo_t pseudo, char *buf)
+static const char *pseudo_name(pseudo_t pseudo, char *buf)
{
switch (pseudo->type) {
case PSEUDO_REG:
- snprintf(buf, MAX_PSEUDO_NAME, "R%d", pseudo->nr);
+ snprintf(buf, MAX_PSEUDO_NAME, "R%d.", pseudo->nr);
break;
- case PSEUDO_SYM:
- assert(0);
+ case PSEUDO_PHI:
+ snprintf(buf, MAX_PSEUDO_NAME, "PHI%d.", pseudo->nr);
break;
+ case PSEUDO_SYM:
case PSEUDO_VAL:
- assert(0);
+ case PSEUDO_ARG:
+ case PSEUDO_VOID:
+ buf[0] = '\0';
break;
- case PSEUDO_ARG: {
+ case PSEUDO_UNDEF:
assert(0);
break;
- }
- case PSEUDO_PHI:
- snprintf(buf, MAX_PSEUDO_NAME, "PHI%d", pseudo->nr);
- break;
default:
assert(0);
}
+
+ return buf;
}
-static LLVMValueRef pseudo_to_value(struct function *fn, struct instruction *insn, pseudo_t pseudo)
+static LLVMValueRef get_sym_value(LLVMModuleRef module, struct symbol *sym)
{
+ const char *name = show_ident(sym->ident);
+ LLVMTypeRef type = symbol_type(sym);
LLVMValueRef result = NULL;
-
- switch (pseudo->type) {
- case PSEUDO_REG:
- result = pseudo->priv;
- break;
- case PSEUDO_SYM: {
- struct symbol *sym = pseudo->sym;
struct expression *expr;
assert(sym->bb_target == NULL);
expr = sym->initializer;
- if (expr) {
+ if (expr && !sym->ident) {
switch (expr->type) {
case EXPR_STRING: {
const char *s = expr->string->data;
LLVMValueRef indices[] = { LLVMConstInt(LLVMInt64Type(), 0, 0), LLVMConstInt(LLVMInt64Type(), 0, 0) };
LLVMValueRef data;
- data = LLVMAddGlobal(fn->module, LLVMArrayType(LLVMInt8Type(), strlen(s) + 1), ".str");
+ data = LLVMAddGlobal(module, LLVMArrayType(LLVMInt8Type(), strlen(s) + 1), ".str");
LLVMSetLinkage(data, LLVMPrivateLinkage);
LLVMSetGlobalConstant(data, 1);
LLVMSetInitializer(data, LLVMConstString(strdup(s), strlen(s) + 1, true));
result = LLVMConstGEP(data, indices, ARRAY_SIZE(indices));
- break;
+ return result;
}
- case EXPR_SYMBOL: {
- struct symbol *sym = expr->symbol;
-
- result = LLVMGetNamedGlobal(fn->module, show_ident(sym->ident));
- assert(result != NULL);
+ default:
break;
}
- default:
- assert(0);
}
- } else {
- const char *name = show_ident(sym->ident);
- LLVMTypeRef type = symbol_type(fn->module, sym);
if (LLVMGetTypeKind(type) == LLVMFunctionTypeKind) {
- result = LLVMGetNamedFunction(fn->module, name);
+ result = LLVMGetNamedFunction(module, name);
if (!result)
- result = LLVMAddFunction(fn->module, name, type);
+ result = LLVMAddFunction(module, name, type);
} else {
- result = LLVMGetNamedGlobal(fn->module, name);
+ result = LLVMGetNamedGlobal(module, name);
if (!result)
- result = LLVMAddGlobal(fn->module, type, name);
+ result = LLVMAddGlobal(module, type, name);
}
+
+ return result;
+}
+
+static LLVMValueRef constant_value(unsigned long long val, LLVMTypeRef dtype)
+{
+ LLVMValueRef result;
+
+ switch (LLVMGetTypeKind(dtype)) {
+ case LLVMPointerTypeKind:
+ if (val != 0) { // for example: ... = (void*) 0x123;
+ LLVMTypeRef itype = LLVMIntType(bits_in_pointer);
+ result = LLVMConstInt(itype, val, 1);
+ result = LLVMConstIntToPtr(result, dtype);
+ } else {
+ result = LLVMConstPointerNull(dtype);
}
break;
+ case LLVMIntegerTypeKind:
+ result = LLVMConstInt(dtype, val, 1);
+ break;
+ case LLVMArrayTypeKind:
+ case LLVMStructTypeKind:
+ if (val != 0)
+ return NULL;
+ result = LLVMConstNull(dtype);
+ break;
+ default:
+ return NULL;
}
+ return result;
+}
+
+static LLVMValueRef val_to_value(unsigned long long val, struct symbol *ctype)
+{
+ LLVMValueRef result;
+ LLVMTypeRef dtype;
+
+ assert(ctype);
+ dtype = symbol_type(ctype);
+ result = constant_value(val, dtype);
+ if (result)
+ return result;
+ sparse_error(ctype->pos, "no value possible for %s", show_typename(ctype));
+ return LLVMGetUndef(symbol_type(ctype));
+}
+
+static LLVMValueRef pseudo_to_value(struct function *fn, struct symbol *ctype, pseudo_t pseudo)
+{
+ LLVMValueRef result = NULL;
+
+ switch (pseudo->type) {
+ case PSEUDO_REG:
+ result = pseudo->priv;
+ break;
+ case PSEUDO_SYM:
+ result = get_sym_value(fn->module, pseudo->sym);
+ break;
case PSEUDO_VAL:
- result = LLVMConstInt(int_type_by_size(pseudo->size), pseudo->value, 1);
+ result = val_to_value(pseudo->value, ctype);
break;
case PSEUDO_ARG: {
result = LLVMGetParam(fn->fn, pseudo->nr - 1);
break;
}
@@ -375,47 +388,128 @@
result = pseudo->priv;
break;
case PSEUDO_VOID:
result = NULL;
break;
+ case PSEUDO_UNDEF:
+ result = LLVMGetUndef(symbol_type(ctype));
+ break;
default:
assert(0);
}
return result;
}
+static LLVMValueRef pseudo_to_rvalue(struct function *fn, struct symbol *ctype, pseudo_t pseudo)
+{
+ LLVMValueRef val = pseudo_to_value(fn, ctype, pseudo);
+ LLVMTypeRef dtype = symbol_type(ctype);
+ char name[MAX_PSEUDO_NAME];
+
+ pseudo_name(pseudo, name);
+ return LLVMBuildBitCast(fn->builder, val, dtype, name);
+}
+
+static LLVMValueRef value_to_ivalue(struct function *fn, struct symbol *ctype, LLVMValueRef val)
+{
+ const char *name = LLVMGetValueName(val);
+ LLVMTypeRef dtype = symbol_type(ctype);
+
+ if (LLVMGetTypeKind(LLVMTypeOf(val)) == LLVMPointerTypeKind) {
+ LLVMTypeRef dtype = LLVMIntType(bits_in_pointer);
+ val = LLVMBuildPtrToInt(fn->builder, val, dtype, name);
+ }
+ if (ctype && is_int_type(ctype)) {
+ val = LLVMBuildIntCast(fn->builder, val, dtype, name);
+ }
+ return val;
+}
+
+static LLVMValueRef value_to_pvalue(struct function *fn, struct symbol *ctype, LLVMValueRef val)
+{
+ const char *name = LLVMGetValueName(val);
+ LLVMTypeRef dtype = symbol_type(ctype);
+
+ assert(is_ptr_type(ctype));
+ switch (LLVMGetTypeKind(LLVMTypeOf(val))) {
+ case LLVMIntegerTypeKind:
+ val = LLVMBuildIntToPtr(fn->builder, val, dtype, name);
+ break;
+ case LLVMPointerTypeKind:
+ val = LLVMBuildBitCast(fn->builder, val, dtype, name);
+ break;
+ default:
+ break;
+ }
+ return val;
+}
+
+static LLVMValueRef adjust_type(struct function *fn, struct symbol *ctype, LLVMValueRef val)
+{
+ if (is_int_type(ctype))
+ return value_to_ivalue(fn, ctype, val);
+ if (is_ptr_type(ctype))
+ return value_to_pvalue(fn, ctype, val);
+ return val;
+}
+
+/*
+ * Get the LLVMValue corresponding to the pseudo
+ * and force the type corresponding to ctype.
+ */
+static LLVMValueRef get_operand(struct function *fn, struct symbol *ctype, pseudo_t pseudo)
+{
+ LLVMValueRef target = pseudo_to_value(fn, ctype, pseudo);
+ return adjust_type(fn, ctype, target);
+}
+
+/*
+ * Get the LLVMValue corresponding to the pseudo
+ * and force the type corresponding to ctype but
+ * map all pointers to intptr_t.
+ */
+static LLVMValueRef get_ioperand(struct function *fn, struct symbol *ctype, pseudo_t pseudo)
+{
+ LLVMValueRef target = pseudo_to_value(fn, ctype, pseudo);
+ return value_to_ivalue(fn, ctype, target);
+}
+
static LLVMValueRef calc_gep(LLVMBuilderRef builder, LLVMValueRef base, LLVMValueRef off)
{
LLVMTypeRef type = LLVMTypeOf(base);
unsigned int as = LLVMGetPointerAddressSpace(type);
LLVMTypeRef bytep = LLVMPointerType(LLVMInt8Type(), as);
LLVMValueRef addr;
+ const char *name = LLVMGetValueName(off);
/* convert base to char* type */
- base = LLVMBuildPointerCast(builder, base, bytep, "");
+ base = LLVMBuildPointerCast(builder, base, bytep, name);
/* addr = base + off */
- addr = LLVMBuildInBoundsGEP(builder, base, &off, 1, "");
+ addr = LLVMBuildInBoundsGEP(builder, base, &off, 1, name);
/* convert back to the actual pointer type */
- addr = LLVMBuildPointerCast(builder, addr, type, "");
+ addr = LLVMBuildPointerCast(builder, addr, type, name);
return addr;
}
static LLVMRealPredicate translate_fop(int opcode)
{
static const LLVMRealPredicate trans_tbl[] = {
- [OP_SET_EQ] = LLVMRealOEQ,
- [OP_SET_NE] = LLVMRealUNE,
- [OP_SET_LE] = LLVMRealOLE,
- [OP_SET_GE] = LLVMRealOGE,
- [OP_SET_LT] = LLVMRealOLT,
- [OP_SET_GT] = LLVMRealOGT,
- /* Are these used with FP? */
- [OP_SET_B] = LLVMRealOLT,
- [OP_SET_A] = LLVMRealOGT,
- [OP_SET_BE] = LLVMRealOLE,
- [OP_SET_AE] = LLVMRealOGE,
+ [OP_FCMP_ORD] = LLVMRealORD,
+ [OP_FCMP_OEQ] = LLVMRealOEQ,
+ [OP_FCMP_ONE] = LLVMRealONE,
+ [OP_FCMP_OLE] = LLVMRealOLE,
+ [OP_FCMP_OGE] = LLVMRealOGE,
+ [OP_FCMP_OLT] = LLVMRealOLT,
+ [OP_FCMP_OGT] = LLVMRealOGT,
+ [OP_FCMP_UEQ] = LLVMRealUEQ,
+ [OP_FCMP_UNE] = LLVMRealUNE,
+ [OP_FCMP_ULE] = LLVMRealULE,
+ [OP_FCMP_UGE] = LLVMRealUGE,
+ [OP_FCMP_ULT] = LLVMRealULT,
+ [OP_FCMP_UGT] = LLVMRealUGT,
+ [OP_FCMP_UNO] = LLVMRealUNO,
};
return trans_tbl[opcode];
}
@@ -440,141 +534,137 @@
static void output_op_binary(struct function *fn, struct instruction *insn)
{
LLVMValueRef lhs, rhs, target;
char target_name[64];
- lhs = pseudo_to_value(fn, insn, insn->src1);
+ lhs = get_ioperand(fn, insn->type, insn->src1);
+ rhs = get_ioperand(fn, insn->type, insn->src2);
- rhs = pseudo_to_value(fn, insn, insn->src2);
-
pseudo_name(insn->target, target_name);
switch (insn->opcode) {
/* Binary */
case OP_ADD:
- if (symbol_is_fp_type(insn->type))
- target = LLVMBuildFAdd(fn->builder, lhs, rhs, target_name);
- else
target = LLVMBuildAdd(fn->builder, lhs, rhs, target_name);
break;
case OP_SUB:
- if (symbol_is_fp_type(insn->type))
- target = LLVMBuildFSub(fn->builder, lhs, rhs, target_name);
- else
target = LLVMBuildSub(fn->builder, lhs, rhs, target_name);
break;
- case OP_MULU:
- if (symbol_is_fp_type(insn->type))
- target = LLVMBuildFMul(fn->builder, lhs, rhs, target_name);
- else
+ case OP_MUL:
target = LLVMBuildMul(fn->builder, lhs, rhs, target_name);
break;
- case OP_MULS:
- assert(!symbol_is_fp_type(insn->type));
- target = LLVMBuildMul(fn->builder, lhs, rhs, target_name);
- break;
case OP_DIVU:
- if (symbol_is_fp_type(insn->type))
- target = LLVMBuildFDiv(fn->builder, lhs, rhs, target_name);
- else
target = LLVMBuildUDiv(fn->builder, lhs, rhs, target_name);
break;
case OP_DIVS:
- assert(!symbol_is_fp_type(insn->type));
+ assert(!is_float_type(insn->type));
target = LLVMBuildSDiv(fn->builder, lhs, rhs, target_name);
break;
case OP_MODU:
- assert(!symbol_is_fp_type(insn->type));
+ assert(!is_float_type(insn->type));
target = LLVMBuildURem(fn->builder, lhs, rhs, target_name);
break;
case OP_MODS:
- assert(!symbol_is_fp_type(insn->type));
+ assert(!is_float_type(insn->type));
target = LLVMBuildSRem(fn->builder, lhs, rhs, target_name);
break;
case OP_SHL:
- assert(!symbol_is_fp_type(insn->type));
+ assert(!is_float_type(insn->type));
target = LLVMBuildShl(fn->builder, lhs, rhs, target_name);
break;
case OP_LSR:
- assert(!symbol_is_fp_type(insn->type));
+ assert(!is_float_type(insn->type));
target = LLVMBuildLShr(fn->builder, lhs, rhs, target_name);
break;
case OP_ASR:
- assert(!symbol_is_fp_type(insn->type));
+ assert(!is_float_type(insn->type));
target = LLVMBuildAShr(fn->builder, lhs, rhs, target_name);
break;
+ /* floating-point */
+ case OP_FADD:
+ target = LLVMBuildFAdd(fn->builder, lhs, rhs, target_name);
+ break;
+ case OP_FSUB:
+ target = LLVMBuildFSub(fn->builder, lhs, rhs, target_name);
+ break;
+ case OP_FMUL:
+ target = LLVMBuildFMul(fn->builder, lhs, rhs, target_name);
+ break;
+ case OP_FDIV:
+ target = LLVMBuildFDiv(fn->builder, lhs, rhs, target_name);
+ break;
+
/* Logical */
case OP_AND:
- assert(!symbol_is_fp_type(insn->type));
+ assert(!is_float_type(insn->type));
target = LLVMBuildAnd(fn->builder, lhs, rhs, target_name);
break;
case OP_OR:
- assert(!symbol_is_fp_type(insn->type));
+ assert(!is_float_type(insn->type));
target = LLVMBuildOr(fn->builder, lhs, rhs, target_name);
break;
case OP_XOR:
- assert(!symbol_is_fp_type(insn->type));
+ assert(!is_float_type(insn->type));
target = LLVMBuildXor(fn->builder, lhs, rhs, target_name);
break;
- case OP_AND_BOOL: {
- LLVMValueRef lhs_nz, rhs_nz;
- LLVMTypeRef dst_type;
-
- lhs_nz = LLVMBuildIsNotNull(fn->builder, lhs, "");
- rhs_nz = LLVMBuildIsNotNull(fn->builder, rhs, "");
- target = LLVMBuildAnd(fn->builder, lhs_nz, rhs_nz, target_name);
-
- dst_type = insn_symbol_type(fn->module, insn);
- target = LLVMBuildZExt(fn->builder, target, dst_type, target_name);
- break;
- }
- case OP_OR_BOOL: {
- LLVMValueRef lhs_nz, rhs_nz;
- LLVMTypeRef dst_type;
-
- lhs_nz = LLVMBuildIsNotNull(fn->builder, lhs, "");
- rhs_nz = LLVMBuildIsNotNull(fn->builder, rhs, "");
- target = LLVMBuildOr(fn->builder, lhs_nz, rhs_nz, target_name);
-
- dst_type = insn_symbol_type(fn->module, insn);
- target = LLVMBuildZExt(fn->builder, target, dst_type, target_name);
- break;
- }
default:
assert(0);
break;
}
+ target = adjust_type(fn, insn->type, target);
insn->target->priv = target;
}
static void output_op_compare(struct function *fn, struct instruction *insn)
{
LLVMValueRef lhs, rhs, target;
char target_name[64];
- lhs = pseudo_to_value(fn, insn, insn->src1);
-
+ lhs = pseudo_to_value(fn, NULL, insn->src1);
if (insn->src2->type == PSEUDO_VAL)
- rhs = LLVMConstInt(LLVMTypeOf(lhs), insn->src2->value, 1);
+ rhs = constant_value(insn->src2->value, LLVMTypeOf(lhs));
else
- rhs = pseudo_to_value(fn, insn, insn->src2);
+ rhs = pseudo_to_value(fn, NULL, insn->src2);
+ if (!rhs)
+ rhs = LLVMGetUndef(symbol_type(insn->type));
pseudo_name(insn->target, target_name);
- LLVMTypeRef dst_type = insn_symbol_type(fn->module, insn);
+ LLVMTypeRef dst_type = insn_symbol_type(insn);
- if (LLVMGetTypeKind(LLVMTypeOf(lhs)) == LLVMIntegerTypeKind) {
+ switch (LLVMGetTypeKind(LLVMTypeOf(lhs))) {
+ case LLVMPointerTypeKind:
+ lhs = value_to_pvalue(fn, &ptr_ctype, lhs);
+ rhs = value_to_pvalue(fn, &ptr_ctype, rhs);
+ /* fall through */
+
+ case LLVMIntegerTypeKind: {
LLVMIntPredicate op = translate_op(insn->opcode);
+ if (LLVMGetTypeKind(LLVMTypeOf(rhs)) == LLVMPointerTypeKind) {
+ LLVMTypeRef ltype = LLVMTypeOf(lhs);
+ rhs = LLVMBuildPtrToInt(fn->builder, rhs, ltype, "");
+ }
target = LLVMBuildICmp(fn->builder, op, lhs, rhs, target_name);
- } else {
+ break;
+ }
+ case LLVMHalfTypeKind:
+ case LLVMFloatTypeKind:
+ case LLVMDoubleTypeKind:
+ case LLVMX86_FP80TypeKind:
+ case LLVMFP128TypeKind:
+ case LLVMPPC_FP128TypeKind: {
LLVMRealPredicate op = translate_fop(insn->opcode);
target = LLVMBuildFCmp(fn->builder, op, lhs, rhs, target_name);
+ break;
}
+ default:
+ assert(0);
+ }
target = LLVMBuildZExt(fn->builder, target, dst_type, target_name);
insn->target->priv = target;
}
@@ -582,12 +672,11 @@
static void output_op_ret(struct function *fn, struct instruction *insn)
{
pseudo_t pseudo = insn->src;
if (pseudo && pseudo != VOID) {
- LLVMValueRef result = pseudo_to_value(fn, insn, pseudo);
-
+ LLVMValueRef result = get_operand(fn, insn->type, pseudo);
LLVMBuildRet(fn->builder, result);
} else
LLVMBuildRetVoid(fn->builder);
}
@@ -600,14 +689,14 @@
/* int type large enough to hold a pointer */
int_type = LLVMIntType(bits_in_pointer);
off = LLVMConstInt(int_type, insn->offset, 0);
/* convert src to the effective pointer type */
- src = pseudo_to_value(fn, insn, insn->src);
+ src = pseudo_to_value(fn, insn->type, insn->src);
as = LLVMGetPointerAddressSpace(LLVMTypeOf(src));
- addr_type = LLVMPointerType(insn_symbol_type(fn->module, insn), as);
- src = LLVMBuildPointerCast(fn->builder, src, addr_type, "");
+ addr_type = LLVMPointerType(insn_symbol_type(insn), as);
+ src = LLVMBuildPointerCast(fn->builder, src, addr_type, LLVMGetValueName(src));
/* addr = src + off */
addr = calc_gep(fn->builder, src, off);
return addr;
}
@@ -614,45 +703,45 @@
static void output_op_load(struct function *fn, struct instruction *insn)
{
LLVMValueRef addr, target;
+ char name[MAX_PSEUDO_NAME];
addr = calc_memop_addr(fn, insn);
/* perform load */
- target = LLVMBuildLoad(fn->builder, addr, "load_target");
+ pseudo_name(insn->target, name);
+ target = LLVMBuildLoad(fn->builder, addr, name);
insn->target->priv = target;
}
static void output_op_store(struct function *fn, struct instruction *insn)
{
- LLVMValueRef addr, target, target_in;
+ LLVMValueRef addr, target_in;
addr = calc_memop_addr(fn, insn);
- target_in = pseudo_to_value(fn, insn, insn->target);
+ target_in = pseudo_to_rvalue(fn, insn->type, insn->target);
/* perform store */
- target = LLVMBuildStore(fn->builder, target_in, addr);
-
- insn->target->priv = target;
+ LLVMBuildStore(fn->builder, target_in, addr);
}
static LLVMValueRef bool_value(struct function *fn, LLVMValueRef value)
{
if (LLVMTypeOf(value) != LLVMInt1Type())
- value = LLVMBuildIsNotNull(fn->builder, value, "cond");
+ value = LLVMBuildIsNotNull(fn->builder, value, LLVMGetValueName(value));
return value;
}
static void output_op_cbr(struct function *fn, struct instruction *br)
{
LLVMValueRef cond = bool_value(fn,
- pseudo_to_value(fn, br, br->cond));
+ pseudo_to_value(fn, NULL, br->cond));
LLVMBuildCondBr(fn->builder, cond,
br->bb_true->priv,
br->bb_false->priv);
}
@@ -663,18 +752,20 @@
}
static void output_op_sel(struct function *fn, struct instruction *insn)
{
LLVMValueRef target, src1, src2, src3;
+ char name[MAX_PSEUDO_NAME];
- src1 = bool_value(fn, pseudo_to_value(fn, insn, insn->src1));
- src2 = pseudo_to_value(fn, insn, insn->src2);
- src3 = pseudo_to_value(fn, insn, insn->src3);
+ src1 = bool_value(fn, pseudo_to_value(fn, NULL, insn->src1));
+ src2 = get_operand(fn, insn->type, insn->src2);
+ src3 = get_operand(fn, insn->type, insn->src3);
- target = LLVMBuildSelect(fn->builder, src1, src2, src3, "select");
+ pseudo_name(insn->target, name);
+ target = LLVMBuildSelect(fn->builder, src1, src2, src3, name);
- insn->target->priv = target;
+ insn->target->priv = adjust_type(fn, insn->type, target);
}
static void output_op_switch(struct function *fn, struct instruction *insn)
{
LLVMValueRef sw_val, target;
@@ -681,55 +772,56 @@
struct basic_block *def = NULL;
struct multijmp *jmp;
int n_jmp = 0;
FOR_EACH_PTR(insn->multijmp_list, jmp) {
- if (jmp->begin == jmp->end) { /* case N */
- n_jmp++;
- } else if (jmp->begin < jmp->end) { /* case M..N */
- assert(0);
+ if (jmp->begin <= jmp->end) {
+ n_jmp += (jmp->end - jmp->begin) + 1;
} else /* default case */
def = jmp->target;
} END_FOR_EACH_PTR(jmp);
- sw_val = pseudo_to_value(fn, insn, insn->target);
+ sw_val = get_ioperand(fn, insn->type, insn->cond);
target = LLVMBuildSwitch(fn->builder, sw_val,
def ? def->priv : NULL, n_jmp);
FOR_EACH_PTR(insn->multijmp_list, jmp) {
- if (jmp->begin == jmp->end) { /* case N */
- LLVMAddCase(target,
- LLVMConstInt(LLVMInt32Type(), jmp->begin, 0),
- jmp->target->priv);
- } else if (jmp->begin < jmp->end) { /* case M..N */
- assert(0);
+ long long val;
+
+ for (val = jmp->begin; val <= jmp->end; val++) {
+ LLVMValueRef Val = val_to_value(val, insn->type);
+ LLVMAddCase(target, Val, jmp->target->priv);
}
} END_FOR_EACH_PTR(jmp);
-
- insn->target->priv = target;
}
static void output_op_call(struct function *fn, struct instruction *insn)
{
LLVMValueRef target, func;
+ struct symbol *ctype;
int n_arg = 0, i;
struct pseudo *arg;
LLVMValueRef *args;
+ char name[64];
- FOR_EACH_PTR(insn->arguments, arg) {
- n_arg++;
- } END_FOR_EACH_PTR(arg);
-
+ n_arg = pseudo_list_size(insn->arguments);
args = calloc(n_arg, sizeof(LLVMValueRef));
+ PREPARE_PTR_LIST(insn->fntypes, ctype);
+ if (insn->func->type == PSEUDO_REG || insn->func->type == PSEUDO_PHI)
+ func = get_operand(fn, ctype, insn->func);
+ else
+ func = pseudo_to_value(fn, ctype, insn->func);
i = 0;
FOR_EACH_PTR(insn->arguments, arg) {
- args[i++] = pseudo_to_value(fn, insn, arg);
+ NEXT_PTR_LIST(ctype);
+ args[i++] = pseudo_to_rvalue(fn, ctype, arg);
} END_FOR_EACH_PTR(arg);
+ FINISH_PTR_LIST(ctype);
- func = pseudo_to_value(fn, insn, insn->func);
- target = LLVMBuildCall(fn->builder, func, args, n_arg, "");
+ pseudo_name(insn->target, name);
+ target = LLVMBuildCall(fn->builder, func, args, n_arg, name);
insn->target->priv = target;
}
static void output_op_phisrc(struct function *fn, struct instruction *insn)
@@ -738,11 +830,11 @@
struct instruction *phi;
assert(insn->target->priv == NULL);
/* target = src */
- v = pseudo_to_value(fn, insn, insn->phi_src);
+ v = get_operand(fn, insn->type, insn->phi_src);
FOR_EACH_PTR(insn->phi_users, phi) {
LLVMValueRef load, ptr;
assert(phi->opcode == OP_PHI);
@@ -768,46 +860,131 @@
}
static void output_op_ptrcast(struct function *fn, struct instruction *insn)
{
LLVMValueRef src, target;
+ LLVMTypeRef dtype;
+ struct symbol *otype = insn->orig_type;
+ LLVMOpcode op;
char target_name[64];
- src = insn->src->priv;
- if (!src)
- src = pseudo_to_value(fn, insn, insn->src);
-
+ src = get_operand(fn, otype, insn->src);
pseudo_name(insn->target, target_name);
- assert(!symbol_is_fp_type(insn->type));
+ dtype = symbol_type(insn->type);
+ switch (insn->opcode) {
+ case OP_UTPTR:
+ case OP_SEXT: // FIXME
+ assert(is_int_type(otype));
+ assert(is_ptr_type(insn->type));
+ op = LLVMIntToPtr;
+ break;
+ case OP_PTRTU:
+ assert(is_ptr_type(otype));
+ assert(is_int_type(insn->type));
+ op = LLVMPtrToInt;
+ break;
+ case OP_PTRCAST:
+ case OP_ZEXT: // FIXME
+ assert(is_ptr_type(otype));
+ assert(is_ptr_type(insn->type));
+ op = LLVMBitCast;
+ break;
+ default:
+ assert(0);
+ }
- target = LLVMBuildBitCast(fn->builder, src, insn_symbol_type(fn->module, insn), target_name);
-
+ target = LLVMBuildCast(fn->builder, op, src, dtype, target_name);
insn->target->priv = target;
}
static void output_op_cast(struct function *fn, struct instruction *insn, LLVMOpcode op)
{
LLVMValueRef src, target;
+ LLVMTypeRef dtype;
+ struct symbol *otype = insn->orig_type;
char target_name[64];
- src = insn->src->priv;
- if (!src)
- src = pseudo_to_value(fn, insn, insn->src);
+ if (is_ptr_type(insn->type)) // cast to void* is OP_CAST ...
+ return output_op_ptrcast(fn, insn);
+ assert(is_int_type(insn->type));
+
+ src = get_operand(fn, otype, insn->src);
pseudo_name(insn->target, target_name);
- assert(!symbol_is_fp_type(insn->type));
+ dtype = symbol_type(insn->type);
+ if (is_ptr_type(otype)) {
+ op = LLVMPtrToInt;
+ } else if (is_float_type(otype)) {
+ assert(op == LLVMFPToUI || op == LLVMFPToSI);
+ } else if (is_int_type(otype)) {
+ unsigned int width = otype->bit_size;
+ if (insn->size < width)
+ op = LLVMTrunc;
+ else if (insn->size == width)
+ op = LLVMBitCast;
+ } else {
+ assert(0);
+ }
- if (insn->size < LLVMGetIntTypeWidth(LLVMTypeOf(src)))
- target = LLVMBuildTrunc(fn->builder, src, insn_symbol_type(fn->module, insn), target_name);
- else
- target = LLVMBuildCast(fn->builder, op, src, insn_symbol_type(fn->module, insn), target_name);
+ target = LLVMBuildCast(fn->builder, op, src, dtype, target_name);
+ insn->target->priv = target;
+}
+static void output_op_fpcast(struct function *fn, struct instruction *insn)
+{
+ LLVMTypeRef dtype = symbol_type(insn->type);
+ LLVMValueRef src, target;
+ struct symbol *otype = insn->orig_type;
+ char name[64];
+
+ assert(is_float_type(insn->type));
+
+ pseudo_name(insn->target, name);
+ src = get_operand(fn, otype, insn->src);
+ switch (insn->opcode) {
+ case OP_FCVTF:
+ target = LLVMBuildFPCast(fn->builder, src, dtype, name);
+ break;
+ case OP_SCVTF:
+ target = LLVMBuildSIToFP(fn->builder, src, dtype, name);
+ break;
+ case OP_UCVTF:
+ target = LLVMBuildUIToFP(fn->builder, src, dtype, name);
+ break;
+ default:
+ assert(0);
+ }
insn->target->priv = target;
}
+static void output_op_setval(struct function *fn, struct instruction *insn)
+{
+ struct expression *val = insn->val;
+ LLVMValueRef target;
+
+ switch (val->type) {
+ case EXPR_LABEL:
+ target = LLVMBlockAddress(fn->fn, val->symbol->bb_target->priv);
+ break;
+ default:
+ assert(0);
+ }
+
+ insn->target->priv = target;
+}
+
+static void output_op_setfval(struct function *fn, struct instruction *insn)
+{
+ LLVMTypeRef dtype = symbol_type(insn->type);
+ LLVMValueRef target;
+
+ target = LLVMConstReal(dtype, insn->fvalue);
+ insn->target->priv = target;
+}
+
static void output_insn(struct function *fn, struct instruction *insn)
{
switch (insn->opcode) {
case OP_RET:
output_op_ret(fn, insn);
@@ -820,12 +997,15 @@
break;
case OP_SYMADDR:
assert(0);
break;
case OP_SETVAL:
- assert(0);
+ output_op_setval(fn, insn);
break;
+ case OP_SETFVAL:
+ output_op_setfval(fn, insn);
+ break;
case OP_SWITCH:
output_op_switch(fn, insn);
break;
case OP_COMPUTEDGOTO:
assert(0);
@@ -837,41 +1017,46 @@
output_op_phi(fn, insn);
break;
case OP_LOAD:
output_op_load(fn, insn);
break;
- case OP_LNOP:
- assert(0);
- break;
case OP_STORE:
output_op_store(fn, insn);
break;
- case OP_SNOP:
- assert(0);
- break;
case OP_INLINED_CALL:
- assert(0);
break;
case OP_CALL:
output_op_call(fn, insn);
break;
- case OP_CAST:
+ case OP_ZEXT:
output_op_cast(fn, insn, LLVMZExt);
break;
- case OP_SCAST:
+ case OP_SEXT:
output_op_cast(fn, insn, LLVMSExt);
break;
- case OP_FPCAST:
- assert(0);
+ case OP_TRUNC:
+ output_op_cast(fn, insn, LLVMTrunc);
break;
+ case OP_FCVTU:
+ output_op_cast(fn, insn, LLVMFPToUI);
+ break;
+ case OP_FCVTS:
+ output_op_cast(fn, insn, LLVMFPToSI);
+ break;
+ case OP_UCVTF: case OP_SCVTF:
+ case OP_FCVTF:
+ output_op_fpcast(fn, insn);
+ break;
+ case OP_UTPTR:
+ case OP_PTRTU:
case OP_PTRCAST:
output_op_ptrcast(fn, insn);
break;
case OP_BINARY ... OP_BINARY_END:
output_op_binary(fn, insn);
break;
- case OP_BINCMP ... OP_BINCMP_END:
+ case OP_FPCMP ... OP_BINCMP_END:
output_op_compare(fn, insn);
break;
case OP_SEL:
output_op_sel(fn, insn);
break;
@@ -880,22 +1065,36 @@
break;
case OP_NOT: {
LLVMValueRef src, target;
char target_name[64];
- src = pseudo_to_value(fn, insn, insn->src);
+ src = pseudo_to_value(fn, insn->type, insn->src);
pseudo_name(insn->target, target_name);
target = LLVMBuildNot(fn->builder, src, target_name);
insn->target->priv = target;
break;
}
- case OP_NEG:
- assert(0);
+ case OP_FNEG:
+ case OP_NEG: {
+ LLVMValueRef src, target;
+ char target_name[64];
+
+ src = pseudo_to_value(fn, insn->type, insn->src);
+
+ pseudo_name(insn->target, target_name);
+
+ if (insn->opcode == OP_FNEG)
+ target = LLVMBuildFNeg(fn->builder, src, target_name);
+ else
+ target = LLVMBuildNeg(fn->builder, src, target_name);
+
+ insn->target->priv = target;
break;
+ }
case OP_CONTEXT:
assert(0);
break;
case OP_RANGE:
assert(0);
@@ -914,16 +1113,14 @@
default:
break;
}
}
-static void output_bb(struct function *fn, struct basic_block *bb, unsigned long generation)
+static void output_bb(struct function *fn, struct basic_block *bb)
{
struct instruction *insn;
- bb->generation = generation;
-
FOR_EACH_PTR(bb->insns, insn) {
if (!insn->bb)
continue;
output_insn(fn, insn);
@@ -933,47 +1130,37 @@
#define MAX_ARGS 64
static void output_fn(LLVMModuleRef module, struct entrypoint *ep)
{
- unsigned long generation = ++bb_generation;
struct symbol *sym = ep->name;
struct symbol *base_type = sym->ctype.base_type;
- struct symbol *ret_type = sym->ctype.base_type->ctype.base_type;
- LLVMTypeRef arg_types[MAX_ARGS];
- LLVMTypeRef return_type;
struct function function = { .module = module };
struct basic_block *bb;
- struct symbol *arg;
- const char *name;
int nr_args = 0;
+ int i;
- FOR_EACH_PTR(base_type->arguments, arg) {
- struct symbol *arg_base_type = arg->ctype.base_type;
-
- arg_types[nr_args++] = symbol_type(module, arg_base_type);
- } END_FOR_EACH_PTR(arg);
-
- name = show_ident(sym->ident);
-
- return_type = symbol_type(module, ret_type);
-
- function.type = LLVMFunctionType(return_type, arg_types, nr_args, 0);
-
- function.fn = LLVMAddFunction(module, name, function.type);
+ function.fn = get_sym_value(module, sym);
LLVMSetFunctionCallConv(function.fn, LLVMCCallConv);
-
LLVMSetLinkage(function.fn, function_linkage(sym));
function.builder = LLVMCreateBuilder();
- static int nr_bb;
+ /* give a name to each argument */
+ nr_args = symbol_list_size(base_type->arguments);
+ for (i = 0; i < nr_args; i++) {
+ char name[MAX_PSEUDO_NAME];
+ LLVMValueRef arg;
- FOR_EACH_PTR(ep->bbs, bb) {
- if (bb->generation == generation)
- continue;
+ arg = LLVMGetParam(function.fn, i);
+ snprintf(name, sizeof(name), "ARG%d.", i+1);
+ LLVMSetValueName(arg, name);
+ }
+ /* create the BBs */
+ FOR_EACH_PTR(ep->bbs, bb) {
+ static int nr_bb;
LLVMBasicBlockRef bbr;
char bbname[32];
struct instruction *insn;
sprintf(bbname, "L%d", nr_bb++);
@@ -990,26 +1177,23 @@
if (!insn->bb || insn->opcode != OP_PHI)
continue;
/* insert alloca into entry block */
entrybbr = LLVMGetEntryBasicBlock(function.fn);
LLVMPositionBuilderAtEnd(function.builder, entrybbr);
- phi_type = insn_symbol_type(module, insn);
+ phi_type = insn_symbol_type(insn);
ptr = LLVMBuildAlloca(function.builder, phi_type, "");
/* emit forward load for phi */
LLVMClearInsertionPosition(function.builder);
insn->target->priv = LLVMBuildLoad(function.builder, ptr, "phi");
} END_FOR_EACH_PTR(insn);
}
END_FOR_EACH_PTR(bb);
FOR_EACH_PTR(ep->bbs, bb) {
- if (bb->generation == generation)
- continue;
-
LLVMPositionBuilderAtEnd(function.builder, bb->priv);
- output_bb(&function, bb, generation);
+ output_bb(&function, bb);
}
END_FOR_EACH_PTR(bb);
}
static LLVMValueRef output_data(LLVMModuleRef module, struct symbol *sym)
@@ -1020,12 +1204,15 @@
const char *name;
if (initializer) {
switch (initializer->type) {
case EXPR_VALUE:
- initial_value = LLVMConstInt(symbol_type(module, sym), initializer->value, 1);
+ initial_value = LLVMConstInt(symbol_type(sym), initializer->value, 1);
break;
+ case EXPR_FVALUE:
+ initial_value = LLVMConstReal(symbol_type(sym), initializer->fvalue);
+ break;
case EXPR_SYMBOL: {
struct symbol *sym = initializer->symbol;
initial_value = LLVMGetNamedGlobal(module, show_ident(sym->ident));
if (!initial_value)
@@ -1037,20 +1224,25 @@
initial_value = LLVMConstString(strdup(s), strlen(s) + 1, true);
break;
}
default:
- assert(0);
+ warning(initializer->pos, "can't initialize type: %s", show_typename(sym));
+ initial_value = NULL;
+ break;
}
} else {
- LLVMTypeRef type = symbol_type(module, sym);
+ LLVMTypeRef type = symbol_type(sym);
initial_value = LLVMConstNull(type);
}
- name = show_ident(sym->ident);
+ if (!initial_value)
+ return NULL;
+ name = sym->ident ? show_ident(sym->ident) : "" ;
+
data = LLVMAddGlobal(module, LLVMTypeOf(initial_value), name);
LLVMSetLinkage(data, data_linkage(sym));
if (sym->ctype.modifiers & MOD_CONST)
LLVMSetGlobalConstant(data, 1);
@@ -1078,12 +1270,15 @@
FOR_EACH_PTR(list, sym) {
struct entrypoint *ep;
expand_symbol(sym);
- if (is_prototype(sym))
+ if (is_prototype(sym)) {
+ // this will do the LLVMAddFunction() we want
+ get_sym_value(module, sym);
continue;
+ }
ep = linearize_symbol(sym);
if (ep)
output_fn(module, ep);
else
@@ -1156,16 +1351,16 @@
compile(module, symlist);
/* need ->phi_users */
dbg_dead = 1;
- FOR_EACH_PTR_NOTAG(filelist, file) {
+ FOR_EACH_PTR(filelist, file) {
symlist = sparse(file);
if (die_if_error)
return 1;
compile(module, symlist);
- } END_FOR_EACH_PTR_NOTAG(file);
+ } END_FOR_EACH_PTR(file);
LLVMVerifyModule(module, LLVMPrintMessageAction, NULL);
LLVMWriteBitcodeToFD(module, STDOUT_FILENO, 0, 0);