diff options
44 files changed, 873 insertions, 366 deletions
diff --git a/Documentation/IR.rst b/Documentation/IR.rst index 0419ac41..8ffc921a 100644 --- a/Documentation/IR.rst +++ b/Documentation/IR.rst @@ -241,6 +241,12 @@ Unary ops * .target: result of the operation (must be a floating-point type) * .type: type of .target +.. op:: OP_SYMADDR + Create a pseudo corresponding to the address of a symbol. + + * .src: input symbol (must be a PSEUDO_SYM) + * .target: symbol's address + .. op:: OP_COPY Copy (only needed after out-of-SSA). @@ -327,12 +333,6 @@ Memory ops Others ------ -.. op:: OP_SYMADDR - Create a pseudo corresponding to the address of a symbol. - - * .symbol: (pseudo_t) input symbol (alias .src) - * .target: symbol's address - .. op:: OP_SETFVAL Create a pseudo corresponding to a floating-point literal. diff --git a/Documentation/dev-options.rst b/Documentation/dev-options.rst index 04fb651f..23e8096c 100644 --- a/Documentation/dev-options.rst +++ b/Documentation/dev-options.rst @@ -33,6 +33,7 @@ OPTIONS The passes currently understood are: + * ``linearize`` (can't be disabled) * ``mem2reg`` * ``optim`` @@ -76,6 +76,7 @@ void cse_collect(struct instruction *insn) /* Unary */ case OP_NOT: case OP_NEG: case OP_FNEG: + case OP_SYMADDR: hash += hashval(insn->src1); break; @@ -87,10 +88,6 @@ void cse_collect(struct instruction *insn) hash += hashval(insn->fvalue); break; - case OP_SYMADDR: - hash += hashval(insn->symbol); - break; - case OP_SEXT: case OP_ZEXT: case OP_TRUNC: case OP_PTRCAST: @@ -213,15 +210,11 @@ static int insn_compare(const void *_i1, const void *_i2) /* Unary */ case OP_NOT: case OP_NEG: case OP_FNEG: + case OP_SYMADDR: if (i1->src1 != i2->src1) return i1->src1 < i2->src1 ? -1 : 1; break; - case OP_SYMADDR: - if (i1->symbol != i2->symbol) - return i1->symbol < i2->symbol ? -1 : 1; - break; - case OP_SETVAL: if (i1->val != i2->val) return i1->val < i2->val ? -1 : 1; @@ -23,7 +23,7 @@ struct piggy { struct basic_block_list *lists[0]; }; -struct piggy *bank_init(unsigned levels) +static struct piggy *bank_init(unsigned levels) { struct piggy *bank; bank = calloc(1, sizeof(*bank) + levels * sizeof(bank->lists[0])); @@ -6,4 +6,8 @@ struct basic_block_list; void idf_compute(struct entrypoint *ep, struct basic_block_list **idf, struct basic_block_list *alpha); + +// For debugging only +void idf_dump(struct entrypoint *ep); + #endif @@ -3003,14 +3003,14 @@ static struct symbol *evaluate_cast(struct expression *expr) } } - if (ttype == &ulong_ctype) + if (ttype == &ulong_ctype && !Wcast_from_as) tas = -1; else if (tclass == TYPE_PTR) { examine_pointer_target(ttype); tas = ttype->ctype.as; } - if (stype == &ulong_ctype) + if (stype == &ulong_ctype && !Wcast_from_as) sas = -1; else if (sclass == TYPE_PTR) { examine_pointer_target(stype); @@ -174,7 +174,7 @@ static int bb_has_side_effects(struct basic_block *bb) case OP_LOAD: if (!insn->type) return 1; - if (insn->type->ctype.modifiers & MOD_VOLATILE) + if (insn->is_volatile) return 1; continue; @@ -20,6 +20,7 @@ extern void simplify_memops(struct entrypoint *ep); extern void pack_basic_blocks(struct entrypoint *ep); extern void convert_instruction_target(struct instruction *insn, pseudo_t src); +extern void remove_dead_insns(struct entrypoint *); extern int simplify_instruction(struct instruction *); extern void kill_bb(struct basic_block *); diff --git a/ident-list.h b/ident-list.h index a37a4a1b..75740b9d 100644 --- a/ident-list.h +++ b/ident-list.h @@ -59,6 +59,7 @@ IDENT_RESERVED(__label__); * sparse. */ IDENT(defined); IDENT(once); +IDENT(__has_attribute); IDENT(__has_builtin); __IDENT(pragma_ident, "__pragma__", 0); __IDENT(__VA_ARGS___ident, "__VA_ARGS__", 0); @@ -29,6 +29,9 @@ static int check_phi_node(struct instruction *insn) pseudo_t phi; int err = 0; + if (!has_users(insn->target)) + return err; + if (bb_list_size(insn->bb->parents) != nbr_phi_operands(insn)) { sparse_error(insn->pos, "bad number of phi operands in:\n\t%s", show_instruction(insn)); @@ -82,7 +85,40 @@ static int check_user(struct instruction *insn, pseudo_t pseudo) return 0; } -static int validate_insn(struct instruction *insn) +static int check_branch(struct entrypoint *ep, struct instruction *insn, struct basic_block *bb) +{ + if (bb->ep && lookup_bb(ep->bbs, bb)) + return 0; + sparse_error(insn->pos, "branch to dead BB: %s", show_instruction(insn)); + return 1; +} + +static int check_switch(struct entrypoint *ep, struct instruction *insn) +{ + struct multijmp *jmp; + int err = 0; + + FOR_EACH_PTR(insn->multijmp_list, jmp) { + err = check_branch(ep, insn, jmp->target); + if (err) + return err; + } END_FOR_EACH_PTR(jmp); + + return err; +} + +static int check_return(struct instruction *insn) +{ + struct symbol *ctype = insn->type; + + if (ctype && ctype->bit_size > 0 && insn->src == VOID) { + sparse_error(insn->pos, "return without value"); + return 1; + } + return 0; +} + +static int validate_insn(struct entrypoint *ep, struct instruction *insn) { int err = 0; @@ -104,6 +140,9 @@ static int validate_insn(struct instruction *insn) break; case OP_CBR: + err += check_branch(ep, insn, insn->bb_true); + err += check_branch(ep, insn, insn->bb_false); + /* fall through */ case OP_COMPUTEDGOTO: err += check_user(insn, insn->cond); break; @@ -124,8 +163,18 @@ static int validate_insn(struct instruction *insn) err += check_user(insn, insn->src); break; - case OP_ENTRY: + case OP_RET: + err += check_return(insn); + break; + case OP_BR: + err += check_branch(ep, insn, insn->bb_true); + break; + case OP_SWITCH: + err += check_switch(ep, insn); + break; + + case OP_ENTRY: case OP_SETVAL: default: break; @@ -147,7 +196,7 @@ int ir_validate(struct entrypoint *ep) FOR_EACH_PTR(bb->insns, insn) { if (!insn->bb) continue; - err += validate_insn(insn); + err += validate_insn(ep, insn); } END_FOR_EACH_PTR(insn); } END_FOR_EACH_PTR(bb); @@ -248,6 +248,7 @@ static struct token *pre_buffer_end = NULL; int Waddress = 0; int Waddress_space = 1; int Wbitwise = 1; +int Wcast_from_as = 0; int Wcast_to_as = 0; int Wcast_truncate = 1; int Wconstexpr_not_const = 0; @@ -682,6 +683,7 @@ static const struct flag warnings[] = { { "address", &Waddress }, { "address-space", &Waddress_space }, { "bitwise", &Wbitwise }, + { "cast-from-as", &Wcast_from_as }, { "cast-to-as", &Wcast_to_as }, { "cast-truncate", &Wcast_truncate }, { "constexpr-not-const", &Wconstexpr_not_const}, @@ -956,6 +958,7 @@ static int handle_fmax_warnings(const char *arg, const char *opt, const struct f static struct flag fflags[] = { { "diagnostic-prefix", NULL, handle_fdiagnostic_prefix }, { "dump-ir", NULL, handle_fdump_ir }, + { "linearize", NULL, handle_fpasses, PASS_LINEARIZE }, { "max-warnings=", NULL, handle_fmax_warnings }, { "mem-report", &fmem_report }, { "memcpy-max-count=", NULL, handle_fmemcpy_max_count }, @@ -1287,6 +1290,7 @@ static void create_builtin_stream(void) add_pre_buffer("#add_system \"%s/include-fixed\"\n", gcc_base_dir); add_pre_buffer("#define __has_builtin(x) 0\n"); + add_pre_buffer("#define __has_attribute(x) 0\n"); add_pre_buffer("#define __builtin_stdarg_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n"); add_pre_buffer("#define __builtin_va_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n"); add_pre_buffer("#define __builtin_ms_va_start(a,b) ((a) = (__builtin_ms_va_list)(&(b)))\n"); @@ -138,6 +138,7 @@ extern int preprocess_only; extern int Waddress; extern int Waddress_space; extern int Wbitwise; +extern int Wcast_from_as; extern int Wcast_to_as; extern int Wcast_truncate; extern int Wconstexpr_not_const; diff --git a/linearize.c b/linearize.c index a56c272f..670e3830 100644 --- a/linearize.c +++ b/linearize.c @@ -351,11 +351,6 @@ const char *show_instruction(struct instruction *insn) buf += sprintf(buf, "%s", show_label(insn->bb_true)); break; - case OP_SYMADDR: - buf += sprintf(buf, "%s <- ", show_pseudo(insn->target)); - buf += sprintf(buf, "%s", show_pseudo(insn->symbol)); - break; - case OP_SETVAL: { struct expression *expr = insn->val; buf += sprintf(buf, "%s <- ", show_pseudo(insn->target)); @@ -481,6 +476,7 @@ const char *show_instruction(struct instruction *insn) case OP_NOT: case OP_NEG: case OP_FNEG: + case OP_SYMADDR: buf += sprintf(buf, "%s <- %s", show_pseudo(insn->target), show_pseudo(insn->src1)); break; @@ -991,6 +987,7 @@ static pseudo_t add_load(struct entrypoint *ep, struct access_data *ad) insn->target = new; insn->offset = ad->offset; + insn->is_volatile = ad->type && (ad->type->ctype.modifiers & MOD_VOLATILE); use_pseudo(insn, ad->address, &insn->src); add_one_insn(ep, insn); return new; @@ -1006,6 +1003,7 @@ static void add_store(struct entrypoint *ep, struct access_data *ad, pseudo_t va store = alloc_typed_instruction(OP_STORE, ad->btype); store->offset = ad->offset; + store->is_volatile = ad->type && (ad->type->ctype.modifiers & MOD_VOLATILE); use_pseudo(store, value, &store->target); use_pseudo(store, ad->address, &store->src); add_one_insn(ep, store); @@ -1104,7 +1102,7 @@ static pseudo_t add_symbol_address(struct entrypoint *ep, struct symbol *sym) pseudo_t target = alloc_pseudo(insn); insn->target = target; - use_pseudo(insn, symbol_pseudo(ep, sym), &insn->symbol); + use_pseudo(insn, symbol_pseudo(ep, sym), &insn->src); add_one_insn(ep, insn); return target; } @@ -1697,41 +1695,54 @@ static pseudo_t linearize_conditional(struct entrypoint *ep, struct expression * return add_join_conditional(ep, expr, phi1, phi2); } +static void insert_phis(struct basic_block *bb, pseudo_t src, struct symbol *ctype, + struct instruction *node) +{ + struct basic_block *parent; + + FOR_EACH_PTR(bb->parents, parent) { + struct instruction *br = delete_last_instruction(&parent->insns); + pseudo_t phi = alloc_phi(parent, src, ctype); + add_instruction(&parent->insns, br); + use_pseudo(node, phi, add_pseudo(&node->phi_list, phi)); + } END_FOR_EACH_PTR(parent); +} + static pseudo_t linearize_logical(struct entrypoint *ep, struct expression *expr) { + struct symbol *ctype = expr->ctype; struct basic_block *other, *merge; - pseudo_t phi1, phi2; + struct instruction *node; + pseudo_t src1, src2, phi2; if (!ep->active || !expr->left || !expr->right) return VOID; other = alloc_basic_block(ep, expr->right->pos); merge = alloc_basic_block(ep, expr->pos); + node = alloc_phi_node(merge, ctype, NULL); + // LHS and its shortcut if (expr->op == SPECIAL_LOGICAL_OR) { - pseudo_t src2; - - phi1 = alloc_phi(ep->active, value_pseudo(1), expr->ctype); linearize_cond_branch(ep, expr->left, merge, other); - - set_activeblock(ep, other); - src2 = linearize_expression_to_bool(ep, expr->right); - src2 = cast_pseudo(ep, src2, &bool_ctype, expr->ctype); - phi2 = alloc_phi(ep->active, src2, expr->ctype); + src1 = value_pseudo(1); } else { - pseudo_t src1; - - phi2 = alloc_phi(ep->active, value_pseudo(0), expr->ctype); linearize_cond_branch(ep, expr->left, other, merge); - - set_activeblock(ep, other); - src1 = linearize_expression_to_bool(ep, expr->right); - src1 = cast_pseudo(ep, src1, &bool_ctype, expr->ctype); - phi1 = alloc_phi(ep->active, src1, expr->ctype); + src1 = value_pseudo(0); } + insert_phis(merge, src1, ctype, node); + // RHS + set_activeblock(ep, other); + src2 = linearize_expression_to_bool(ep, expr->right); + src2 = cast_pseudo(ep, src2, &bool_ctype, ctype); + phi2 = alloc_phi(ep->active, src2, ctype); + use_pseudo(node, phi2, add_pseudo(&node->phi_list, phi2)); + + // join set_activeblock(ep, merge); - return add_join_conditional(ep, expr, phi1, phi2); + add_instruction(&merge->insns, node); + return node->target; } static pseudo_t linearize_compare(struct entrypoint *ep, struct expression *expr) @@ -1971,22 +1982,49 @@ static pseudo_t linearize_compound_statement(struct entrypoint *ep, struct state { pseudo_t pseudo; struct statement *s; - struct symbol *ret = stmt->ret; pseudo = VOID; FOR_EACH_PTR(stmt->stmts, s) { pseudo = linearize_statement(ep, s); } END_FOR_EACH_PTR(s); - if (ret) { - struct basic_block *bb = add_label(ep, ret); - struct instruction *phi_node = first_instruction(bb->insns); + return pseudo; +} - if (!phi_node) - return pseudo; - return phi_node->target; +static void add_return(struct entrypoint *ep, struct basic_block *bb, struct symbol *ctype, pseudo_t src) +{ + struct instruction *phi_node = first_instruction(bb->insns); + pseudo_t phi; + if (!phi_node) { + phi_node = alloc_typed_instruction(OP_PHI, ctype); + phi_node->target = alloc_pseudo(phi_node); + phi_node->bb = bb; + add_instruction(&bb->insns, phi_node); } + phi = alloc_phi(ep->active, src, ctype); + phi->ident = &return_ident; + use_pseudo(phi_node, phi, add_pseudo(&phi_node->phi_list, phi)); +} +static pseudo_t linearize_fn_statement(struct entrypoint *ep, struct statement *stmt) +{ + struct instruction *phi_node; + struct basic_block *bb; + pseudo_t pseudo; + + pseudo = linearize_compound_statement(ep, stmt); + if (!is_void_type(stmt->ret)) { // non-void function + struct basic_block *active = ep->active; + if (active && !bb_terminated(active)) { // missing return + struct basic_block *bb_ret; + bb_ret = get_bound_block(ep, stmt->ret); + add_return(ep, bb_ret, stmt->ret, undef_pseudo()); + } + } + bb = add_label(ep, stmt->ret); + phi_node = first_instruction(bb->insns); + if (phi_node) + pseudo = phi_node->target; return pseudo; } @@ -2007,10 +2045,12 @@ static pseudo_t linearize_inlined_call(struct entrypoint *ep, struct statement * } END_FOR_EACH_PTR(sym); } - insn->target = pseudo = linearize_compound_statement(ep, stmt); + pseudo = linearize_fn_statement(ep, stmt); + insn->target = pseudo; + use_pseudo(insn, symbol_pseudo(ep, stmt->inline_fn), &insn->func); bb = ep->active; - if (bb && !bb->insns) + if (!bb->insns) bb->pos = stmt->pos; add_one_insn(ep, insn); return pseudo; @@ -2146,22 +2186,13 @@ static pseudo_t linearize_declaration(struct entrypoint *ep, struct statement *s static pseudo_t linearize_return(struct entrypoint *ep, struct statement *stmt) { struct expression *expr = stmt->expression; - struct basic_block *bb_return = get_bound_block(ep, stmt->ret_target); + struct symbol *ret = stmt->ret_target; + struct basic_block *bb_return = get_bound_block(ep, ret); struct basic_block *active; pseudo_t src = linearize_expression(ep, expr); active = ep->active; - if (active && src != VOID) { - struct instruction *phi_node = first_instruction(bb_return->insns); - pseudo_t phi; - if (!phi_node) { - phi_node = alloc_typed_instruction(OP_PHI, expr->ctype); - phi_node->target = alloc_pseudo(phi_node); - phi_node->bb = bb_return; - add_instruction(&bb_return->insns, phi_node); - } - phi = alloc_phi(active, src, expr->ctype); - phi->ident = &return_ident; - use_pseudo(phi_node, phi, add_pseudo(&phi_node->phi_list, phi)); + if (active && !is_void_type(ret)) { + add_return(ep, bb_return, ret, src); } add_goto(ep, bb_return); return VOID; @@ -2177,13 +2208,14 @@ static pseudo_t linearize_switch(struct entrypoint *ep, struct statement *stmt) struct multijmp *jmp; pseudo_t pseudo; + if (!expr || !expr->ctype) + return VOID; pseudo = linearize_expression(ep, expr); - if (pseudo == VOID) - return pseudo; - active = ep->active; - if (!bb_reachable(active)) - return VOID; + if (!active) { + active = alloc_basic_block(ep, stmt->pos); + set_activeblock(ep, active); + } switch_ins = alloc_typed_instruction(OP_SWITCH, expr->ctype); use_pseudo(switch_ins, pseudo, &switch_ins->cond); @@ -2417,23 +2449,30 @@ static pseudo_t linearize_statement(struct entrypoint *ep, struct statement *stm static struct entrypoint *linearize_fn(struct symbol *sym, struct symbol *base_type) { + struct statement *stmt = base_type->stmt; struct entrypoint *ep; struct basic_block *bb; + struct symbol *ret_type; struct symbol *arg; struct instruction *entry; + struct instruction *ret; pseudo_t result; int i; - if (!base_type->stmt) + if (!stmt) return NULL; ep = alloc_entrypoint(); - bb = alloc_basic_block(ep, sym->pos); - ep->name = sym; sym->ep = ep; + bb = alloc_basic_block(ep, sym->pos); set_activeblock(ep, bb); + if (stmt->type == STMT_ASM) { // top-level asm + linearize_asm_statement(ep, stmt); + return ep; + } + entry = alloc_instruction(OP_ENTRY, 0); add_one_insn(ep, entry); ep->entry = entry; @@ -2446,15 +2485,12 @@ static struct entrypoint *linearize_fn(struct symbol *sym, struct symbol *base_t linearize_argument(ep, arg, ++i); } END_FOR_EACH_PTR(arg); - result = linearize_statement(ep, base_type->stmt); - if (bb_reachable(ep->active) && !bb_terminated(ep->active)) { - struct symbol *ret_type = base_type->ctype.base_type; - struct instruction *insn = alloc_typed_instruction(OP_RET, ret_type); - - if (type_size(ret_type) > 0) - use_pseudo(insn, result, &insn->src); - add_one_insn(ep, insn); - } + result = linearize_fn_statement(ep, stmt); + ret_type = base_type->ctype.base_type; + ret = alloc_typed_instruction(OP_RET, ret_type); + if (type_size(ret_type) > 0) + use_pseudo(ret, result, &ret->src); + add_one_insn(ep, ret); optimize(ep); return ep; diff --git a/linearize.h b/linearize.h index 5eb9562e..89da3db6 100644 --- a/linearize.h +++ b/linearize.h @@ -113,7 +113,11 @@ struct instruction { struct /* unops */ { pseudo_t src; struct symbol *orig_type; /* casts */ - unsigned int offset; /* memops */ + }; + struct /* memops */ { + pseudo_t addr; /* alias .src */ + unsigned int offset; + unsigned int is_volatile:1; }; struct /* binops and sel */ { pseudo_t src1, src2, src3; @@ -122,9 +126,6 @@ struct instruction { pseudo_t base; unsigned from, len; }; - struct /* symaddr */ { - pseudo_t symbol; /* Subtle: same offset as "src" !! */ - }; struct /* setval */ { struct expression *val; }; @@ -148,122 +149,6 @@ struct instruction { }; }; -enum opcode { - OP_BADOP, - - /* Entry */ - OP_ENTRY, - - /* Terminator */ - OP_TERMINATOR, - OP_RET = OP_TERMINATOR, - OP_BR, - OP_CBR, - OP_SWITCH, - OP_COMPUTEDGOTO, - OP_TERMINATOR_END = OP_COMPUTEDGOTO, - - /* Binary */ - OP_BINARY, - OP_ADD = OP_BINARY, - OP_SUB, - OP_MUL, - OP_DIVU, OP_DIVS, - OP_MODU, OP_MODS, - OP_SHL, - OP_LSR, OP_ASR, - - /* Floating-point binops */ - OP_FADD, - OP_FSUB, - OP_FMUL, - OP_FDIV, - - /* Logical */ - OP_AND, - OP_OR, - OP_XOR, - OP_BINARY_END = OP_XOR, - - /* floating-point comparison */ - OP_FPCMP, - OP_FCMP_ORD = OP_FPCMP, - OP_FCMP_OEQ, - OP_FCMP_ONE, - OP_FCMP_OLE, - OP_FCMP_OGE, - OP_FCMP_OLT, - OP_FCMP_OGT, - OP_FCMP_UEQ, - OP_FCMP_UNE, - OP_FCMP_ULE, - OP_FCMP_UGE, - OP_FCMP_ULT, - OP_FCMP_UGT, - OP_FCMP_UNO, - OP_FPCMP_END = OP_FCMP_UNO, - - /* Binary comparison */ - OP_BINCMP, - OP_SET_EQ = OP_BINCMP, - OP_SET_NE, - OP_SET_LE, - OP_SET_GE, - OP_SET_LT, - OP_SET_GT, - OP_SET_B, - OP_SET_A, - OP_SET_BE, - OP_SET_AE, - OP_BINCMP_END = OP_SET_AE, - - /* Uni */ - OP_UNOP, - OP_NOT = OP_UNOP, - OP_NEG, - OP_FNEG, - - /* Casts */ - OP_TRUNC, - OP_ZEXT, OP_SEXT, - OP_FCVTU, OP_FCVTS, - OP_UCVTF, OP_SCVTF, - OP_FCVTF, - OP_UTPTR, - OP_PTRTU, - OP_PTRCAST, - OP_UNOP_END = OP_PTRCAST, - - /* Select - three input values */ - OP_SEL, - - /* Memory */ - OP_LOAD, - OP_STORE, - OP_SETVAL, - OP_SETFVAL, - OP_SYMADDR, - - /* Other */ - OP_PHI, - OP_PHISOURCE, - OP_INLINED_CALL, - OP_CALL, - OP_SLICE, - OP_NOP, - OP_DEATHNOTE, - OP_ASM, - - /* Sparse tagging (line numbers, context, whatever) */ - OP_CONTEXT, - OP_RANGE, - - /* Needed to translate SSA back to normal form */ - OP_COPY, - - OP_LAST, /* keep this one last! */ -}; - struct basic_block_list; struct instruction_list; @@ -343,6 +228,12 @@ static inline int bb_reachable(struct basic_block *bb) return bb != NULL; } +static inline int lookup_bb(struct basic_block_list *list, struct basic_block *bb) +{ + return lookup_ptr_list_entry((struct ptr_list *)list, bb); +} + + static inline void add_pseudo_user_ptr(struct pseudo_user *user, struct pseudo_user_list **list) { add_ptr_list(list, user); @@ -72,6 +72,7 @@ static void track_instruction_usage(struct basic_block *bb, struct instruction * /* Uni */ case OP_UNOP ... OP_UNOP_END: + case OP_SYMADDR: USES(src1); DEFINES(target); break; @@ -93,10 +94,6 @@ static void track_instruction_usage(struct basic_block *bb, struct instruction * DEFINES(target); break; - case OP_SYMADDR: - USES(symbol); DEFINES(target); - break; - /* Other */ case OP_PHI: /* Phi-nodes are "backwards" nodes. Their def doesn't matter */ @@ -99,7 +99,7 @@ static void simplify_loads(struct basic_block *bb) /* Check for illegal offsets.. */ check_access(insn); - if (insn->type->ctype.modifiers & MOD_VOLATILE) + if (insn->is_volatile) continue; RECURSE_PTR_REVERSE(insn, dom) { @@ -160,7 +160,7 @@ static void kill_dominated_stores(struct basic_block *bb) if (!insn->type) continue; - if (insn->type->ctype.modifiers & MOD_VOLATILE) + if (insn->is_volatile) continue; local = local_pseudo(pseudo); @@ -20,42 +20,19 @@ * THE SOFTWARE. */ -#include "linearize.h" +#include "opcode.h" const struct opcode_table opcode_table[OP_LAST] = { - [OP_SET_EQ] = { .negate = OP_SET_NE, .swap = OP_SET_EQ, .to_float = OP_FCMP_OEQ, }, - [OP_SET_NE] = { .negate = OP_SET_EQ, .swap = OP_SET_NE, .to_float = OP_FCMP_UNE, }, - [OP_SET_LT] = { .negate = OP_SET_GE, .swap = OP_SET_GT, .to_float = OP_FCMP_OLT, }, - [OP_SET_LE] = { .negate = OP_SET_GT, .swap = OP_SET_GE, .to_float = OP_FCMP_OLE, }, - [OP_SET_GE] = { .negate = OP_SET_LT, .swap = OP_SET_LE, .to_float = OP_FCMP_OGE, }, - [OP_SET_GT] = { .negate = OP_SET_LE, .swap = OP_SET_LT, .to_float = OP_FCMP_OGT, }, - [OP_SET_B ] = { .negate = OP_SET_AE, .swap = OP_SET_A , .to_float = OP_FCMP_OLT, }, - [OP_SET_BE] = { .negate = OP_SET_A , .swap = OP_SET_AE, .to_float = OP_FCMP_OLE, }, - [OP_SET_AE] = { .negate = OP_SET_B , .swap = OP_SET_BE, .to_float = OP_FCMP_OGE, }, - [OP_SET_A ] = { .negate = OP_SET_BE, .swap = OP_SET_B , .to_float = OP_FCMP_OGT, }, - - [OP_FCMP_ORD] = { .negate = OP_FCMP_UNO, .swap = OP_FCMP_ORD, }, - [OP_FCMP_UNO] = { .negate = OP_FCMP_ORD, .swap = OP_FCMP_UNO, }, - - [OP_FCMP_OEQ] = { .negate = OP_FCMP_UNE, .swap = OP_FCMP_OEQ, }, - [OP_FCMP_ONE] = { .negate = OP_FCMP_UEQ, .swap = OP_FCMP_ONE, }, - [OP_FCMP_UEQ] = { .negate = OP_FCMP_ONE, .swap = OP_FCMP_UEQ, }, - [OP_FCMP_UNE] = { .negate = OP_FCMP_OEQ, .swap = OP_FCMP_UNE, }, - - [OP_FCMP_OLT] = { .negate = OP_FCMP_UGE, .swap = OP_FCMP_OGT, }, - [OP_FCMP_OLE] = { .negate = OP_FCMP_UGT, .swap = OP_FCMP_OGE, }, - [OP_FCMP_OGE] = { .negate = OP_FCMP_ULT, .swap = OP_FCMP_OLE, }, - [OP_FCMP_OGT] = { .negate = OP_FCMP_ULE, .swap = OP_FCMP_OLT, }, - - [OP_FCMP_ULT] = { .negate = OP_FCMP_OGE, .swap = OP_FCMP_UGT, }, - [OP_FCMP_ULE] = { .negate = OP_FCMP_OGT, .swap = OP_FCMP_UGE, }, - [OP_FCMP_UGE] = { .negate = OP_FCMP_OLT, .swap = OP_FCMP_ULE, }, - [OP_FCMP_UGT] = { .negate = OP_FCMP_OLE, .swap = OP_FCMP_ULT, }, - - [OP_ADD] = { .to_float = OP_FADD, }, - [OP_SUB] = { .to_float = OP_FSUB, }, - [OP_MUL] = { .to_float = OP_FMUL, }, - [OP_DIVS] = { .to_float = OP_FDIV, }, - [OP_DIVU] = { .to_float = OP_FDIV, }, - [OP_NEG] = { .to_float = OP_FNEG, }, +#define OPCODE(OP,NG,SW,TF,N,FL) \ + [OP_##OP] = { \ + .negate = OP_##NG, \ + .swap = OP_##SW, \ + .to_float = OP_##TF, \ + .arity = N, \ + .flags = FL, \ + }, +#define OPCODE_RANGE(OP,S,E) +#include "opcode.def" +#undef OPCODE +#undef OPCODE_RANGE }; diff --git a/opcode.def b/opcode.def new file mode 100644 index 00000000..57d827f4 --- /dev/null +++ b/opcode.def @@ -0,0 +1,114 @@ +// OPCODE negated swaped float arity, flags + +OPCODE(BADOP, BADOP, BADOP, BADOP, 0, OPF_NONE) + +/* Entry */ +OPCODE(ENTRY, BADOP, BADOP, BADOP, 0, OPF_NONE) + +/* Terminator */ +OPCODE(RET, BADOP, BADOP, BADOP, 1, OPF_NONE) +OPCODE(BR, BADOP, BADOP, BADOP, 0, OPF_NONE) +OPCODE(CBR, BADOP, BADOP, BADOP, 1, OPF_NONE) +OPCODE(SWITCH, BADOP, BADOP, BADOP, 1, OPF_NONE) +OPCODE(COMPUTEDGOTO, BADOP, BADOP, BADOP, 1, OPF_NONE) +OPCODE_RANGE(TERMINATOR, RET, COMPUTEDGOTO) + +/* Binary */ +OPCODE(ADD, BADOP, BADOP, FADD, 2, OPF_TARGET) +OPCODE(SUB, BADOP, BADOP, FSUB, 2, OPF_TARGET) +OPCODE(MUL, BADOP, BADOP, FMUL, 2, OPF_TARGET) +OPCODE(DIVU, BADOP, BADOP, FDIV, 2, OPF_TARGET) +OPCODE(DIVS, BADOP, BADOP, FDIV, 2, OPF_TARGET) +OPCODE(MODU, BADOP, BADOP, BADOP, 2, OPF_TARGET) +OPCODE(MODS, BADOP, BADOP, BADOP, 2, OPF_TARGET) +OPCODE(SHL, BADOP, BADOP, BADOP, 2, OPF_TARGET) +OPCODE(LSR, BADOP, BADOP, BADOP, 2, OPF_TARGET) +OPCODE(ASR, BADOP, BADOP, BADOP, 2, OPF_TARGET) + +/* Floating-point binops */ +OPCODE(FADD, BADOP, BADOP, BADOP, 2, OPF_TARGET) +OPCODE(FSUB, BADOP, BADOP, BADOP, 2, OPF_TARGET) +OPCODE(FMUL, BADOP, BADOP, BADOP, 2, OPF_TARGET) +OPCODE(FDIV, BADOP, BADOP, BADOP, 2, OPF_TARGET) + +/* Logical */ +OPCODE(AND_BOOL, BADOP, BADOP, BADOP, 2, OPF_TARGET) +OPCODE(OR_BOOL, BADOP, BADOP, BADOP, 2, OPF_TARGET) +OPCODE(AND, BADOP, BADOP, BADOP, 2, OPF_TARGET) +OPCODE(OR, BADOP, BADOP, BADOP, 2, OPF_TARGET) +OPCODE(XOR, BADOP, BADOP, BADOP, 2, OPF_TARGET) +OPCODE_RANGE(BINARY, ADD, XOR) + +/* floating-point comparison */ +OPCODE(FCMP_ORD, FCMP_UNO, FCMP_ORD, BADOP, 2, OPF_TARGET) +OPCODE(FCMP_OEQ, FCMP_UNE, FCMP_OEQ, BADOP, 2, OPF_TARGET) +OPCODE(FCMP_ONE, FCMP_UEQ, FCMP_ONE, BADOP, 2, OPF_TARGET) +OPCODE(FCMP_UEQ, FCMP_ONE, FCMP_UEQ, BADOP, 2, OPF_TARGET) +OPCODE(FCMP_UNE, FCMP_OEQ, FCMP_UNE, BADOP, 2, OPF_TARGET) +OPCODE(FCMP_OLT, FCMP_UGE, FCMP_OGT, BADOP, 2, OPF_TARGET) +OPCODE(FCMP_OLE, FCMP_UGT, FCMP_OGE, BADOP, 2, OPF_TARGET) +OPCODE(FCMP_OGE, FCMP_ULT, FCMP_OLE, BADOP, 2, OPF_TARGET) +OPCODE(FCMP_OGT, FCMP_ULE, FCMP_OLT, BADOP, 2, OPF_TARGET) +OPCODE(FCMP_ULT, FCMP_OGE, FCMP_UGT, BADOP, 2, OPF_TARGET) +OPCODE(FCMP_ULE, FCMP_OGT, FCMP_UGE, BADOP, 2, OPF_TARGET) +OPCODE(FCMP_UGE, FCMP_OLT, FCMP_ULE, BADOP, 2, OPF_TARGET) +OPCODE(FCMP_UGT, FCMP_OLE, FCMP_ULT, BADOP, 2, OPF_TARGET) +OPCODE(FCMP_UNO, FCMP_ORD, FCMP_UNO, BADOP, 2, OPF_TARGET) +OPCODE_RANGE(FPCMP, FCMP_ORD, FCMP_UNO) + +/* Binary comparison */ +OPCODE(SET_EQ, SET_NE, SET_EQ, FCMP_OEQ, 2, OPF_TARGET) +OPCODE(SET_LT, SET_GE, SET_GT, FCMP_OLT, 2, OPF_TARGET) +OPCODE(SET_LE, SET_GT, SET_GE, FCMP_OLE, 2, OPF_TARGET) +OPCODE(SET_GE, SET_LT, SET_LE, FCMP_OGE, 2, OPF_TARGET) +OPCODE(SET_GT, SET_LE, SET_LT, FCMP_OGT, 2, OPF_TARGET) +OPCODE(SET_B, SET_AE, SET_A, FCMP_OLT, 2, OPF_TARGET) +OPCODE(SET_BE, SET_A, SET_AE, FCMP_OLE, 2, OPF_TARGET) +OPCODE(SET_AE, SET_B, SET_BE, FCMP_OGE, 2, OPF_TARGET) +OPCODE(SET_A, SET_BE, SET_B, FCMP_OGT, 2, OPF_TARGET) +OPCODE(SET_NE, SET_EQ, SET_NE, FCMP_UNE, 2, OPF_TARGET) +OPCODE_RANGE(BINCMP, SET_EQ, SET_NE) + +/* Uni */ +OPCODE(NOT, BADOP, BADOP, BADOP, 1, OPF_TARGET) +OPCODE(NEG, BADOP, BADOP, FNEG, 1, OPF_TARGET) +OPCODE(FNEG, BADOP, BADOP, BADOP, 1, OPF_TARGET) +OPCODE(TRUNC, BADOP, BADOP, BADOP, 1, OPF_TARGET) +OPCODE(ZEXT, BADOP, BADOP, BADOP, 1, OPF_TARGET) +OPCODE(SEXT, BADOP, BADOP, BADOP, 1, OPF_TARGET) +OPCODE(FCVTU, BADOP, BADOP, BADOP, 1, OPF_TARGET) +OPCODE(FCVTS, BADOP, BADOP, BADOP, 1, OPF_TARGET) +OPCODE(UCVTF, BADOP, BADOP, BADOP, 1, OPF_TARGET) +OPCODE(SCVTF, BADOP, BADOP, BADOP, 1, OPF_TARGET) +OPCODE(FCVTF, BADOP, BADOP, BADOP, 1, OPF_TARGET) +OPCODE(UTPTR, BADOP, BADOP, BADOP, 1, OPF_TARGET) +OPCODE(PTRTU, BADOP, BADOP, BADOP, 1, OPF_TARGET) +OPCODE(PTRCAST, BADOP, BADOP, BADOP, 1, OPF_TARGET) +OPCODE_RANGE(UNOP, NOT, PTRCAST) +OPCODE(SYMADDR, BADOP, BADOP, BADOP, 1, OPF_TARGET) +OPCODE(SLICE, BADOP, BADOP, BADOP, 1, OPF_TARGET) + +/* Select - three input values */ +OPCODE(SEL, BADOP, BADOP, BADOP, 3, OPF_TARGET) + +/* Memory */ +OPCODE(LOAD, BADOP, BADOP, BADOP, 1, OPF_TARGET) +OPCODE(STORE, BADOP, BADOP, BADOP, 1, OPF_NONE) + +/* Other */ +OPCODE(PHISOURCE, BADOP, BADOP, BADOP, 1, OPF_TARGET) +OPCODE(PHI, BADOP, BADOP, BADOP, 0, OPF_TARGET) +OPCODE(SETVAL, BADOP, BADOP, BADOP, 0, OPF_TARGET) +OPCODE(SETFVAL, BADOP, BADOP, BADOP, 0, OPF_TARGET) +OPCODE(CALL, BADOP, BADOP, BADOP, 1, OPF_TARGET) +OPCODE(INLINED_CALL, BADOP, BADOP, BADOP, 0, OPF_NONE) +OPCODE(NOP, BADOP, BADOP, BADOP, 0, OPF_NONE) +OPCODE(DEATHNOTE, BADOP, BADOP, BADOP, 0, OPF_NONE) +OPCODE(ASM, BADOP, BADOP, BADOP, 0, OPF_NONE) + +/* Sparse tagging (line numbers, context, whatever) */ +OPCODE(CONTEXT, BADOP, BADOP, BADOP, 0, OPF_NONE) +OPCODE(RANGE, BADOP, BADOP, BADOP, 3, OPF_NONE) + +/* Needed to translate SSA back to normal form */ +OPCODE(COPY, BADOP, BADOP, BADOP, 1, OPF_TARGET) @@ -3,10 +3,23 @@ #include "symbol.h" +enum opcode { +#define OPCODE(OP,NG,SW,TF,N,FL) OP_##OP, +#define OPCODE_RANGE(OP,S,E) OP_##OP = OP_##S, OP_##OP##_END = OP_##E, +#include "opcode.def" +#undef OPCODE +#undef OPCODE_RANGE + OP_LAST, /* keep this one last! */ +}; + extern const struct opcode_table { int negate:8; int swap:8; int to_float:8; + unsigned int arity:2; + unsigned int flags:6; +#define OPF_NONE 0 +#define OPF_TARGET (1 << 0) } opcode_table[]; @@ -91,7 +91,8 @@ static attr_t typedef struct symbol *to_mode_t(struct symbol *); static to_mode_t - to_QI_mode, to_HI_mode, to_SI_mode, to_DI_mode, to_TI_mode, to_word_mode; + to_QI_mode, to_HI_mode, to_SI_mode, to_DI_mode, to_TI_mode; +static to_mode_t to_pointer_mode, to_word_mode; enum { Set_T = 1, @@ -410,6 +411,11 @@ static struct symbol_op mode_TI_op = { .to_mode = to_TI_mode }; +static struct symbol_op mode_pointer_op = { + .type = KW_MODE, + .to_mode = to_pointer_mode +}; + static struct symbol_op mode_word_op = { .type = KW_MODE, .to_mode = to_word_mode @@ -525,9 +531,10 @@ static struct init_keyword { { "bitwise", NS_KEYWORD, MOD_BITWISE, .op = &attr_bitwise_op }, { "__bitwise__",NS_KEYWORD, MOD_BITWISE, .op = &attr_bitwise_op }, { "address_space",NS_KEYWORD, .op = &address_space_op }, - { "mode", NS_KEYWORD, .op = &mode_op }, { "context", NS_KEYWORD, .op = &context_op }, { "designated_init", NS_KEYWORD, .op = &designated_init_op }, + { "__designated_init__", NS_KEYWORD, .op = &designated_init_op }, + { "transparent_union", NS_KEYWORD, .op = &transparent_union_op }, { "__transparent_union__", NS_KEYWORD, .op = &transparent_union_op }, { "noreturn", NS_KEYWORD, MOD_NORETURN, .op = &attr_mod_op }, { "__noreturn__", NS_KEYWORD, MOD_NORETURN, .op = &attr_mod_op }, @@ -537,19 +544,24 @@ static struct init_keyword { {"__const", NS_KEYWORD, MOD_PURE, .op = &attr_mod_op }, {"__const__", NS_KEYWORD, MOD_PURE, .op = &attr_mod_op }, + { "mode", NS_KEYWORD, .op = &mode_op }, { "__mode__", NS_KEYWORD, .op = &mode_op }, - { "QI", NS_KEYWORD, MOD_CHAR, .op = &mode_QI_op }, - { "__QI__", NS_KEYWORD, MOD_CHAR, .op = &mode_QI_op }, - { "HI", NS_KEYWORD, MOD_SHORT, .op = &mode_HI_op }, - { "__HI__", NS_KEYWORD, MOD_SHORT, .op = &mode_HI_op }, - { "SI", NS_KEYWORD, .op = &mode_SI_op }, - { "__SI__", NS_KEYWORD, .op = &mode_SI_op }, - { "DI", NS_KEYWORD, MOD_LONGLONG, .op = &mode_DI_op }, - { "__DI__", NS_KEYWORD, MOD_LONGLONG, .op = &mode_DI_op }, - { "TI", NS_KEYWORD, MOD_LONGLONGLONG, .op = &mode_TI_op }, - { "__TI__", NS_KEYWORD, MOD_LONGLONGLONG, .op = &mode_TI_op }, - { "word", NS_KEYWORD, MOD_LONG, .op = &mode_word_op }, - { "__word__", NS_KEYWORD, MOD_LONG, .op = &mode_word_op }, + { "QI", NS_KEYWORD, .op = &mode_QI_op }, + { "__QI__", NS_KEYWORD, .op = &mode_QI_op }, + { "HI", NS_KEYWORD, .op = &mode_HI_op }, + { "__HI__", NS_KEYWORD, .op = &mode_HI_op }, + { "SI", NS_KEYWORD, .op = &mode_SI_op }, + { "__SI__", NS_KEYWORD, .op = &mode_SI_op }, + { "DI", NS_KEYWORD, .op = &mode_DI_op }, + { "__DI__", NS_KEYWORD, .op = &mode_DI_op }, + { "TI", NS_KEYWORD, .op = &mode_TI_op }, + { "__TI__", NS_KEYWORD, .op = &mode_TI_op }, + { "byte", NS_KEYWORD, .op = &mode_QI_op }, + { "__byte__", NS_KEYWORD, .op = &mode_QI_op }, + { "pointer", NS_KEYWORD, .op = &mode_pointer_op }, + { "__pointer__",NS_KEYWORD, .op = &mode_pointer_op }, + { "word", NS_KEYWORD, .op = &mode_word_op }, + { "__word__", NS_KEYWORD, .op = &mode_word_op }, }; @@ -1105,6 +1117,14 @@ static struct symbol *to_TI_mode(struct symbol *ctype) : &slllong_ctype; } +static struct symbol *to_pointer_mode(struct symbol *ctype) +{ + if (ctype->ctype.base_type != &int_type) + return NULL; + return ctype->ctype.modifiers & MOD_UNSIGNED ? uintptr_ctype + : intptr_ctype; +} + static struct symbol *to_word_mode(struct symbol *ctype) { if (ctype->ctype.base_type != &int_type) @@ -1121,7 +1141,7 @@ static struct token *attribute_mode(struct token *token, struct symbol *attr, st if (mode && mode->op->type == KW_MODE) ctx->mode = mode->op; else - sparse_error(token->pos, "unknown mode attribute %s\n", show_ident(token->ident)); + sparse_error(token->pos, "unknown mode attribute %s", show_ident(token->ident)); token = token->next; } else sparse_error(token->pos, "expect attribute mode symbol\n"); diff --git a/pre-process.c b/pre-process.c index da4b7acd..bf4b8e76 100644 --- a/pre-process.c +++ b/pre-process.c @@ -165,6 +165,12 @@ static void replace_with_has_builtin(struct token *token) replace_with_bool(token, sym && sym->builtin); } +static void replace_with_has_attribute(struct token *token) +{ + struct symbol *sym = lookup_symbol(token->ident, NS_KEYWORD); + replace_with_bool(token, sym && sym->op && sym->op->attribute); +} + static void expand_line(struct token *token) { replace_with_integer(token, token->pos.line); @@ -1592,6 +1598,10 @@ static int expression_value(struct token **where) state = 4; beginning = list; break; + } else if (p->ident == &__has_attribute_ident) { + state = 6; + beginning = list; + break; } if (!expand_one_symbol(list)) continue; @@ -1623,29 +1633,34 @@ static int expression_value(struct token **where) *list = p->next; continue; - // __has_builtin(xyz) - case 4: + // __has_builtin(x) or __has_attribute(x) + case 4: case 6: if (match_op(p, '(')) { - state = 5; + state++; } else { - sparse_error(p->pos, "missing '(' after \"__has_builtin\""); + sparse_error(p->pos, "missing '(' after \"__has_%s\"", + state == 4 ? "builtin" : "attribute"); state = 0; } *beginning = p; break; - case 5: + case 5: case 7: if (token_type(p) != TOKEN_IDENT) { sparse_error(p->pos, "identifier expected"); state = 0; break; } if (!match_op(p->next, ')')) - sparse_error(p->pos, "missing ')' after \"__has_builtin\""); - state = 6; - replace_with_has_builtin(p); + sparse_error(p->pos, "missing ')' after \"__has_%s\"", + state == 5 ? "builtin" : "attribute"); + if (state == 5) + replace_with_has_builtin(p); + else + replace_with_has_attribute(p); + state = 8; *beginning = p; break; - case 6: + case 8: state = 0; *list = p->next; continue; @@ -337,7 +337,7 @@ int kill_insn(struct instruction *insn, int force) break; case OP_SYMADDR: - kill_use(&insn->symbol); + kill_use(&insn->src); repeat_phase |= REPEAT_SYMBOL_CLEANUP; break; @@ -361,7 +361,7 @@ int kill_insn(struct instruction *insn, int force) break; case OP_LOAD: - if (!force && insn->type->ctype.modifiers & MOD_VOLATILE) + if (!force && insn->is_volatile) return 0; kill_use(&insn->src); break; @@ -401,6 +401,28 @@ static int dead_insn(struct instruction *insn, pseudo_t *src1, pseudo_t *src2, p return REPEAT_CSE; } +static inline bool has_target(struct instruction *insn) +{ + return opcode_table[insn->opcode].flags & OPF_TARGET; +} + +void remove_dead_insns(struct entrypoint *ep) +{ + struct basic_block *bb; + + FOR_EACH_PTR_REVERSE(ep->bbs, bb) { + struct instruction *insn; + FOR_EACH_PTR_REVERSE(bb->insns, insn) { + if (!insn->bb) + continue; + if (!has_target(insn)) + continue; + if (!has_users(insn->target)) + kill_instruction(insn); + } END_FOR_EACH_PTR_REVERSE(insn); + } END_FOR_EACH_PTR_REVERSE(bb); +} + static inline int constant(pseudo_t pseudo) { return pseudo->type == PSEUDO_VAL; @@ -1729,9 +1751,9 @@ int simplify_instruction(struct instruction *insn) case OP_STORE: return simplify_memop(insn); case OP_SYMADDR: - if (dead_insn(insn, &insn->symbol, NULL, NULL)) + if (dead_insn(insn, &insn->src, NULL, NULL)) return REPEAT_CSE | REPEAT_SYMBOL_CLEANUP; - return replace_with_pseudo(insn, insn->symbol); + return replace_with_pseudo(insn, insn->src); case OP_SEXT: case OP_ZEXT: case OP_TRUNC: return simplify_cast(insn); @@ -77,6 +77,15 @@ Sparse issues these warnings by default. To turn them off, use \fB\-Wno\-bitwise\fR. . .TP +.B \-Wcast\-from\-as +Warn about which remove an address space to a pointer type. + +This is similar to \fB\-Waddress\-space\fR but will also warn +on casts to \fBunsigned long\fR. + +Sparse does not issues these warnings by default. +. +.TP .B \-Wcast\-to\-as Warn about casts which add an address space to a pointer type. @@ -315,7 +315,7 @@ static void check_symbols(struct symbol_list *list) expand_symbol(sym); ep = linearize_symbol(sym); - if (ep) { + if (ep && ep->entry) { if (dbg_entry) show_entry(ep); @@ -5,6 +5,7 @@ // #include <assert.h> +#include "ssa.h" #include "lib.h" #include "sset.h" #include "dominate.h" @@ -1,6 +1,8 @@ #ifndef SSA_H #define SSA_H +struct entrypoint; + void ssa_convert(struct entrypoint *ep); #endif diff --git a/validation/Waddress-space-strict.c b/validation/Waddress-space-strict.c new file mode 100644 index 00000000..5071aab2 --- /dev/null +++ b/validation/Waddress-space-strict.c @@ -0,0 +1,56 @@ +#define __user __attribute__((address_space(1))) + +typedef unsigned long ulong; +typedef long long llong; +typedef struct s obj_t; + +static void expl(int i, ulong u, llong l, void *v, obj_t *o, obj_t __user *p) +{ + (obj_t*)(i); + (obj_t __user*)(i); + + (obj_t*)(u); + (obj_t __user*)(u); + + (obj_t*)(l); + (obj_t __user*)(l); + + (obj_t*)(v); + (obj_t __user*)(v); + + (int)(o); + (ulong)(o); + (llong)(o); + (void *)(o); + (obj_t*)(o); + (obj_t __user*)(o); + + (int)(p); // w + (ulong)(p); // w! + (llong)(p); // w + (void *)(p); // w + (obj_t*)(p); // w + (obj_t __user*)(p); // ok +} + +/* + * check-name: Waddress-space-strict + * check-command: sparse -Wcast-from-as -Wcast-to-as $file + * + * check-error-start +Waddress-space-strict.c:10:10: warning: cast adds address space to expression (<asn:1>) +Waddress-space-strict.c:13:10: warning: cast adds address space to expression (<asn:1>) +Waddress-space-strict.c:16:10: warning: cast adds address space to expression (<asn:1>) +Waddress-space-strict.c:19:10: warning: cast adds address space to expression (<asn:1>) +Waddress-space-strict.c:26:10: warning: cast adds address space to expression (<asn:1>) +Waddress-space-strict.c:28:10: warning: cast removes address space of expression +Waddress-space-strict.c:29:10: warning: cast removes address space of expression +Waddress-space-strict.c:30:10: warning: cast removes address space of expression +Waddress-space-strict.c:31:10: warning: cast removes address space of expression +Waddress-space-strict.c:32:10: warning: cast removes address space of expression +Waddress-space-strict.c:9:18: warning: non size-preserving integer to pointer cast +Waddress-space-strict.c:10:25: warning: non size-preserving integer to pointer cast +Waddress-space-strict.c:21:15: warning: non size-preserving pointer to integer cast +Waddress-space-strict.c:28:15: warning: non size-preserving pointer to integer cast + * check-error-end + */ diff --git a/validation/enum+mode.c b/validation/enum+mode.c new file mode 100644 index 00000000..182af189 --- /dev/null +++ b/validation/enum+mode.c @@ -0,0 +1,18 @@ +enum e { ZERO, ONE, TWO }; + +struct s { + enum e __attribute__ ((mode(__byte__))) b; + enum e __attribute__ ((mode(__word__))) w; + enum e __attribute__ ((mode(__TI__))) t; +}; + +static struct s s; + +_Static_assert(sizeof(s.b) == 1, ""); +_Static_assert(sizeof(s.w) == sizeof(long), ""); +_Static_assert(sizeof(s.t) == sizeof(long long), ""); + +/* + * check-name: enum+mode + * check-known-to-fail + */ diff --git a/validation/asm-toplevel.c b/validation/linear/asm-toplevel.c index 8bdd7fc1..8bdd7fc1 100644 --- a/validation/asm-toplevel.c +++ b/validation/linear/asm-toplevel.c diff --git a/validation/linear/logical-phi0.c b/validation/linear/logical-phi0.c new file mode 100644 index 00000000..96a47dba --- /dev/null +++ b/validation/linear/logical-phi0.c @@ -0,0 +1,48 @@ +int a(void); +int b(void); +int c(void); + +static int laa(void) +{ + return (a() && b()) && c(); +} + +static int lao(void) +{ + return (a() && b()) || c(); +} + +static int loa(void) +{ + return (a() || b()) && c(); +} + +static int loo(void) +{ + return (a() || b()) || c(); +} + +static int raa(void) +{ + return a() && (b() && c()); +} + +static int rao(void) +{ + return a() && (b() || c()); +} + +static int roa(void) +{ + return a() || (b() && c()); +} + +static int roo(void) +{ + return a() || (b() || c()); +} + +/* + * check-name: bad-logical-phi0 + * check-command: sparse -vir -flinearize=last $file + */ diff --git a/validation/linear/logical.c b/validation/linear/logical.c index 0f502c6b..b190f608 100644 --- a/validation/linear/logical.c +++ b/validation/linear/logical.c @@ -26,24 +26,24 @@ os: <entry-point> store.32 %arg1 -> 0[i] store.64 %arg2 -> 0[b] + load.32 %r2 <- 0[i] + setne.1 %r3 <- %r2, $0 phisrc.32 %phi1 <- $1 - load.32 %r1 <- 0[i] - setne.1 %r2 <- %r1, $0 - cbr %r2, .L3, .L2 + cbr %r3, .L3, .L2 .L2: - load.64 %r3 <- 0[b] - load.32 %r4 <- 0[%r3] - lsr.32 %r5 <- %r4, $1 - trunc.2 %r6 <- (32) %r5 - setne.1 %r7 <- %r6, $0 - zext.32 %r8 <- (1) %r7 - phisrc.32 %phi2 <- %r8 + load.64 %r4 <- 0[b] + load.32 %r5 <- 0[%r4] + lsr.32 %r6 <- %r5, $1 + trunc.2 %r7 <- (32) %r6 + setne.1 %r8 <- %r7, $0 + zext.32 %r9 <- (1) %r8 + phisrc.32 %phi2 <- %r9 br .L3 .L3: - phi.32 %r9 <- %phi1, %phi2 - phisrc.32 %phi3(return) <- %r9 + phi.32 %r1 <- %phi1, %phi2 + phisrc.32 %phi3(return) <- %r1 br .L1 .L1: @@ -56,24 +56,24 @@ ou: <entry-point> store.32 %arg1 -> 0[i] store.64 %arg2 -> 0[b] + load.32 %r12 <- 0[i] + setne.1 %r13 <- %r12, $0 phisrc.32 %phi4 <- $1 - load.32 %r11 <- 0[i] - setne.1 %r12 <- %r11, $0 - cbr %r12, .L7, .L6 + cbr %r13, .L7, .L6 .L6: - load.64 %r13 <- 0[b] - load.32 %r14 <- 0[%r13] - lsr.32 %r15 <- %r14, $3 - trunc.3 %r16 <- (32) %r15 - setne.1 %r17 <- %r16, $0 - zext.32 %r18 <- (1) %r17 - phisrc.32 %phi5 <- %r18 + load.64 %r14 <- 0[b] + load.32 %r15 <- 0[%r14] + lsr.32 %r16 <- %r15, $3 + trunc.3 %r17 <- (32) %r16 + setne.1 %r18 <- %r17, $0 + zext.32 %r19 <- (1) %r18 + phisrc.32 %phi5 <- %r19 br .L7 .L7: - phi.32 %r19 <- %phi4, %phi5 - phisrc.32 %phi6(return) <- %r19 + phi.32 %r11 <- %phi4, %phi5 + phisrc.32 %phi6(return) <- %r11 br .L5 .L5: @@ -86,22 +86,22 @@ ol: <entry-point> store.32 %arg1 -> 0[i] store.64 %arg2 -> 0[b] + load.32 %r22 <- 0[i] + setne.1 %r23 <- %r22, $0 phisrc.32 %phi7 <- $1 - load.32 %r21 <- 0[i] - setne.1 %r22 <- %r21, $0 - cbr %r22, .L11, .L10 + cbr %r23, .L11, .L10 .L10: - load.64 %r23 <- 0[b] - load.64 %r24 <- 8[%r23] - setne.1 %r25 <- %r24, $0 - zext.32 %r26 <- (1) %r25 - phisrc.32 %phi8 <- %r26 + load.64 %r24 <- 0[b] + load.64 %r25 <- 8[%r24] + setne.1 %r26 <- %r25, $0 + zext.32 %r27 <- (1) %r26 + phisrc.32 %phi8 <- %r27 br .L11 .L11: - phi.32 %r27 <- %phi7, %phi8 - phisrc.32 %phi9(return) <- %r27 + phi.32 %r21 <- %phi7, %phi8 + phisrc.32 %phi9(return) <- %r21 br .L9 .L9: @@ -114,23 +114,23 @@ od: <entry-point> store.32 %arg1 -> 0[i] store.64 %arg2 -> 0[b] + load.32 %r30 <- 0[i] + setne.1 %r31 <- %r30, $0 phisrc.32 %phi10 <- $1 - load.32 %r29 <- 0[i] - setne.1 %r30 <- %r29, $0 - cbr %r30, .L15, .L14 + cbr %r31, .L15, .L14 .L14: - load.64 %r31 <- 0[b] - load.64 %r32 <- 16[%r31] - setfval.64 %r33 <- 0.000000e+00 - fcmpune.1 %r34 <- %r32, %r33 - zext.32 %r35 <- (1) %r34 - phisrc.32 %phi11 <- %r35 + load.64 %r32 <- 0[b] + load.64 %r33 <- 16[%r32] + setfval.64 %r34 <- 0.000000e+00 + fcmpune.1 %r35 <- %r33, %r34 + zext.32 %r36 <- (1) %r35 + phisrc.32 %phi11 <- %r36 br .L15 .L15: - phi.32 %r36 <- %phi10, %phi11 - phisrc.32 %phi12(return) <- %r36 + phi.32 %r29 <- %phi10, %phi11 + phisrc.32 %phi12(return) <- %r29 br .L13 .L13: @@ -143,24 +143,24 @@ as: <entry-point> store.32 %arg1 -> 0[i] store.64 %arg2 -> 0[b] + load.32 %r39 <- 0[i] + setne.1 %r40 <- %r39, $0 phisrc.32 %phi13 <- $0 - load.32 %r38 <- 0[i] - setne.1 %r39 <- %r38, $0 - cbr %r39, .L18, .L19 + cbr %r40, .L18, .L19 .L18: - load.64 %r40 <- 0[b] - load.32 %r41 <- 0[%r40] - lsr.32 %r42 <- %r41, $1 - trunc.2 %r43 <- (32) %r42 - setne.1 %r44 <- %r43, $0 - zext.32 %r45 <- (1) %r44 - phisrc.32 %phi14 <- %r45 + load.64 %r41 <- 0[b] + load.32 %r42 <- 0[%r41] + lsr.32 %r43 <- %r42, $1 + trunc.2 %r44 <- (32) %r43 + setne.1 %r45 <- %r44, $0 + zext.32 %r46 <- (1) %r45 + phisrc.32 %phi14 <- %r46 br .L19 .L19: - phi.32 %r46 <- %phi14, %phi13 - phisrc.32 %phi15(return) <- %r46 + phi.32 %r38 <- %phi13, %phi14 + phisrc.32 %phi15(return) <- %r38 br .L17 .L17: @@ -173,24 +173,24 @@ au: <entry-point> store.32 %arg1 -> 0[i] store.64 %arg2 -> 0[b] + load.32 %r49 <- 0[i] + setne.1 %r50 <- %r49, $0 phisrc.32 %phi16 <- $0 - load.32 %r48 <- 0[i] - setne.1 %r49 <- %r48, $0 - cbr %r49, .L22, .L23 + cbr %r50, .L22, .L23 .L22: - load.64 %r50 <- 0[b] - load.32 %r51 <- 0[%r50] - lsr.32 %r52 <- %r51, $3 - trunc.3 %r53 <- (32) %r52 - setne.1 %r54 <- %r53, $0 - zext.32 %r55 <- (1) %r54 - phisrc.32 %phi17 <- %r55 + load.64 %r51 <- 0[b] + load.32 %r52 <- 0[%r51] + lsr.32 %r53 <- %r52, $3 + trunc.3 %r54 <- (32) %r53 + setne.1 %r55 <- %r54, $0 + zext.32 %r56 <- (1) %r55 + phisrc.32 %phi17 <- %r56 br .L23 .L23: - phi.32 %r56 <- %phi17, %phi16 - phisrc.32 %phi18(return) <- %r56 + phi.32 %r48 <- %phi16, %phi17 + phisrc.32 %phi18(return) <- %r48 br .L21 .L21: @@ -203,22 +203,22 @@ al: <entry-point> store.32 %arg1 -> 0[i] store.64 %arg2 -> 0[b] + load.32 %r59 <- 0[i] + setne.1 %r60 <- %r59, $0 phisrc.32 %phi19 <- $0 - load.32 %r58 <- 0[i] - setne.1 %r59 <- %r58, $0 - cbr %r59, .L26, .L27 + cbr %r60, .L26, .L27 .L26: - load.64 %r60 <- 0[b] - load.64 %r61 <- 8[%r60] - setne.1 %r62 <- %r61, $0 - zext.32 %r63 <- (1) %r62 - phisrc.32 %phi20 <- %r63 + load.64 %r61 <- 0[b] + load.64 %r62 <- 8[%r61] + setne.1 %r63 <- %r62, $0 + zext.32 %r64 <- (1) %r63 + phisrc.32 %phi20 <- %r64 br .L27 .L27: - phi.32 %r64 <- %phi20, %phi19 - phisrc.32 %phi21(return) <- %r64 + phi.32 %r58 <- %phi19, %phi20 + phisrc.32 %phi21(return) <- %r58 br .L25 .L25: @@ -231,23 +231,23 @@ ad: <entry-point> store.32 %arg1 -> 0[i] store.64 %arg2 -> 0[b] + load.32 %r67 <- 0[i] + setne.1 %r68 <- %r67, $0 phisrc.32 %phi22 <- $0 - load.32 %r66 <- 0[i] - setne.1 %r67 <- %r66, $0 - cbr %r67, .L30, .L31 + cbr %r68, .L30, .L31 .L30: - load.64 %r68 <- 0[b] - load.64 %r69 <- 16[%r68] - setfval.64 %r70 <- 0.000000e+00 - fcmpune.1 %r71 <- %r69, %r70 - zext.32 %r72 <- (1) %r71 - phisrc.32 %phi23 <- %r72 + load.64 %r69 <- 0[b] + load.64 %r70 <- 16[%r69] + setfval.64 %r71 <- 0.000000e+00 + fcmpune.1 %r72 <- %r70, %r71 + zext.32 %r73 <- (1) %r72 + phisrc.32 %phi23 <- %r73 br .L31 .L31: - phi.32 %r73 <- %phi23, %phi22 - phisrc.32 %phi24(return) <- %r73 + phi.32 %r66 <- %phi22, %phi23 + phisrc.32 %phi24(return) <- %r66 br .L29 .L29: diff --git a/validation/linear/missing-return0.c b/validation/linear/missing-return0.c new file mode 100644 index 00000000..77ab5abd --- /dev/null +++ b/validation/linear/missing-return0.c @@ -0,0 +1,10 @@ +static int foo(int a) +{ + if (a) + return 1; +} + +/* + * check-name: missing-return0 + * check-command: sparse -vir -flinearize=last $file + */ diff --git a/validation/linear/missing-return1.c b/validation/linear/missing-return1.c new file mode 100644 index 00000000..4a8a9517 --- /dev/null +++ b/validation/linear/missing-return1.c @@ -0,0 +1,15 @@ +static inline int fun(int a) +{ + if (a) + return 1; +} + +static int foo(int a) +{ + return fun(a); +} + +/* + * check-name: missing-return1 + * check-command: sparse -vir -flinearize=last $file + */ diff --git a/validation/linear/missing-return2.c b/validation/linear/missing-return2.c new file mode 100644 index 00000000..395dcc14 --- /dev/null +++ b/validation/linear/missing-return2.c @@ -0,0 +1,11 @@ +static int foo(int a) +{ + switch (a) + case 3: + return 4; +} + +/* + * check-name: missing-return2 + * check-command: sparse -vir -flinearize=last $file + */ diff --git a/validation/linear/missing-return3.c b/validation/linear/missing-return3.c new file mode 100644 index 00000000..b32e5eea --- /dev/null +++ b/validation/linear/missing-return3.c @@ -0,0 +1,18 @@ +static int foo(int a) +{ + if (a) + return; +} + +static void ref(void) +{ +} + +/* + * check-name: missing-return3 + * check-command: sparse -vir -flinearize=last $file + * + * check-error-start +linear/missing-return3.c:4:17: error: return with no return value + * check-error-end + */ diff --git a/validation/linear/missing-return4.c b/validation/linear/missing-return4.c new file mode 100644 index 00000000..779893a0 --- /dev/null +++ b/validation/linear/missing-return4.c @@ -0,0 +1,14 @@ +static int foo(int a) +{ + int r = a; + r; +} + +/* + * check-name: missing-return4 + * check-command: test-linearize -Wno-decl $file + * + * check-error-ignore + * check-output-ignore + * check-output-contains: ret\\..*UNDEF + */ diff --git a/validation/linear/missing-return5.c b/validation/linear/missing-return5.c new file mode 100644 index 00000000..e5504a19 --- /dev/null +++ b/validation/linear/missing-return5.c @@ -0,0 +1,23 @@ +int foo(int p) +{ + if (p) + return 0; +} + +int bar(int p) +{ + if (p) + return 0; + p++; +} + +/* + * check-name: missing/undef return + * check-command: test-linearize -Wno-decl -fdump-ir=linearize $file + * + * check-output-ignore + * check-output-pattern(2): phi\\..*,.* + * check-output-pattern(2): phisrc\\..*\\$0 + * check-output-pattern(2): phisrc\\..*UNDEF + * check-output-excludes: ret\\..*\\$0 + */ diff --git a/validation/linear/phi-order01.c b/validation/linear/phi-order01.c new file mode 100644 index 00000000..0c4004fe --- /dev/null +++ b/validation/linear/phi-order01.c @@ -0,0 +1,16 @@ +int fun(void); + +static int foo(int a) +{ + return a && fun(); +} + +static int bar(int a) +{ + return a || fun(); +} + +/* + * check-name: phi-order01 + * check-command: sparse -vir -flinearize=last $file + */ diff --git a/validation/linear/phi-order02.c b/validation/linear/phi-order02.c new file mode 100644 index 00000000..d217ae45 --- /dev/null +++ b/validation/linear/phi-order02.c @@ -0,0 +1,16 @@ +int fun(void); + +static int foo(int a) { return 0 || fun(); } +static int bar(int a) { return 1 || fun(); } +static int baz(int a) { return 0 && fun(); } +static int qux(int a) { return 1 && fun(); } + +static int oof(int a) { return fun() || 1; } +static int rab(int a) { return fun() || 0; } +static int zab(int a) { return fun() && 1; } +static int xuq(int a) { return fun() && 0; } + +/* + * check-name: phi-order02 + * check-command: sparse -vir -flinearize=last $file + */ diff --git a/validation/linear/phi-order03.c b/validation/linear/phi-order03.c new file mode 100644 index 00000000..24ae10e7 --- /dev/null +++ b/validation/linear/phi-order03.c @@ -0,0 +1,8 @@ +int fun(void); + +static int foo(void) { return ((0 || fun()) && fun()); } + +/* + * check-name: phi-order03 + * check-command: sparse -vir -flinearize=last $file + */ diff --git a/validation/linear/phi-order04.c b/validation/linear/phi-order04.c new file mode 100644 index 00000000..7548537a --- /dev/null +++ b/validation/linear/phi-order04.c @@ -0,0 +1,12 @@ +static void foo(int *b) +{ + if (1) { + int c; + b = &c; + } +} + +/* + * check-name: phi-order04 + * check-command: sparse -vir -flinearize=last $file + */ diff --git a/validation/linear/unreachable-label0.c b/validation/linear/unreachable-label0.c new file mode 100644 index 00000000..695e5cb0 --- /dev/null +++ b/validation/linear/unreachable-label0.c @@ -0,0 +1,19 @@ +static int foo(int a) +{ + goto label; + switch(a) { + default: +label: + break; + } + return 0; +} + +/* + * check-name: unreachable-label0 + * check-command: test-linearize $file + * + * check-output-ignore + * check-output-contains: ret\\. + * check-output-excludes: END + */ diff --git a/validation/optim/volatile-bitfield.c b/validation/optim/volatile-bitfield.c new file mode 100644 index 00000000..99db4401 --- /dev/null +++ b/validation/optim/volatile-bitfield.c @@ -0,0 +1,16 @@ +struct s { + int f:3; +}; + +void foo(volatile struct s *p) +{ + p->f; +} + +/* + * check-name: volatile-bitfield + * check-command: test-linearize -Wno-decl $file + * + * check-output-ignore + * check-output-contains: load\\. + */ diff --git a/validation/preprocessor/has-attribute.c b/validation/preprocessor/has-attribute.c new file mode 100644 index 00000000..3149cbfa --- /dev/null +++ b/validation/preprocessor/has-attribute.c @@ -0,0 +1,56 @@ +#ifndef __has_attribute +__has_attribute()??? Quesako? +#define __has_attribute(x) 0 +#else +"has __has_attribute(), yeah!" +#endif + +123 __has_attribute(nothinx) def + +#if __has_attribute(nothinx) +#error "not a attribute!" +#endif + +#if 1 \ + && __has_attribute(packed) \ + && __has_attribute(aligned) \ + && __has_attribute(const) \ + && __has_attribute(pure) \ + && __has_attribute(noreturn) \ + && __has_attribute(designated_init) \ + && __has_attribute(transparent_union) \ + +"ok gcc" +#endif + +#if 1 \ + && __has_attribute(fastcall) \ + +"ok gcc ignore" +#endif + +#if 1 \ + && __has_attribute(nocast) \ + && __has_attribute(noderef) \ + && __has_attribute(safe) \ + && __has_attribute(force) \ + && __has_attribute(bitwise) \ + && __has_attribute(address_space) \ + && __has_attribute(context) \ + +"ok sparse specific" +#endif + +/* + * check-name: has-attribute + * check-command: sparse -E $file + * + * check-output-start + +"has __has_attribute(), yeah!" +123 0 def +"ok gcc" +"ok gcc ignore" +"ok sparse specific" + * check-output-end + */ |
