diff options
author | Christopher Li <sparse@chrisli.org> | 2013-07-25 09:37:11 -0700 |
---|---|---|
committer | Christopher Li <sparse@chrisli.org> | 2013-07-25 09:37:11 -0700 |
commit | 1c1a74106ea78f624105be6a9bb5d24268f38d91 (patch) | |
tree | 2e08c3f33ad0817aa42dedd0946c0bc21335ff6a | |
parent | 5aa922d3919897481c8e65d9603ffc55e551fc19 (diff) | |
parent | c0296d71405a97349d82e9909cad82a2af3271c2 (diff) | |
download | sparse-1c1a74106ea78f624105be6a9bb5d24268f38d91.tar.gz |
Merge branch 'llvmcore'
Please consider pulling the latest Sparse/LLVM tree:
git@github.com:penberg/sparse-llvm.git llvm/core
It has various LLVM backend fixes from Jonathan and Xi.
-rw-r--r-- | evaluate.c | 17 | ||||
-rw-r--r-- | lib.h | 2 | ||||
-rw-r--r-- | linearize.c | 4 | ||||
-rw-r--r-- | sparse-llvm.c | 488 | ||||
-rwxr-xr-x | sparsei | 13 | ||||
-rw-r--r-- | validation/backend/loop2.c | 14 | ||||
-rw-r--r-- | validation/backend/store-type.c | 12 | ||||
-rw-r--r-- | validation/backend/struct-access.c | 28 | ||||
-rw-r--r-- | validation/backend/struct.c | 6 | ||||
-rw-r--r-- | validation/backend/sum.c | 28 | ||||
-rw-r--r-- | validation/cond_expr3.c | 17 |
11 files changed, 320 insertions, 309 deletions
@@ -860,12 +860,13 @@ static struct symbol *evaluate_logical(struct expression *expr) if (!evaluate_conditional(expr->right, 0)) return NULL; - expr->ctype = &bool_ctype; + /* the result is int [6.5.13(3), 6.5.14(3)] */ + expr->ctype = &int_ctype; if (expr->flags) { if (!(expr->left->flags & expr->right->flags & Int_const_expr)) expr->flags = 0; } - return &bool_ctype; + return &int_ctype; } static struct symbol *evaluate_binop(struct expression *expr) @@ -1064,8 +1065,9 @@ static struct symbol *evaluate_compare(struct expression *expr) return NULL; OK: - expr->ctype = &bool_ctype; - return &bool_ctype; + /* the result is int [6.5.8(6), 6.5.9(3)]*/ + expr->ctype = &int_ctype; + return &int_ctype; } /* @@ -1795,7 +1797,7 @@ static struct symbol *evaluate_preop(struct expression *expr) warning(expr->pos, "testing a 'safe expression'"); if (is_float_type(ctype)) { struct expression *arg = expr->unop; - expr->type = EXPR_BINOP; + expr->type = EXPR_COMPARE; expr->op = SPECIAL_EQUAL; expr->left = arg; expr->right = alloc_expression(expr->pos, EXPR_FVALUE); @@ -1805,14 +1807,15 @@ static struct symbol *evaluate_preop(struct expression *expr) warning(expr->pos, "%s degrades to integer", show_typename(ctype->ctype.base_type)); } - ctype = &bool_ctype; + /* the result is int [6.5.3.3(5)]*/ + ctype = &int_ctype; break; default: break; } expr->ctype = ctype; - return &bool_ctype; + return ctype; } static struct symbol *find_identifier(struct ident *ident, struct symbol_list *_list, int *offset) @@ -113,6 +113,8 @@ extern int Wvla; extern int dbg_entry; extern int dbg_dead; +extern int arch_m64; + extern void declare_builtin_functions(void); extern void create_builtin_stream(void); extern struct symbol_list *sparse_initialize(int argc, char **argv, struct string_list **files); diff --git a/linearize.c b/linearize.c index 1d15cfde..c6ada1e8 100644 --- a/linearize.c +++ b/linearize.c @@ -1064,7 +1064,7 @@ static pseudo_t linearize_regular_preop(struct entrypoint *ep, struct expression return pre; case '!': { pseudo_t zero = value_pseudo(0); - return add_binary_op(ep, expr->unop->ctype, OP_SET_EQ, pre, zero); + return add_binary_op(ep, expr->ctype, OP_SET_EQ, pre, zero); } case '~': return add_uniop(ep, expr, OP_NOT, pre); @@ -1418,7 +1418,7 @@ static pseudo_t linearize_compare(struct entrypoint *ep, struct expression *expr pseudo_t src1 = linearize_expression(ep, expr->left); pseudo_t src2 = linearize_expression(ep, expr->right); - pseudo_t dst = add_binary_op(ep, expr->left->ctype, cmpop[expr->op], src1, src2); + pseudo_t dst = add_binary_op(ep, expr->ctype, cmpop[expr->op], src1, src2); return dst; } diff --git a/sparse-llvm.c b/sparse-llvm.c index 6f2fbd69..ecb5b28e 100644 --- a/sparse-llvm.c +++ b/sparse-llvm.c @@ -6,6 +6,7 @@ #include <llvm-c/Core.h> #include <llvm-c/BitWriter.h> #include <llvm-c/Analysis.h> +#include <llvm-c/Target.h> #include <stdbool.h> #include <stdio.h> @@ -18,21 +19,11 @@ #include "linearize.h" #include "flow.h" -struct phi_fwd { - struct phi_fwd *next; - - LLVMValueRef phi; - pseudo_t pseudo; - bool resolved; -}; - struct function { LLVMBuilderRef builder; LLVMTypeRef type; LLVMValueRef fn; LLVMModuleRef module; - - struct phi_fwd *fwd_list; }; static inline bool symbol_is_fp_type(struct symbol *sym) @@ -80,7 +71,7 @@ static LLVMTypeRef sym_func_type(LLVMModuleRef module, struct symbol *sym) arg_type[idx++] = symbol_type(module, arg_sym); } END_FOR_EACH_PTR(arg); func_type = LLVMFunctionType(ret_type, arg_type, n_arg, - sym->ctype.base_type->variadic); + sym->variadic); return func_type; } @@ -91,12 +82,14 @@ static LLVMTypeRef sym_array_type(LLVMModuleRef module, struct symbol *sym) 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); if (!elem_type) return NULL; - return LLVMArrayType(elem_type, sym->bit_size / 8); + return LLVMArrayType(elem_type, sym->bit_size / base_type->bit_size); } #define MAX_STRUCT_MEMBERS 64 @@ -109,13 +102,10 @@ static LLVMTypeRef sym_struct_type(LLVMModuleRef module, struct symbol *sym) LLVMTypeRef ret; unsigned nr = 0; - sprintf(buffer, "%.*s", sym->ident->len, sym->ident->name); - - ret = LLVMGetTypeByName(module, buffer); - if (ret) - return ret; - + snprintf(buffer, sizeof(buffer), "struct.%s", sym->ident ? sym->ident->name : "anno"); ret = LLVMStructCreateNamed(LLVMGetGlobalContext(), buffer); + /* set ->aux to avoid recursion */ + sym->aux = ret; FOR_EACH_PTR(sym->symbol_list, member) { LLVMTypeRef member_type; @@ -213,10 +203,16 @@ static LLVMTypeRef symbol_type(LLVMModuleRef module, 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); + + if (sym->aux) + return sym->aux; + switch (sym->type) { case SYM_BITFIELD: case SYM_ENUM: - case SYM_NODE: ret = symbol_type(module, sym->ctype.base_type); break; case SYM_BASETYPE: @@ -240,6 +236,9 @@ static LLVMTypeRef symbol_type(LLVMModuleRef module, struct symbol *sym) default: assert(0); } + + /* cache the result */ + sym->aux = ret; return ret; } @@ -346,11 +345,16 @@ static LLVMValueRef pseudo_to_value(struct function *fn, struct instruction *ins } } else { const char *name = show_ident(sym->ident); - - result = LLVMGetNamedGlobal(fn->module, name); - if (!result) { - LLVMTypeRef type = symbol_type(fn->module, sym); - result = LLVMAddGlobal(fn->module, type, name); + LLVMTypeRef type = symbol_type(fn->module, sym); + + if (LLVMGetTypeKind(type) == LLVMFunctionTypeKind) { + result = LLVMGetNamedFunction(fn->module, name); + if (!result) + result = LLVMAddFunction(fn->module, name, type); + } else { + result = LLVMGetNamedGlobal(fn->module, name); + if (!result) + result = LLVMAddGlobal(fn->module, type, name); } } break; @@ -375,56 +379,20 @@ static LLVMValueRef pseudo_to_value(struct function *fn, struct instruction *ins return result; } -static LLVMTypeRef pseudo_type(struct function *fn, struct instruction *insn, pseudo_t pseudo) +static LLVMValueRef calc_gep(LLVMBuilderRef builder, LLVMValueRef base, LLVMValueRef off) { - LLVMValueRef v; - LLVMTypeRef result = NULL; - - if (pseudo->priv) { - v = pseudo->priv; - return LLVMTypeOf(v); - } - - switch (pseudo->type) { - case PSEUDO_REG: - result = symbol_type(fn->module, pseudo->def->type); - break; - case PSEUDO_SYM: { - struct symbol *sym = pseudo->sym; - struct expression *expr; - - assert(sym->bb_target == NULL); - assert(sym->ident == NULL); - - expr = sym->initializer; - if (expr) { - switch (expr->type) { - case EXPR_STRING: - result = LLVMPointerType(LLVMInt8Type(), 0); - break; - default: - assert(0); - } - } - break; - } - case PSEUDO_VAL: - result = insn_symbol_type(fn->module, insn); - break; - case PSEUDO_ARG: - result = LLVMTypeOf(LLVMGetParam(fn->fn, pseudo->nr - 1)); - break; - case PSEUDO_PHI: - assert(0); - break; - case PSEUDO_VOID: - result = LLVMVoidType(); - break; - default: - assert(0); - } - - return result; + LLVMTypeRef type = LLVMTypeOf(base); + unsigned int as = LLVMGetPointerAddressSpace(type); + LLVMTypeRef bytep = LLVMPointerType(LLVMInt8Type(), as); + LLVMValueRef addr; + + /* convert base to char* type */ + base = LLVMBuildPointerCast(builder, base, bytep, ""); + /* addr = base + off */ + addr = LLVMBuildInBoundsGEP(builder, base, &off, 1, ""); + /* convert back to the actual pointer type */ + addr = LLVMBuildPointerCast(builder, addr, type, ""); + return addr; } static LLVMRealPredicate translate_fop(int opcode) @@ -544,29 +512,34 @@ static void output_op_binary(struct function *fn, struct instruction *insn) target = LLVMBuildXor(fn->builder, lhs, rhs, target_name); break; case OP_AND_BOOL: { - LLVMValueRef x, y; - - assert(!symbol_is_fp_type(insn->type)); + LLVMValueRef lhs_nz, rhs_nz; + LLVMTypeRef dst_type; - y = LLVMBuildICmp(fn->builder, LLVMIntNE, lhs, LLVMConstInt(LLVMTypeOf(lhs), 0, 0), "y"); - x = LLVMBuildICmp(fn->builder, LLVMIntNE, rhs, LLVMConstInt(LLVMTypeOf(rhs), 0, 0), "x"); + lhs_nz = LLVMBuildIsNotNull(fn->builder, lhs, ""); + rhs_nz = LLVMBuildIsNotNull(fn->builder, rhs, ""); + target = LLVMBuildAnd(fn->builder, lhs_nz, rhs_nz, target_name); - target = LLVMBuildAnd(fn->builder, y, x, 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 tmp; - - assert(!symbol_is_fp_type(insn->type)); + LLVMValueRef lhs_nz, rhs_nz; + LLVMTypeRef dst_type; - tmp = LLVMBuildOr(fn->builder, rhs, lhs, "tmp"); + lhs_nz = LLVMBuildIsNotNull(fn->builder, lhs, ""); + rhs_nz = LLVMBuildIsNotNull(fn->builder, rhs, ""); + target = LLVMBuildOr(fn->builder, lhs_nz, rhs_nz, target_name); - target = LLVMBuildICmp(fn->builder, LLVMIntNE, tmp, LLVMConstInt(LLVMTypeOf(tmp), 0, 0), target_name); + dst_type = insn_symbol_type(fn->module, insn); + target = LLVMBuildZExt(fn->builder, target, dst_type, target_name); break; } /* Binary comparison */ case OP_BINCMP ... OP_BINCMP_END: { + LLVMTypeRef dst_type = insn_symbol_type(fn->module, insn); + if (LLVMGetTypeKind(LLVMTypeOf(lhs)) == LLVMIntegerTypeKind) { LLVMIntPredicate op = translate_op(insn->opcode); @@ -576,6 +549,8 @@ static void output_op_binary(struct function *fn, struct instruction *insn) target = LLVMBuildFCmp(fn->builder, op, lhs, rhs, target_name); } + + target = LLVMBuildZExt(fn->builder, target, dst_type, target_name); break; } default: @@ -598,24 +573,33 @@ static void output_op_ret(struct function *fn, struct instruction *insn) LLVMBuildRetVoid(fn->builder); } -static void output_op_load(struct function *fn, struct instruction *insn) +static LLVMValueRef calc_memop_addr(struct function *fn, struct instruction *insn) { - LLVMTypeRef int_type; - LLVMValueRef src_p, src_i, ofs_i, addr_i, addr, target; + LLVMTypeRef int_type, addr_type; + LLVMValueRef src, off, addr; + unsigned int as; /* 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); + as = LLVMGetPointerAddressSpace(LLVMTypeOf(src)); + addr_type = LLVMPointerType(insn_symbol_type(fn->module, insn), as); + src = LLVMBuildPointerCast(fn->builder, src, addr_type, ""); + + /* addr = src + off */ + addr = calc_gep(fn->builder, src, off); + return addr; +} - /* convert to integer, add src + offset */ - src_p = pseudo_to_value(fn, insn, insn->src); - src_i = LLVMBuildPtrToInt(fn->builder, src_p, int_type, "src_i"); - ofs_i = LLVMConstInt(int_type, insn->offset, 0); - addr_i = LLVMBuildAdd(fn->builder, src_i, ofs_i, "addr_i"); +static void output_op_load(struct function *fn, struct instruction *insn) +{ + LLVMValueRef addr, target; - /* convert address back to pointer */ - addr = LLVMBuildIntToPtr(fn->builder, addr_i, - LLVMTypeOf(src_p), "addr"); + addr = calc_memop_addr(fn, insn); /* perform load */ target = LLVMBuildLoad(fn->builder, addr, "load_target"); @@ -625,22 +609,9 @@ static void output_op_load(struct function *fn, struct instruction *insn) static void output_op_store(struct function *fn, struct instruction *insn) { - LLVMTypeRef int_type; - LLVMValueRef src_p, src_i, ofs_i, addr_i, addr, target, target_in; + LLVMValueRef addr, target, target_in; - /* int type large enough to hold a pointer */ - int_type = LLVMIntType(bits_in_pointer); - - /* convert to integer, add src + offset */ - src_p = pseudo_to_value(fn, insn, insn->src); - src_i = LLVMBuildPtrToInt(fn->builder, src_p, int_type, "src_i"); - - ofs_i = LLVMConstInt(int_type, insn->offset, 0); - addr_i = LLVMBuildAdd(fn->builder, src_i, ofs_i, "addr_i"); - - /* convert address back to pointer */ - addr = LLVMBuildIntToPtr(fn->builder, addr_i, - LLVMPointerType(int_type, 0), "addr"); + addr = calc_memop_addr(fn, insn); target_in = pseudo_to_value(fn, insn, insn->target); @@ -719,102 +690,6 @@ static void output_op_switch(struct function *fn, struct instruction *insn) insn->target->priv = target; } -struct llfunc { - char name[256]; /* wasteful */ - LLVMValueRef func; -}; - -DECLARE_ALLOCATOR(llfunc); -DECLARE_PTR_LIST(llfunc_list, struct llfunc); -ALLOCATOR(llfunc, "llfuncs"); - -static struct local_module { - struct llfunc_list *llfunc_list; -} mi; - -static LLVMTypeRef get_func_type(struct function *fn, struct instruction *insn) -{ - struct symbol *sym = insn->func->sym; - char buffer[256]; - LLVMTypeRef func_type, ret_type; - struct pseudo *arg; - int n_arg = 0; - LLVMTypeRef *arg_type; - - if (sym->ident) - sprintf(buffer, "%.*s", sym->ident->len, sym->ident->name); - else - sprintf(buffer, "<anon sym %p>", sym); - - /* VERIFY: is this correct, for functions? */ - func_type = LLVMGetTypeByName(fn->module, buffer); - if (func_type) - return func_type; - - /* 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. - */ - - /* build return type */ - if (insn->target && insn->target != VOID) - ret_type = pseudo_type(fn, insn, insn->target); - else - ret_type = LLVMVoidType(); - - /* count args, build argument type information */ - FOR_EACH_PTR(insn->arguments, arg) { - n_arg++; - } END_FOR_EACH_PTR(arg); - - arg_type = calloc(n_arg, sizeof(LLVMTypeRef)); - - int idx = 0; - FOR_EACH_PTR(insn->arguments, arg) { - arg_type[idx++] = pseudo_type(fn, insn, arg); - } END_FOR_EACH_PTR(arg); - - func_type = LLVMFunctionType(ret_type, arg_type, n_arg, - insn->fntype->variadic); - - return func_type; -} - -static LLVMValueRef get_function(struct function *fn, struct instruction *insn) -{ - struct symbol *sym = insn->func->sym; - char buffer[256]; - LLVMValueRef func; - struct llfunc *f; - - if (sym->ident) - sprintf(buffer, "%.*s", sym->ident->len, sym->ident->name); - else - sprintf(buffer, "<anon sym %p>", sym); - - - /* search for pre-built function type definition */ - FOR_EACH_PTR(mi.llfunc_list, f) { - if (!strcmp(f->name, buffer)) - return f->func; /* found match; return */ - } END_FOR_EACH_PTR(f); - - /* build function type definition */ - LLVMTypeRef func_type = get_func_type(fn, insn); - - func = LLVMAddFunction(fn->module, buffer, func_type); - - /* store built function on list, for later referencing */ - f = calloc(1, sizeof(*f)); - strncpy(f->name, buffer, sizeof(f->name) - 1); - f->func = func; - - add_ptr_list(&mi.llfunc_list, f); - - return func; -} - static void output_op_call(struct function *fn, struct instruction *insn) { LLVMValueRef target, func; @@ -833,106 +708,45 @@ static void output_op_call(struct function *fn, struct instruction *insn) args[i++] = pseudo_to_value(fn, insn, arg); } END_FOR_EACH_PTR(arg); - func = get_function(fn, insn); + func = pseudo_to_value(fn, insn, insn->func); target = LLVMBuildCall(fn->builder, func, args, n_arg, ""); insn->target->priv = target; } -static void store_phi_fwd(struct function *fn, LLVMValueRef phi, - pseudo_t pseudo) -{ - struct phi_fwd *fwd; - - fwd = calloc(1, sizeof(*fwd)); - fwd->phi = phi; - fwd->pseudo = pseudo; - - /* append fwd ref to function-wide list */ - if (!fn->fwd_list) - fn->fwd_list = fwd; - else { - struct phi_fwd *last = fn->fwd_list; - - while (last->next) - last = last->next; - last->next = fwd; - } -} - -static void output_phi_fwd(struct function *fn, pseudo_t pseudo, LLVMValueRef v) -{ - struct phi_fwd *fwd = fn->fwd_list; - - while (fwd) { - struct phi_fwd *tmp; - - tmp = fwd; - fwd = fwd->next; - - if (tmp->pseudo == pseudo && !tmp->resolved) { - LLVMValueRef phi_vals[1]; - LLVMBasicBlockRef phi_blks[1]; - - phi_vals[0] = v; - phi_blks[0] = pseudo->def->bb->priv; - - LLVMAddIncoming(tmp->phi, phi_vals, phi_blks, 1); - - tmp->resolved = true; - } - } -} - static void output_op_phisrc(struct function *fn, struct instruction *insn) { LLVMValueRef v; + struct instruction *phi; assert(insn->target->priv == NULL); /* target = src */ v = pseudo_to_value(fn, insn, insn->phi_src); - insn->target->priv = v; - assert(insn->target->priv != NULL); + FOR_EACH_PTR(insn->phi_users, phi) { + LLVMValueRef load, ptr; - /* resolve forward references to this phi source, if present */ - output_phi_fwd(fn, insn->target, v); + assert(phi->opcode == OP_PHI); + /* phi must be load from alloca */ + load = phi->target->priv; + assert(LLVMGetInstructionOpcode(load) == LLVMLoad); + ptr = LLVMGetOperand(load, 0); + /* store v to alloca */ + LLVMBuildStore(fn->builder, v, ptr); + } END_FOR_EACH_PTR(phi); } static void output_op_phi(struct function *fn, struct instruction *insn) { - pseudo_t phi; - LLVMValueRef target; - - target = LLVMBuildPhi(fn->builder, insn_symbol_type(fn->module, insn), - "phi"); - int pll = 0; - FOR_EACH_PTR(insn->phi_list, phi) { - if (pseudo_to_value(fn, insn, phi)) /* skip VOID, fwd refs*/ - pll++; - } END_FOR_EACH_PTR(phi); - - LLVMValueRef *phi_vals = calloc(pll, sizeof(LLVMValueRef)); - LLVMBasicBlockRef *phi_blks = calloc(pll, sizeof(LLVMBasicBlockRef)); - - int idx = 0; - FOR_EACH_PTR(insn->phi_list, phi) { - LLVMValueRef v; - - v = pseudo_to_value(fn, insn, phi); - if (v) { /* skip VOID, fwd refs */ - phi_vals[idx] = v; - phi_blks[idx] = phi->def->bb->priv; - idx++; - } - else if (phi->type == PSEUDO_PHI) /* fwd ref */ - store_phi_fwd(fn, target, phi); - } END_FOR_EACH_PTR(phi); - - LLVMAddIncoming(target, phi_vals, phi_blks, pll); - - insn->target->priv = target; + LLVMValueRef load = insn->target->priv; + + /* forward load */ + assert(LLVMGetInstructionOpcode(load) == LLVMLoad); + /* forward load has no parent block */ + assert(!LLVMGetInstructionParent(load)); + /* finalize load in current block */ + LLVMInsertIntoBuilder(fn->builder, load); } static void output_op_ptrcast(struct function *fn, struct instruction *insn) @@ -1095,7 +909,6 @@ static void output_insn(struct function *fn, struct instruction *insn) assert(0); break; case OP_DEATHNOTE: - assert(0); break; case OP_ASM: assert(0); @@ -1138,7 +951,6 @@ static void output_fn(LLVMModuleRef module, struct entrypoint *ep) struct symbol *arg; const char *name; int nr_args = 0; - struct llfunc *f; FOR_EACH_PTR(base_type->arguments, arg) { struct symbol *arg_base_type = arg->ctype.base_type; @@ -1157,13 +969,6 @@ static void output_fn(LLVMModuleRef module, struct entrypoint *ep) LLVMSetLinkage(function.fn, function_linkage(sym)); - /* store built function on list, for later referencing */ - f = calloc(1, sizeof(*f)); - strncpy(f->name, name, sizeof(f->name) - 1); - f->func = function.fn; - - add_ptr_list(&mi.llfunc_list, f); - function.builder = LLVMCreateBuilder(); static int nr_bb; @@ -1174,11 +979,30 @@ static void output_fn(LLVMModuleRef module, struct entrypoint *ep) LLVMBasicBlockRef bbr; char bbname[32]; + struct instruction *insn; sprintf(bbname, "L%d", nr_bb++); bbr = LLVMAppendBasicBlock(function.fn, bbname); bb->priv = bbr; + + /* allocate alloca for each phi */ + FOR_EACH_PTR(bb->insns, insn) { + LLVMBasicBlockRef entrybbr; + LLVMTypeRef phi_type; + LLVMValueRef ptr; + + 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); + 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); @@ -1233,6 +1057,12 @@ static LLVMValueRef output_data(LLVMModuleRef module, struct symbol *sym) data = LLVMAddGlobal(module, LLVMTypeOf(initial_value), name); LLVMSetLinkage(data, data_linkage(sym)); + if (sym->ctype.modifiers & MOD_CONST) + LLVMSetGlobalConstant(data, 1); + if (sym->ctype.modifiers & MOD_TLS) + LLVMSetThreadLocal(data, 1); + if (sym->ctype.alignment) + LLVMSetAlignment(data, sym->ctype.alignment); if (!(sym->ctype.modifiers & MOD_EXTERN)) LLVMSetInitializer(data, initial_value); @@ -1258,17 +1088,75 @@ static int compile(LLVMModuleRef module, struct symbol_list *list) return 0; } +#ifndef LLVM_DEFAULT_TARGET_TRIPLE +#define LLVM_DEFAULT_TARGET_TRIPLE LLVM_HOSTTRIPLE +#endif + +#define X86_LINUX_LAYOUT \ + "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" \ + "i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-" \ + "a0:0:64-f80:32:32-n8:16:32-S128" + +#define X86_64_LINUX_LAYOUT \ + "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" \ + "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-" \ + "a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" + +static void set_target(LLVMModuleRef module) +{ + char target[] = LLVM_DEFAULT_TARGET_TRIPLE; + const char *arch, *vendor, *os, *env, *layout = NULL; + char triple[256]; + + arch = strtok(target, "-"); + vendor = strtok(NULL, "-"); + os = strtok(NULL, "-"); + env = strtok(NULL, "-"); + + if (!os) + return; + if (!env) + env = "unknown"; + + if (!strcmp(arch, "x86_64") && !strcmp(os, "linux")) { + if (arch_m64) { + layout = X86_64_LINUX_LAYOUT; + } else { + arch = "i386"; + layout = X86_LINUX_LAYOUT; + } + } + + /* unsupported target */ + if (!layout) + return; + + snprintf(triple, sizeof(triple), "%s-%s-%s-%s", arch, vendor, os, env); + LLVMSetTarget(module, triple); + LLVMSetDataLayout(module, layout); +} + int main(int argc, char **argv) { - struct string_list * filelist = NULL; + struct string_list *filelist = NULL; + struct symbol_list *symlist; + LLVMModuleRef module; char *file; - LLVMModuleRef module = LLVMModuleCreateWithName("sparse"); + symlist = sparse_initialize(argc, argv, &filelist); + + module = LLVMModuleCreateWithName("sparse"); + set_target(module); - compile(module, sparse_initialize(argc, argv, &filelist)); + compile(module, symlist); + /* need ->phi_users */ + dbg_dead = 1; FOR_EACH_PTR_NOTAG(filelist, file) { - compile(module, sparse(file)); + symlist = sparse(file); + if (die_if_error) + return 1; + compile(module, symlist); } END_FOR_EACH_PTR_NOTAG(file); LLVMVerifyModule(module, LLVMPrintMessageAction, NULL); diff --git a/sparsei b/sparsei new file mode 100755 index 00000000..46321542 --- /dev/null +++ b/sparsei @@ -0,0 +1,13 @@ +#!/bin/sh + +set +e + +DIRNAME=`dirname $0` +LLI=`llvm-config --bindir`/lli + +if [ $# -eq 0 ]; then + echo "`basename $0`: no input files" + exit 1 +fi + +$DIRNAME/sparse-llvm $@ | $LLI diff --git a/validation/backend/loop2.c b/validation/backend/loop2.c new file mode 100644 index 00000000..279af214 --- /dev/null +++ b/validation/backend/loop2.c @@ -0,0 +1,14 @@ +extern int op(void); + +static void test(void) +{ + int i; + for (i = 0; ; i++) { + op(); + } +} + +/* + * check-name: Loops with unused counter + * check-command: ./sparsec -c $file -o tmp.o + */ diff --git a/validation/backend/store-type.c b/validation/backend/store-type.c new file mode 100644 index 00000000..9e2ce73f --- /dev/null +++ b/validation/backend/store-type.c @@ -0,0 +1,12 @@ +struct foo; +static struct foo *var; + +static void set(struct foo *f) +{ + var = f; +} + +/* + * check-name: Type of stored objects + * check-command: ./sparsec -c $file -o tmp.o + */ diff --git a/validation/backend/struct-access.c b/validation/backend/struct-access.c new file mode 100644 index 00000000..884b4706 --- /dev/null +++ b/validation/backend/struct-access.c @@ -0,0 +1,28 @@ +struct st { + int i, *d; +}; + +static int load_i(struct st *st) +{ + return st->i; +} + +static void store_i(struct st *st, int i) +{ + st->i = i; +} + +static int *load_d(struct st *st) +{ + return st->d; +} + +static void store_d(struct st *st, int *d) +{ + st->d = d; +} + +/* + * check-name: struct access code generation + * check-command: ./sparsec -c $file -o tmp.o + */ diff --git a/validation/backend/struct.c b/validation/backend/struct.c index 1afaf2db..905339af 100644 --- a/validation/backend/struct.c +++ b/validation/backend/struct.c @@ -9,10 +9,16 @@ struct symbol { struct symbol *next_id; }; +struct unnamed { + struct { int x, y; }; +}; + static struct symbol sym; static struct symbol *sym_p; static struct symbol *sym_q = &sym; +static struct unnamed un; + /* * check-name: Struct code generation * check-command: ./sparsec -c $file -o tmp.o diff --git a/validation/backend/sum.c b/validation/backend/sum.c new file mode 100644 index 00000000..c9451d4b --- /dev/null +++ b/validation/backend/sum.c @@ -0,0 +1,28 @@ +#include <stdio.h> +#include <stdlib.h> + +static int sum(int n) +{ + int i, result = 0; + + for (i = 1; i <= n; ++i) + result += i; + return result; +} + +int main(int argc, char **argv) +{ + printf("%d\n", sum(5)); + printf("%d\n", sum(100)); + return 0; +} + +/* + * check-name: sum from 1 to n + * check-command: ./sparsei $file + * + * check-output-start +15 +5050 + * check-output-end + */ diff --git a/validation/cond_expr3.c b/validation/cond_expr3.c new file mode 100644 index 00000000..748409e6 --- /dev/null +++ b/validation/cond_expr3.c @@ -0,0 +1,17 @@ +static int icmp = 1 / (sizeof(int) - sizeof(1 > 0)); +static int fcmp = 1 / (sizeof(int) - sizeof(1.0 == 2.0 - 1.0)); +static int lnot = 1 / (sizeof(int) - sizeof(!!1.0)); +static int land = 1 / (sizeof(int) - sizeof(2 && 3)); +static int lor = 1 / (sizeof(int) - sizeof('c' || 1.0f)); + +/* + * check-name: result type of relational and logical operators + * + * check-error-start +cond_expr3.c:1:21: warning: division by zero +cond_expr3.c:2:21: warning: division by zero +cond_expr3.c:3:21: warning: division by zero +cond_expr3.c:4:21: warning: division by zero +cond_expr3.c:5:21: warning: division by zero + * check-error-end + */ |