diff options
| -rw-r--r-- | allocate.c | 2 | ||||
| -rw-r--r-- | allocate.h | 3 | ||||
| -rw-r--r-- | compile-i386.c | 2 | ||||
| -rw-r--r-- | evaluate.c | 84 | ||||
| -rw-r--r-- | expand.c | 7 | ||||
| -rw-r--r-- | expression.h | 7 | ||||
| -rw-r--r-- | flow.c | 7 | ||||
| -rw-r--r-- | gdbhelpers | 12 | ||||
| -rw-r--r-- | ident-list.h | 2 | ||||
| -rw-r--r-- | inline.c | 19 | ||||
| -rw-r--r-- | lib.c | 1 | ||||
| -rw-r--r-- | linearize.c | 42 | ||||
| -rw-r--r-- | linearize.h | 2 | ||||
| -rw-r--r-- | memops.c | 6 | ||||
| -rw-r--r-- | parse.c | 45 | ||||
| -rw-r--r-- | ptrlist.h | 2 | ||||
| -rw-r--r-- | scope.h | 1 | ||||
| -rw-r--r-- | show-parse.c | 9 | ||||
| -rw-r--r-- | simplify.c | 4 | ||||
| -rw-r--r-- | symbol.c | 4 | ||||
| -rw-r--r-- | symbol.h | 86 | ||||
| -rw-r--r-- | validation/c11-atomic.c | 93 | ||||
| -rw-r--r-- | validation/cast-kinds.c | 12 | ||||
| -rw-r--r-- | validation/fp2i-cast.c | 30 | ||||
| -rw-r--r-- | validation/memops-volatile.c | 15 | ||||
| -rw-r--r-- | validation/optim/restrict.c | 73 | ||||
| -rw-r--r-- | validation/optim/volatile-side-effect.c | 13 | ||||
| -rw-r--r-- | validation/reload-aliasing.c | 41 | ||||
| -rw-r--r-- | validation/restrict.c | 93 | ||||
| -rw-r--r-- | validation/typeof-mods.c | 28 |
30 files changed, 552 insertions, 193 deletions
@@ -120,7 +120,7 @@ void *allocate(struct allocator_struct *desc, unsigned int size) void show_allocations(struct allocator_struct *x) { - fprintf(stderr, "%s: %d allocations, %d bytes (%d total bytes, " + fprintf(stderr, "%s: %d allocations, %lu bytes (%lu total bytes, " "%6.2f%% usage, %6.2f average size)\n", x->name, x->allocations, x->useful_bytes, x->total_bytes, 100 * (double) x->useful_bytes / x->total_bytes, @@ -14,7 +14,8 @@ struct allocator_struct { unsigned int chunking; void *freelist; /* statistics */ - unsigned int allocations, total_bytes, useful_bytes; + unsigned int allocations; + unsigned long total_bytes, useful_bytes; }; struct allocator_stats { diff --git a/compile-i386.c b/compile-i386.c index 1242d384..7b7ace92 100644 --- a/compile-i386.c +++ b/compile-i386.c @@ -2236,7 +2236,7 @@ static struct storage *x86_symbol_expr(struct symbol *sym) return new; } if (sym->ctype.modifiers & MOD_ADDRESSABLE) { - printf("\taddi.%d\t\tv%d,vFP,$%lld\n", bits_in_pointer, new->pseudo, sym->value); + printf("\taddi.%d\t\tv%d,vFP,$%lld\n", bits_in_pointer, new->pseudo, 0LL); return new; } printf("\taddi.%d\t\tv%d,vFP,$offsetof(%s:%p)\n", bits_in_pointer, new->pseudo, show_ident(sym->ident), sym); @@ -638,7 +638,7 @@ static struct symbol *evaluate_ptr_add(struct expression *expr, struct symbol *i static void examine_fn_arguments(struct symbol *fn); -#define MOD_IGN (MOD_VOLATILE | MOD_CONST | MOD_PURE) +#define MOD_IGN (MOD_QUALIFIER | MOD_PURE) const char *type_difference(struct ctype *c1, struct ctype *c2, unsigned long mod1, unsigned long mod2) @@ -3258,6 +3258,9 @@ struct symbol *evaluate_expression(struct expression *expr) case EXPR_SLICE: expression_error(expr, "internal front-end error: SLICE re-evaluated"); return NULL; + case EXPR_ASM_OPERAND: + expression_error(expr, "internal front-end error: ASM_OPERAND evaluated"); + return NULL; } return NULL; } @@ -3420,8 +3423,8 @@ static void verify_input_constraint(struct expression *expr, const char *constra static void evaluate_asm_statement(struct statement *stmt) { struct expression *expr; + struct expression *op; struct symbol *sym; - int state; expr = stmt->asm_string; if (!expr || expr->type != EXPR_STRING) { @@ -3429,58 +3432,41 @@ static void evaluate_asm_statement(struct statement *stmt) return; } - state = 0; - FOR_EACH_PTR(stmt->asm_outputs, expr) { - switch (state) { - case 0: /* Identifier */ - state = 1; - continue; + FOR_EACH_PTR(stmt->asm_outputs, op) { + /* Identifier */ - case 1: /* Constraint */ - state = 2; - if (!expr || expr->type != EXPR_STRING) { - sparse_error(expr ? expr->pos : stmt->pos, "asm output constraint is not a string"); - *THIS_ADDRESS(expr) = NULL; - continue; - } + /* Constraint */ + expr = op->constraint; + if (!expr || expr->type != EXPR_STRING) { + sparse_error(expr ? expr->pos : stmt->pos, "asm output constraint is not a string"); + op->constraint = NULL; + } else verify_output_constraint(expr, expr->string->data); - continue; - case 2: /* Expression */ - state = 0; - if (!evaluate_expression(expr)) - return; - if (!lvalue_expression(expr)) - warning(expr->pos, "asm output is not an lvalue"); - evaluate_assign_to(expr, expr->ctype); - continue; - } - } END_FOR_EACH_PTR(expr); - - state = 0; - FOR_EACH_PTR(stmt->asm_inputs, expr) { - switch (state) { - case 0: /* Identifier */ - state = 1; - continue; - - case 1: /* Constraint */ - state = 2; - if (!expr || expr->type != EXPR_STRING) { - sparse_error(expr ? expr->pos : stmt->pos, "asm input constraint is not a string"); - *THIS_ADDRESS(expr) = NULL; - continue; - } + /* Expression */ + expr = op->expr; + if (!evaluate_expression(expr)) + return; + if (!lvalue_expression(expr)) + warning(expr->pos, "asm output is not an lvalue"); + evaluate_assign_to(expr, expr->ctype); + } END_FOR_EACH_PTR(op); + + FOR_EACH_PTR(stmt->asm_inputs, op) { + /* Identifier */ + + /* Constraint */ + expr = op->constraint; + if (!expr || expr->type != EXPR_STRING) { + sparse_error(expr ? expr->pos : stmt->pos, "asm input constraint is not a string"); + op->constraint = NULL; + } else verify_input_constraint(expr, expr->string->data); - continue; - case 2: /* Expression */ - state = 0; - if (!evaluate_expression(expr)) - return; - continue; - } - } END_FOR_EACH_PTR(expr); + /* Expression */ + if (!evaluate_expression(op->expr)) + return; + } END_FOR_EACH_PTR(op); FOR_EACH_PTR(stmt->asm_clobbers, expr) { if (!expr) { @@ -478,7 +478,7 @@ static int expand_comma(struct expression *expr) return cost; } -#define MOD_IGN (MOD_VOLATILE | MOD_CONST) +#define MOD_IGN (MOD_QUALIFIER) static int compare_types(int op, struct symbol *left, struct symbol *right) { @@ -582,7 +582,7 @@ static struct expression *constant_symbol_value(struct symbol *sym, int offset) { struct expression *value; - if (sym->ctype.modifiers & (MOD_ASSIGNED | MOD_ADDRESSABLE)) + if (sym->ctype.modifiers & MOD_ACCESS) return NULL; value = sym->initializer; if (!value) @@ -1048,6 +1048,9 @@ static int expand_expression(struct expression *expr) case EXPR_OFFSETOF: expression_error(expr, "internal front-end error: sizeof in expansion?"); return UNSAFE; + case EXPR_ASM_OPERAND: + expression_error(expr, "internal front-end error: ASM_OPERAND in expansion?"); + return UNSAFE; } return SIDE_EFFECTS; } diff --git a/expression.h b/expression.h index e98bef8a..d12b9197 100644 --- a/expression.h +++ b/expression.h @@ -64,6 +64,7 @@ enum expression_type { EXPR_FVALUE, EXPR_SLICE, EXPR_OFFSETOF, + EXPR_ASM_OPERAND, }; @@ -233,6 +234,12 @@ struct expression { struct expression *index; }; }; + // EXPR_ASM_OPERAND + struct { + struct ident *name; + struct expression *constraint; + struct expression *expr; + }; }; }; @@ -169,6 +169,13 @@ static int bb_has_side_effects(struct basic_block *bb) /* FIXME! This should take "const" etc into account */ return 1; + case OP_LOAD: + if (!insn->type) + return 1; + if (insn->type->ctype.modifiers & MOD_VOLATILE) + return 1; + continue; + case OP_STORE: case OP_CONTEXT: return 1; @@ -107,6 +107,12 @@ define gdb_show_ctype if ($arg0->modifiers & MOD_VOLATILE) printf "MOD_VOLATILE " end + if ($arg0->modifiers & MOD_RESTRICT) + printf "MOD_RESTRICT " + end + if ($arg0->modifiers & MOD_ATOMIC) + printf "MOD_ATOMIC " + end if ($arg0->modifiers & MOD_SIGNED) printf "MOD_SIGNED " end @@ -128,9 +134,6 @@ define gdb_show_ctype if ($arg0->modifiers & MOD_LONGLONGLONG) printf "MOD_LONGLONGLONG " end - if ($arg0->modifiers & MOD_TYPEDEF) - printf "MOD_TYPEDEF " - end if ($arg0->modifiers & MOD_INLINE) printf "MOD_INLINE " end @@ -143,9 +146,6 @@ define gdb_show_ctype if ($arg0->modifiers & MOD_NODEREF) printf "MOD_NODEREF " end - if ($arg0->modifiers & MOD_ACCESSED) - printf "MOD_ACCESSED " - end if ($arg0->modifiers & MOD_TOPLEVEL) printf "MOD_TOPLEVEL " end diff --git a/ident-list.h b/ident-list.h index 13087574..2f1fecb4 100644 --- a/ident-list.h +++ b/ident-list.h @@ -37,7 +37,7 @@ IDENT_RESERVED(_Imaginary); /* C11 keywords */ IDENT(_Alignas); IDENT_RESERVED(_Alignof); -IDENT_RESERVED(_Atomic); +IDENT(_Atomic); IDENT_RESERVED(_Generic); IDENT(_Noreturn); IDENT_RESERVED(_Static_assert); @@ -271,6 +271,12 @@ static struct expression * copy_expression(struct expression *expr) } break; } + case EXPR_ASM_OPERAND: { + expr = dup_expression(expr); + expr->constraint = copy_expression(expr->constraint); + expr->expr = copy_expression(expr->expr); + break; + } default: warning(expr->pos, "trying to copy expression type %d", expr->type); } @@ -281,20 +287,9 @@ static struct expression_list *copy_asm_constraints(struct expression_list *in) { struct expression_list *out = NULL; struct expression *expr; - int state = 0; FOR_EACH_PTR(in, expr) { - switch (state) { - case 0: /* identifier */ - case 1: /* constraint */ - state++; - add_expression(&out, expr); - continue; - case 2: /* expression */ - state = 0; - add_expression(&out, copy_expression(expr)); - continue; - } + add_expression(&out, copy_expression(expr)); } END_FOR_EACH_PTR(expr); return out; } @@ -110,6 +110,7 @@ static void do_warn(const char *type, struct position pos, const char * fmt, va_ vsprintf(buffer, fmt, args); name = stream_name(pos.stream); + fflush(stdout); fprintf(stderr, "%s:%d:%d: %s%s\n", name, pos.line, pos.pos, type, buffer); } diff --git a/linearize.c b/linearize.c index ba76397e..905b473e 100644 --- a/linearize.c +++ b/linearize.c @@ -1805,12 +1805,10 @@ static void add_asm_output(struct entrypoint *ep, struct instruction *insn, stru static pseudo_t linearize_asm_statement(struct entrypoint *ep, struct statement *stmt) { - int state; struct expression *expr; struct instruction *insn; struct asm_rules *rules; const char *constraint; - struct ident *ident; insn = alloc_instruction(OP_ASM, 0); expr = stmt->asm_string; @@ -1824,49 +1822,17 @@ static pseudo_t linearize_asm_statement(struct entrypoint *ep, struct statement insn->asm_rules = rules; /* Gather the inputs.. */ - state = 0; - ident = NULL; - constraint = NULL; FOR_EACH_PTR(stmt->asm_inputs, expr) { - switch (state) { - case 0: /* Identifier */ - state = 1; - ident = (struct ident *)expr; - continue; - - case 1: /* Constraint */ - state = 2; - constraint = expr ? expr->string->data : ""; - continue; - - case 2: /* Expression */ - state = 0; - add_asm_input(ep, insn, expr, constraint, ident); - } + constraint = expr->constraint ? expr->constraint->string->data : ""; + add_asm_input(ep, insn, expr->expr, constraint, expr->name); } END_FOR_EACH_PTR(expr); add_one_insn(ep, insn); /* Assign the outputs */ - state = 0; - ident = NULL; - constraint = NULL; FOR_EACH_PTR(stmt->asm_outputs, expr) { - switch (state) { - case 0: /* Identifier */ - state = 1; - ident = (struct ident *)expr; - continue; - - case 1: /* Constraint */ - state = 2; - constraint = expr ? expr->string->data : ""; - continue; - - case 2: - state = 0; - add_asm_output(ep, insn, expr, constraint, ident); - } + constraint = expr->constraint ? expr->constraint->string->data : ""; + add_asm_output(ep, insn, expr->expr, constraint, expr->name); } END_FOR_EACH_PTR(expr); return VOID; diff --git a/linearize.h b/linearize.h index bac82d7f..68efd891 100644 --- a/linearize.h +++ b/linearize.h @@ -106,7 +106,7 @@ struct instruction { pseudo_t base; unsigned from, len; }; - struct /* setval */ { + struct /* setval and symaddr */ { pseudo_t symbol; /* Subtle: same offset as "src" !! */ struct expression *val; }; @@ -158,8 +158,12 @@ static void kill_dominated_stores(struct basic_block *bb) if (insn->opcode == OP_STORE) { struct instruction *dom; pseudo_t pseudo = insn->src; - int local = local_pseudo(pseudo); + int local; + + if (insn->type->ctype.modifiers & MOD_VOLATILE) + continue; + local = local_pseudo(pseudo); RECURSE_PTR_REVERSE(insn, dom) { int dominance; if (!dom->bb) @@ -58,6 +58,8 @@ static declarator_t typedef_specifier, inline_specifier, auto_specifier, register_specifier, static_specifier, extern_specifier, thread_specifier, const_qualifier, volatile_qualifier; +static declarator_t restrict_qualifier; +static declarator_t atomic_qualifier; static struct token *parse_if_statement(struct token *token, struct statement *stmt); static struct token *parse_return_statement(struct token *token, struct statement *stmt); @@ -174,6 +176,12 @@ static struct symbol_op volatile_op = { static struct symbol_op restrict_op = { .type = KW_QUALIFIER, + .declarator = restrict_qualifier, +}; + +static struct symbol_op atomic_op = { + .type = KW_QUALIFIER, + .declarator = atomic_qualifier, }; static struct symbol_op typeof_op = { @@ -422,6 +430,10 @@ static struct init_keyword { { "volatile", NS_TYPEDEF, .op = &volatile_op }, { "__volatile", NS_TYPEDEF, .op = &volatile_op }, { "__volatile__", NS_TYPEDEF, .op = &volatile_op }, + { "restrict", NS_TYPEDEF, .op = &restrict_op}, + { "__restrict", NS_TYPEDEF, .op = &restrict_op}, + { "__restrict__", NS_TYPEDEF, .op = &restrict_op}, + { "_Atomic", NS_TYPEDEF, .op = &atomic_op}, /* Typedef.. */ { "typedef", NS_TYPEDEF, .op = &typedef_op }, @@ -467,11 +479,6 @@ static struct init_keyword { { "_Alignas", NS_TYPEDEF, .op = &alignas_op }, - /* Ignored for now.. */ - { "restrict", NS_TYPEDEF, .op = &restrict_op}, - { "__restrict", NS_TYPEDEF, .op = &restrict_op}, - { "__restrict__", NS_TYPEDEF, .op = &restrict_op}, - /* Static assertion */ { "_Static_assert", NS_KEYWORD, .op = &static_assert_op }, @@ -1377,6 +1384,18 @@ static struct token *volatile_qualifier(struct token *next, struct decl_state *c return next; } +static struct token *restrict_qualifier(struct token *next, struct decl_state *ctx) +{ + apply_qualifier(&next->pos, &ctx->ctype, MOD_RESTRICT); + return next; +} + +static struct token *atomic_qualifier(struct token *next, struct decl_state *ctx) +{ + apply_qualifier(&next->pos, &ctx->ctype, MOD_ATOMIC); + return next; +} + static void apply_ctype(struct position pos, struct ctype *thistype, struct ctype *ctype) { unsigned long mod = thistype->modifiers; @@ -1929,24 +1948,20 @@ static struct token *expression_statement(struct token *token, struct expression static struct token *parse_asm_operands(struct token *token, struct statement *stmt, struct expression_list **inout) { - struct expression *expr; - /* Allow empty operands */ if (match_op(token->next, ':') || match_op(token->next, ')')) return token->next; do { - struct ident *ident = NULL; + struct expression *op = alloc_expression(token->pos, EXPR_ASM_OPERAND); if (match_op(token->next, '[') && token_type(token->next->next) == TOKEN_IDENT && match_op(token->next->next->next, ']')) { - ident = token->next->next->ident; + op->name = token->next->next->ident; token = token->next->next->next; } - add_expression(inout, (struct expression *)ident); /* UGGLEE!!! */ - token = primary_expression(token->next, &expr); - add_expression(inout, expr); - token = parens_expression(token, &expr, "in asm parameter"); - add_expression(inout, expr); + token = primary_expression(token->next, &op->constraint); + token = parens_expression(token, &op->expr, "in asm parameter"); + add_expression(inout, op); } while (match_op(token, ',')); return token; } @@ -2094,7 +2109,7 @@ static struct statement *start_function(struct symbol *sym) start_function_scope(); ret = alloc_symbol(sym->pos, SYM_NODE); ret->ctype = sym->ctype.base_type->ctype; - ret->ctype.modifiers &= ~(MOD_STORAGE | MOD_CONST | MOD_VOLATILE | MOD_TLS | MOD_INLINE | MOD_ADDRESSABLE | MOD_NOCAST | MOD_NODEREF | MOD_ACCESSED | MOD_TOPLEVEL); + ret->ctype.modifiers &= ~(MOD_STORAGE | MOD_QUALIFIER | MOD_TLS | MOD_ACCESS | MOD_NOCAST | MOD_NODEREF); ret->ctype.modifiers |= (MOD_AUTO | MOD_REGISTER); bind_symbol(ret, &return_ident, NS_ITERATOR); stmt->ret = ret; @@ -22,7 +22,7 @@ */ #define MKTYPE(head,expr) ({ (TYPEOF(head))(expr); }) -#define LIST_NODE_NR (29) +#define LIST_NODE_NR (13) struct ptr_list { int nr:8; @@ -28,7 +28,6 @@ struct symbol; struct scope { - struct token *token; /* Scope start information */ struct symbol_list *symbols; /* List of symbols in this scope */ struct scope *next; }; diff --git a/show-parse.c b/show-parse.c index d365d737..d60a6dec 100644 --- a/show-parse.c +++ b/show-parse.c @@ -125,6 +125,8 @@ const char *modifier_string(unsigned long mod) {MOD_EXTERN, "extern"}, {MOD_CONST, "const"}, {MOD_VOLATILE, "volatile"}, + {MOD_RESTRICT, "restrict"}, + {MOD_ATOMIC, "[atomic]"}, {MOD_SIGNED, "[signed]"}, {MOD_UNSIGNED, "[unsigned]"}, {MOD_CHAR, "[char]"}, @@ -132,13 +134,11 @@ const char *modifier_string(unsigned long mod) {MOD_LONG, "[long]"}, {MOD_LONGLONG, "[long long]"}, {MOD_LONGLONGLONG, "[long long long]"}, - {MOD_TYPEDEF, "[typedef]"}, {MOD_TLS, "[tls]"}, {MOD_INLINE, "inline"}, {MOD_ADDRESSABLE, "[addressable]"}, {MOD_NOCAST, "[nocast]"}, {MOD_NODEREF, "[noderef]"}, - {MOD_ACCESSED, "[accessed]"}, {MOD_TOPLEVEL, "[toplevel]"}, {MOD_ASSIGNED, "[assigned]"}, {MOD_TYPE, "[type]"}, @@ -927,7 +927,7 @@ static int show_symbol_expr(struct symbol *sym) return new; } if (sym->ctype.modifiers & MOD_ADDRESSABLE) { - printf("\taddi.%d\t\tv%d,vFP,$%lld\n", bits_in_pointer, new, sym->value); + printf("\taddi.%d\t\tv%d,vFP,$%lld\n", bits_in_pointer, new, 0LL); return new; } printf("\taddi.%d\t\tv%d,vFP,$offsetof(%s:%p)\n", bits_in_pointer, new, show_ident(sym->ident), sym); @@ -1169,6 +1169,9 @@ int show_expression(struct expression *expr) case EXPR_TYPE: warning(expr->pos, "unable to show type expression"); return 0; + case EXPR_ASM_OPERAND: + warning(expr->pos, "unable to show asm operand expression"); + return 0; } return 0; } @@ -944,6 +944,10 @@ static int simplify_cast(struct instruction *insn) if (is_ptr_type(orig_type) || is_ptr_type(insn->type)) return 0; + /* Keep float-to-int casts */ + if (is_float_type(orig_type) && !is_float_type(insn->type)) + return 0; + orig_size = orig_type->bit_size; size = insn->size; src = insn->src; @@ -48,9 +48,9 @@ struct symbol_list *translation_unit_used_list = NULL; void access_symbol(struct symbol *sym) { if (sym->ctype.modifiers & MOD_INLINE) { - if (!(sym->ctype.modifiers & MOD_ACCESSED)) { + if (!sym->accessed) { add_symbol(&translation_unit_used_list, sym); - sym->ctype.modifiers |= MOD_ACCESSED; + sym->accessed = 1; } } } @@ -164,7 +164,6 @@ struct symbol { unsigned long offset; int bit_size; unsigned int bit_offset:8, - arg_count:10, variadic:1, initialized:1, examined:1, @@ -173,6 +172,7 @@ struct symbol { string:1, designated_init:1, forced_arg:1, + accessed:1, transparent_union:1; struct expression *array_size; struct ctype ctype; @@ -183,7 +183,6 @@ struct symbol { struct symbol_list *inline_symbol_list; struct expression *initializer; struct entrypoint *ep; - long long value; /* Initial value */ struct symbol *definition; }; }; @@ -199,55 +198,54 @@ struct symbol { }; /* Modifiers */ -#define MOD_AUTO 0x0001 -#define MOD_REGISTER 0x0002 -#define MOD_STATIC 0x0004 -#define MOD_EXTERN 0x0008 - -#define MOD_CONST 0x0010 -#define MOD_VOLATILE 0x0020 -#define MOD_SIGNED 0x0040 -#define MOD_UNSIGNED 0x0080 - -#define MOD_CHAR 0x0100 -#define MOD_SHORT 0x0200 -#define MOD_LONG 0x0400 -#define MOD_LONGLONG 0x0800 -#define MOD_LONGLONGLONG 0x1000 -#define MOD_PURE 0x2000 - -#define MOD_TYPEDEF 0x10000 - -#define MOD_TLS 0x20000 -#define MOD_INLINE 0x40000 -#define MOD_ADDRESSABLE 0x80000 - -#define MOD_NOCAST 0x100000 -#define MOD_NODEREF 0x200000 -#define MOD_ACCESSED 0x400000 -#define MOD_TOPLEVEL 0x800000 // scoping.. - -#define MOD_ASSIGNED 0x2000000 -#define MOD_TYPE 0x4000000 -#define MOD_SAFE 0x8000000 // non-null/non-trapping pointer - -#define MOD_USERTYPE 0x10000000 -#define MOD_NORETURN 0x20000000 -#define MOD_EXPLICITLY_SIGNED 0x40000000 -#define MOD_BITWISE 0x80000000 - - +#define MOD_AUTO 0x00000001 +#define MOD_REGISTER 0x00000002 +#define MOD_STATIC 0x00000004 +#define MOD_EXTERN 0x00000008 +#define MOD_TOPLEVEL 0x00000010 // scoping.. +#define MOD_TLS 0x00000020 +#define MOD_INLINE 0x00000040 + +#define MOD_ASSIGNED 0x00000080 +#define MOD_ADDRESSABLE 0x00000100 + +#define MOD_CONST 0x00000200 +#define MOD_VOLATILE 0x00000400 +#define MOD_RESTRICT 0x00000800 +#define MOD_ATOMIC 0x00001000 + +#define MOD_SIGNED 0x00002000 +#define MOD_UNSIGNED 0x00004000 +#define MOD_EXPLICITLY_SIGNED 0x00008000 + +#define MOD_TYPE 0x00010000 +#define MOD_USERTYPE 0x00020000 +#define MOD_CHAR 0x00040000 +#define MOD_SHORT 0x00080000 +#define MOD_LONG 0x00100000 +#define MOD_LONGLONG 0x00200000 +#define MOD_LONGLONGLONG 0x00400000 + +#define MOD_SAFE 0x00800000 // non-null/non-trapping pointer +#define MOD_PURE 0x01000000 +#define MOD_BITWISE 0x02000000 +#define MOD_NOCAST 0x04000000 +#define MOD_NODEREF 0x08000000 +#define MOD_NORETURN 0x10000000 + + +#define MOD_ACCESS (MOD_ASSIGNED | MOD_ADDRESSABLE) #define MOD_NONLOCAL (MOD_EXTERN | MOD_TOPLEVEL) #define MOD_STORAGE (MOD_AUTO | MOD_REGISTER | MOD_STATIC | MOD_EXTERN | MOD_INLINE | MOD_TOPLEVEL) #define MOD_SIGNEDNESS (MOD_SIGNED | MOD_UNSIGNED | MOD_EXPLICITLY_SIGNED) #define MOD_LONG_ALL (MOD_LONG | MOD_LONGLONG | MOD_LONGLONGLONG) #define MOD_SPECIFIER (MOD_CHAR | MOD_SHORT | MOD_LONG_ALL | MOD_SIGNEDNESS) #define MOD_SIZE (MOD_CHAR | MOD_SHORT | MOD_LONG_ALL) -#define MOD_IGNORE (MOD_TOPLEVEL | MOD_STORAGE | MOD_ADDRESSABLE | \ - MOD_ASSIGNED | MOD_USERTYPE | MOD_ACCESSED | MOD_EXPLICITLY_SIGNED) -#define MOD_PTRINHERIT (MOD_VOLATILE | MOD_CONST | MOD_NODEREF | MOD_NORETURN | MOD_NOCAST) +#define MOD_IGNORE (MOD_STORAGE | MOD_ACCESS | MOD_USERTYPE | MOD_EXPLICITLY_SIGNED) +#define MOD_QUALIFIER (MOD_CONST | MOD_VOLATILE | MOD_RESTRICT | MOD_ATOMIC) +#define MOD_PTRINHERIT (MOD_QUALIFIER | MOD_NODEREF | MOD_NORETURN | MOD_NOCAST) /* modifiers preserved by typeof() operator */ -#define MOD_TYPEOF (MOD_VOLATILE | MOD_CONST | MOD_NOCAST | MOD_SPECIFIER) +#define MOD_TYPEOF (MOD_QUALIFIER | MOD_NOCAST | MOD_SPECIFIER) /* Current parsing/evaluation function */ diff --git a/validation/c11-atomic.c b/validation/c11-atomic.c new file mode 100644 index 00000000..bea3dab8 --- /dev/null +++ b/validation/c11-atomic.c @@ -0,0 +1,93 @@ +void f00(int _Atomic dst); +void f01(int _Atomic *dst); +void f02(int _Atomic *dst); +void f03(int _Atomic *dst); + +int _Atomic qo; +int uo; + +void f00(int dst) { } /* check-should-pass */ +void f01(typeof(&qo) dst) { } /* check-should-pass */ +void f02(int *dst) { } /* check-should-fail */ +void f03(typeof(&uo) dst) { } /* check-should-fail */ + +void foo(void) +{ + qo = uo; /* check-should-pass */ + uo = qo; /* check-should-pass */ +} + +void ref(void) +{ + const int qo; + int uo; + extern const int *pqo; + extern int *puo; + + pqo = &qo; /* check-should-pass */ + pqo = &uo; /* check-should-pass */ + pqo = puo; + + puo = &uo; /* check-should-pass */ + + puo = &qo; /* check-should-fail */ + puo = pqo; /* check-should-fail */ +} + +void bar(void) +{ + extern int _Atomic *pqo; + extern int *puo; + + pqo = &qo; /* check-should-pass */ + pqo = &uo; /* check-should-pass */ + pqo = puo; + + puo = &uo; /* check-should-pass */ + + puo = &qo; /* check-should-fail */ + puo = pqo; /* check-should-fail */ +} + +void baz(void) +{ + extern typeof(&qo) pqo; + extern typeof(&uo) puo; + + pqo = &qo; /* check-should-pass */ + pqo = &uo; /* check-should-pass */ + pqo = puo; + + puo = &uo; /* check-should-pass */ + + puo = &qo; /* check-should-fail */ + puo = pqo; /* check-should-fail */ +} + +/* + * check-name: C11 _Atomic type qualifier + * check-command: sparse -Wno-decl $file; + * + * check-error-start +c11-atomic.c:11:6: error: symbol 'f02' redeclared with different type (originally declared at c11-atomic.c:3) - incompatible argument 1 (different modifiers) +c11-atomic.c:12:6: error: symbol 'f03' redeclared with different type (originally declared at c11-atomic.c:4) - incompatible argument 1 (different modifiers) +c11-atomic.c:33:13: warning: incorrect type in assignment (different modifiers) +c11-atomic.c:33:13: expected int *extern [assigned] puo +c11-atomic.c:33:13: got int const *<noident> +c11-atomic.c:34:13: warning: incorrect type in assignment (different modifiers) +c11-atomic.c:34:13: expected int *extern [assigned] puo +c11-atomic.c:34:13: got int const *extern [assigned] pqo +c11-atomic.c:48:13: warning: incorrect type in assignment (different modifiers) +c11-atomic.c:48:13: expected int *extern [assigned] puo +c11-atomic.c:48:13: got int [atomic] *<noident> +c11-atomic.c:49:13: warning: incorrect type in assignment (different modifiers) +c11-atomic.c:49:13: expected int *extern [assigned] puo +c11-atomic.c:49:13: got int [atomic] *extern [assigned] pqo +c11-atomic.c:63:13: warning: incorrect type in assignment (different modifiers) +c11-atomic.c:63:13: expected int *extern [assigned] puo +c11-atomic.c:63:13: got int [atomic] *<noident> +c11-atomic.c:64:13: warning: incorrect type in assignment (different modifiers) +c11-atomic.c:64:13: expected int *extern [assigned] puo +c11-atomic.c:64:13: got int [atomic] *extern [assigned] pqo + * check-error-end + */ diff --git a/validation/cast-kinds.c b/validation/cast-kinds.c index 697f9735..e686c01e 100644 --- a/validation/cast-kinds.c +++ b/validation/cast-kinds.c @@ -92,7 +92,8 @@ iptr_2_int: float_2_int: .L10: <entry-point> - ret.32 %arg1 + cast.32 %r17 <- (32) %arg1 + ret.32 %r17 double_2_int: @@ -139,7 +140,8 @@ iptr_2_uint: float_2_uint: .L24: <entry-point> - ret.32 %arg1 + cast.32 %r38 <- (32) %arg1 + ret.32 %r38 double_2_uint: @@ -193,7 +195,8 @@ float_2_long: double_2_long: .L40: <entry-point> - ret.64 %arg1 + cast.64 %r62 <- (64) %arg1 + ret.64 %r62 int_2_ulong: @@ -240,7 +243,8 @@ float_2_ulong: double_2_ulong: .L54: <entry-point> - ret.64 %arg1 + cast.64 %r83 <- (64) %arg1 + ret.64 %r83 int_2_vptr: diff --git a/validation/fp2i-cast.c b/validation/fp2i-cast.c new file mode 100644 index 00000000..08f8c925 --- /dev/null +++ b/validation/fp2i-cast.c @@ -0,0 +1,30 @@ +#if __SIZEOF_INT__ == __SIZEOF_FLOAT__ +typedef signed int si; +typedef unsigned int ui; +#else +#error "no float-sized integer type" +#endif + +#if __SIZEOF_LONG_LONG__ == __SIZEOF_DOUBLE__ +typedef signed long long sl; +typedef unsigned long long ul; +#else +#error "no double-sized integer type" +#endif + +si f2si(float a) { return a; } +ui f2ui(float a) { return a; } +sl f2sl(float a) { return a; } +ul f2ul(float a) { return a; } +si d2si(double a) { return a; } +ui d2ui(double a) { return a; } +sl d2sl(double a) { return a; } +ul d2ul(double a) { return a; } + +/* + * check-name: fp2i cast + * check-command: test-linearize -Wno-decl $file + * + * check-output-ignore + * check-output-pattern-8-times: cast\\. + */ diff --git a/validation/memops-volatile.c b/validation/memops-volatile.c index 0f3e12ad..15314e1c 100644 --- a/validation/memops-volatile.c +++ b/validation/memops-volatile.c @@ -1,6 +1,7 @@ static int foo(volatile int *a, int v) { *a = v; + *a = 0; return *a; } @@ -8,14 +9,8 @@ static int foo(volatile int *a, int v) * check-name: memops-volatile * check-command: test-linearize $file * - * check-output-start -foo: -.L0: - <entry-point> - store.32 %arg2 -> 0[%arg1] - load.32 %r5 <- 0[%arg1] - ret.32 %r5 - - - * check-output-end + * check-output-ignore + * check-output-contains: store\\..*%arg2 -> 0\\[%arg1] + * check-output-contains: store\\..*\\$0 -> 0\\[%arg1] + * check-output-contains: load\\..*%r.* <- 0\\[%arg1] */ diff --git a/validation/optim/restrict.c b/validation/optim/restrict.c new file mode 100644 index 00000000..de6289e2 --- /dev/null +++ b/validation/optim/restrict.c @@ -0,0 +1,73 @@ +extern int g, h; + +void f00u(int *s) +{ + g = *s; + h = *s; +} + +void f00r(int *restrict s) +{ + g = *s; + h = *s; +} + + +void f01u(int *a, int *b, int *s) +{ + *a = *s; + *b = *s; +} + +void f01r(int *restrict a, int *restrict b, int *restrict s) +{ + *a = *s; + *b = *s; +} + +/* + * check-name: optim/restrict + * check-command: test-linearize -Wno-decl $file + * check-known-to-fail + * + * check-output-start +f00u: +.L0: + <entry-point> + load.32 %r2 <- 0[%arg1] + store.32 %r2 -> 0[g] + load.32 %r4 <- 0[%arg1] + store.32 %r4 -> 0[h] + ret + + +f00r: +.L2: + <entry-point> + load.32 %r6 <- 0[%arg1] + store.32 %r6 -> 0[g] + store.32 %r6 -> 0[h] + ret + + +f01u: +.L4: + <entry-point> + load.32 %r10 <- 0[%arg3] + store.32 %r10 -> 0[%arg1] + load.32 %r13 <- 0[%arg3] + store.32 %r13 -> 0[%arg2] + ret + + +f01r: +.L6: + <entry-point> + load.32 %r16 <- 0[%arg3] + store.32 %r16 -> 0[%arg1] + store.32 %r16 -> 0[%arg2] + ret + + + * check-output-end + */ diff --git a/validation/optim/volatile-side-effect.c b/validation/optim/volatile-side-effect.c new file mode 100644 index 00000000..842b7228 --- /dev/null +++ b/validation/optim/volatile-side-effect.c @@ -0,0 +1,13 @@ +void foo(int p, volatile int *ptr) +{ + p ? : *ptr; + p ? : *ptr; +} + +/* + * check-name: volatile-side-effect + * check-command: test-linearize -Wno-decl $file + * check-output-ignore + * + * check-output-pattern(2): load + */ diff --git a/validation/reload-aliasing.c b/validation/reload-aliasing.c new file mode 100644 index 00000000..3aad317b --- /dev/null +++ b/validation/reload-aliasing.c @@ -0,0 +1,41 @@ +extern int g, h; + +void f00(int *s) +{ + g = *s; + h = *s; +} + +void f01(int *a, int *b, int *s) +{ + *a = *s; + *b = *s; +} + +/* + * check-name: reload-aliasing.c + * check-command: test-linearize -Wno-decl $file + * + * check-output-start +f00: +.L0: + <entry-point> + load.32 %r2 <- 0[%arg1] + store.32 %r2 -> 0[g] + load.32 %r4 <- 0[%arg1] + store.32 %r4 -> 0[h] + ret + + +f01: +.L2: + <entry-point> + load.32 %r6 <- 0[%arg3] + store.32 %r6 -> 0[%arg1] + load.32 %r9 <- 0[%arg3] + store.32 %r9 -> 0[%arg2] + ret + + + * check-output-end + */ diff --git a/validation/restrict.c b/validation/restrict.c new file mode 100644 index 00000000..f431f6d0 --- /dev/null +++ b/validation/restrict.c @@ -0,0 +1,93 @@ +void f00(void *restrict dst); +void f01(void *restrict *dst); +void f02(void *restrict *dst); +void f03(void *restrict *dst); + +void *restrict rp; +void * up; + +void f00(void *dst) { } /* check-should-pass */ +void f01(typeof(&rp) dst) { } /* check-should-pass */ +void f02(void **dst) { } /* check-should-fail */ +void f03(typeof(&up) dst) { } /* check-should-fail */ + +void foo(void) +{ + rp = up; /* check-should-pass */ + up = rp; /* check-should-pass */ +} + +void ref(void) +{ + void *const qp; + void * up; + extern void *const *pqp; + extern void **pup; + + pqp = &qp; /* check-should-pass */ + pqp = &up; /* check-should-pass */ + pqp = pup; + + pup = &up; /* check-should-pass */ + + pup = &qp; /* check-should-fail */ + pup = pqp; /* check-should-fail */ +} + +void bar(void) +{ + extern void *restrict *prp; + extern void **pup; + + prp = &rp; /* check-should-pass */ + prp = &up; /* check-should-pass */ + prp = pup; + + pup = &up; /* check-should-pass */ + + pup = &rp; /* check-should-fail */ + pup = prp; /* check-should-fail */ +} + +void baz(void) +{ + extern typeof(&rp) prp; + extern typeof(&up) pup; + + prp = &rp; /* check-should-pass */ + prp = &up; /* check-should-pass */ + prp = pup; + + pup = &up; /* check-should-pass */ + + pup = &rp; /* check-should-fail */ + pup = prp; /* check-should-fail */ +} + +/* + * check-name: restrict qualifier + * check-command: sparse -Wno-decl $file; + * + * check-error-start +restrict.c:11:6: error: symbol 'f02' redeclared with different type (originally declared at restrict.c:3) - incompatible argument 1 (different modifiers) +restrict.c:12:6: error: symbol 'f03' redeclared with different type (originally declared at restrict.c:4) - incompatible argument 1 (different modifiers) +restrict.c:33:13: warning: incorrect type in assignment (different modifiers) +restrict.c:33:13: expected void **extern [assigned] pup +restrict.c:33:13: got void *const *<noident> +restrict.c:34:13: warning: incorrect type in assignment (different modifiers) +restrict.c:34:13: expected void **extern [assigned] pup +restrict.c:34:13: got void *const *extern [assigned] pqp +restrict.c:48:13: warning: incorrect type in assignment (different modifiers) +restrict.c:48:13: expected void **extern [assigned] pup +restrict.c:48:13: got void *restrict *<noident> +restrict.c:49:13: warning: incorrect type in assignment (different modifiers) +restrict.c:49:13: expected void **extern [assigned] pup +restrict.c:49:13: got void *restrict *extern [assigned] prp +restrict.c:63:13: warning: incorrect type in assignment (different modifiers) +restrict.c:63:13: expected void **extern [assigned] pup +restrict.c:63:13: got void *restrict *<noident> +restrict.c:64:13: warning: incorrect type in assignment (different modifiers) +restrict.c:64:13: expected void **extern [assigned] pup +restrict.c:64:13: got void *restrict *extern [assigned] prp + * check-error-end + */ diff --git a/validation/typeof-mods.c b/validation/typeof-mods.c index 9822e96f..aa880f37 100644 --- a/validation/typeof-mods.c +++ b/validation/typeof-mods.c @@ -43,6 +43,34 @@ static void test_volatile(void) obj = *ptr; } +static void test_restrict(void) +{ + int *restrict obj, *restrict *ptr; + typeof(obj) var = obj; + typeof(ptr) ptr2 = ptr; + typeof(*ptr) var2 = obj; + typeof(*ptr) *ptr3 = ptr; + typeof(obj) *ptr4 = ptr; + obj = obj; + ptr = ptr; + ptr = &obj; + obj = *ptr; +} + +static void test_atomic(void) +{ + int _Atomic obj, *ptr; + typeof(obj) var = obj; + typeof(ptr) ptr2 = ptr; + typeof(*ptr) var2 = obj; + typeof(*ptr) *ptr3 = ptr; + typeof(obj) *ptr4 = ptr; + obj = obj; + ptr = ptr; + ptr = &obj; + obj = *ptr; +} + static void test_bitwise(void) { typedef int __bitwise type_t; |
