diff options
author | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2020-08-08 18:44:49 +0200 |
---|---|---|
committer | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2020-08-08 18:44:49 +0200 |
commit | 13252024246cc03fc8cc0d812c61421f96faa3c7 (patch) | |
tree | 124c3c44c320855768308c338f618bcb5526b395 | |
parent | ed14a50f8ff71d1b6c0ddaab9465b689482fff4d (diff) | |
parent | 561d0af146666fde424da06a994b9f9016ba6e05 (diff) | |
download | sparse-13252024246cc03fc8cc0d812c61421f96faa3c7.tar.gz |
Merge branch 'sync-cas' into next
* fix evaluation of __sync_{bool,val}_compare_and_swap()
-rw-r--r-- | builtin.c | 60 | ||||
-rw-r--r-- | evaluate.c | 7 | ||||
-rw-r--r-- | evaluate.h | 7 | ||||
-rw-r--r-- | validation/builtin-sync-cas.c | 25 |
4 files changed, 93 insertions, 6 deletions
@@ -355,6 +355,62 @@ static struct symbol_op overflow_p_op = { }; +static int eval_sync_compare_and_swap(struct expression *expr) +{ + struct symbol_list *types = NULL; + struct symbol *ctype = NULL; + struct expression *arg; + int n = 0; + + /* the first arg is a pointer type; we'd already verified that */ + FOR_EACH_PTR(expr->args, arg) { + struct symbol *t = arg->ctype; + + if (!t) + return 0; + + // 2nd & 3rd args must be a basic integer type or a pointer + // 1st arg must be a pointer to such a type. + if (++n == 1) { + if (t->type == SYM_NODE) + t = t->ctype.base_type; + if (!t) + return 0; + if (t->type != SYM_PTR) + goto err; + t = t->ctype.base_type; + if (!t) + return 0; + if (t->type == SYM_NODE) + t = t->ctype.base_type; + if (!t) + return 0; + if (t->type != SYM_PTR && t->ctype.base_type != &int_type) + goto err; + ctype = t; + add_ptr_list(&types, arg->ctype); + } else { + add_ptr_list(&types, ctype); + } + } END_FOR_EACH_PTR(arg); + + if (!expr->ctype) // __sync_val_compare_and_swap() + expr->ctype = ctype; + return evaluate_arguments(types, expr->args); + +err: + sparse_error(arg->pos, "invalid type for argument %d:", n); + info(arg->pos, " %s", show_typename(arg->ctype)); + expr->ctype = &bad_ctype; + return 0; +} + +static struct symbol_op sync_compare_and_swap_op = { + .args = args_triadic, + .evaluate = eval_sync_compare_and_swap, +}; + + /* * Builtin functions */ @@ -548,7 +604,7 @@ static const struct builtin_fn builtins_common[] = { { "__sync_add_and_fetch", &int_ctype, 1, { &ptr_ctype }}, { "__sync_and_and_fetch", &int_ctype, 1, { &ptr_ctype }}, - { "__sync_bool_compare_and_swap", &int_ctype, 1, { &ptr_ctype }}, + { "__sync_bool_compare_and_swap", &bool_ctype, 1, { &ptr_ctype }, .op = &sync_compare_and_swap_op}, { "__sync_fetch_and_add", &int_ctype, 1, { &ptr_ctype }}, { "__sync_fetch_and_and", &int_ctype, 1, { &ptr_ctype }}, { "__sync_fetch_and_nand", &int_ctype, 1, { &ptr_ctype }}, @@ -561,7 +617,7 @@ static const struct builtin_fn builtins_common[] = { { "__sync_or_and_fetch", &int_ctype, 1, { &ptr_ctype }}, { "__sync_sub_and_fetch", &int_ctype, 1, { &ptr_ctype }}, { "__sync_synchronize", &void_ctype, 0 }, - { "__sync_val_compare_and_swap", &int_ctype, 1, { &ptr_ctype }}, + { "__sync_val_compare_and_swap", NULL, 1, { &ptr_ctype }, .op = &sync_compare_and_swap_op }, { "__sync_xor_and_fetch", &int_ctype, 1, { &ptr_ctype }}, { } @@ -2342,14 +2342,13 @@ static struct symbol *evaluate_alignof(struct expression *expr) return size_t_ctype; } -static int evaluate_arguments(struct symbol *fn, struct expression_list *head) +int evaluate_arguments(struct symbol_list *argtypes, struct expression_list *head) { struct expression *expr; - struct symbol_list *argument_types = fn->arguments; struct symbol *argtype; int i = 1; - PREPARE_PTR_LIST(argument_types, argtype); + PREPARE_PTR_LIST(argtypes, argtype); FOR_EACH_PTR (head, expr) { struct expression **p = THIS_ADDRESS(expr); struct symbol *ctype, *target; @@ -3158,7 +3157,7 @@ static struct symbol *evaluate_call(struct expression *expr) if (!sym->op->args(expr)) return NULL; } else { - if (!evaluate_arguments(ctype, arglist)) + if (!evaluate_arguments(ctype->arguments, arglist)) return NULL; args = expression_list_size(expr->args); fnargs = symbol_list_size(ctype->arguments); @@ -2,6 +2,7 @@ #define EVALUATE_H struct expression; +struct expression_list; struct statement; struct symbol; struct symbol_list; @@ -25,4 +26,10 @@ struct symbol *evaluate_statement(struct statement *stmt); // @list: the list of the symbol to be evaluated void evaluate_symbol_list(struct symbol_list *list); +/// +// evaluate the arguments of a function +// @argtypes: the list of the types in the prototype +// @args: the list of the effective arguments +int evaluate_arguments(struct symbol_list *argtypes, struct expression_list *args); + #endif diff --git a/validation/builtin-sync-cas.c b/validation/builtin-sync-cas.c new file mode 100644 index 00000000..846e21bb --- /dev/null +++ b/validation/builtin-sync-cas.c @@ -0,0 +1,25 @@ +static int *foo(int *ptr) +{ + __sync_val_compare_and_swap(ptr, 123, 0L); + return __sync_val_compare_and_swap(&ptr, ptr, ptr); +} + +static long bar(long *ptr) +{ + return __sync_val_compare_and_swap(ptr, ptr, 1); +} + +static _Bool boz(_Bool *ptr) +{ + return __sync_bool_compare_and_swap(ptr, 0, ptr); +} + +/* + * check-name: builtin-sync-cas + * + * check-error-start +builtin-sync-cas.c:9:49: warning: incorrect type in argument 2 (different base types) +builtin-sync-cas.c:9:49: expected long +builtin-sync-cas.c:9:49: got long *ptr + * check-error-end + */ |