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);