aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
-rw-r--r--allocate.c2
-rw-r--r--allocate.h3
-rw-r--r--compile-i386.c2
-rw-r--r--evaluate.c84
-rw-r--r--expand.c7
-rw-r--r--expression.h7
-rw-r--r--flow.c7
-rw-r--r--gdbhelpers12
-rw-r--r--ident-list.h2
-rw-r--r--inline.c19
-rw-r--r--lib.c1
-rw-r--r--linearize.c42
-rw-r--r--linearize.h2
-rw-r--r--memops.c6
-rw-r--r--parse.c45
-rw-r--r--ptrlist.h2
-rw-r--r--scope.h1
-rw-r--r--show-parse.c9
-rw-r--r--simplify.c4
-rw-r--r--symbol.c4
-rw-r--r--symbol.h86
-rw-r--r--validation/c11-atomic.c93
-rw-r--r--validation/cast-kinds.c12
-rw-r--r--validation/fp2i-cast.c30
-rw-r--r--validation/memops-volatile.c15
-rw-r--r--validation/optim/restrict.c73
-rw-r--r--validation/optim/volatile-side-effect.c13
-rw-r--r--validation/reload-aliasing.c41
-rw-r--r--validation/restrict.c93
-rw-r--r--validation/typeof-mods.c28
30 files changed, 552 insertions, 193 deletions
diff --git a/allocate.c b/allocate.c
index daa4ac24..0cc55630 100644
--- a/allocate.c
+++ b/allocate.c
@@ -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,
diff --git a/allocate.h b/allocate.h
index 64bb6dd6..cbddc2aa 100644
--- a/allocate.h
+++ b/allocate.h
@@ -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);
diff --git a/evaluate.c b/evaluate.c
index b96696d3..4bca1354 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -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) {
diff --git a/expand.c b/expand.c
index 4113e83c..f1aa838d 100644
--- a/expand.c
+++ b/expand.c
@@ -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;
+ };
};
};
diff --git a/flow.c b/flow.c
index 6b2c879a..1144bff4 100644
--- a/flow.c
+++ b/flow.c
@@ -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;
diff --git a/gdbhelpers b/gdbhelpers
index 86347863..2fe9336d 100644
--- a/gdbhelpers
+++ b/gdbhelpers
@@ -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);
diff --git a/inline.c b/inline.c
index a3002c6b..012fb379 100644
--- a/inline.c
+++ b/inline.c
@@ -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;
}
diff --git a/lib.c b/lib.c
index b255fec1..d6b7c77c 100644
--- a/lib.c
+++ b/lib.c
@@ -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;
};
diff --git a/memops.c b/memops.c
index aeacdf56..1c845a5f 100644
--- a/memops.c
+++ b/memops.c
@@ -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)
diff --git a/parse.c b/parse.c
index 02a55a74..e255345f 100644
--- a/parse.c
+++ b/parse.c
@@ -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;
diff --git a/ptrlist.h b/ptrlist.h
index 78625c8d..4451ee33 100644
--- a/ptrlist.h
+++ b/ptrlist.h
@@ -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;
diff --git a/scope.h b/scope.h
index 9bbb6757..d9a14aa3 100644
--- a/scope.h
+++ b/scope.h
@@ -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;
}
diff --git a/simplify.c b/simplify.c
index 2bc86f53..6555da5f 100644
--- a/simplify.c
+++ b/simplify.c
@@ -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;
diff --git a/symbol.c b/symbol.c
index 26906ec4..2f4afd51 100644
--- a/symbol.c
+++ b/symbol.c
@@ -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;
}
}
}
diff --git a/symbol.h b/symbol.h
index 0c50884a..b0a7205a 100644
--- a/symbol.h
+++ b/symbol.h
@@ -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;