aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-08-08 18:44:49 +0200
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-08-08 18:44:49 +0200
commit13252024246cc03fc8cc0d812c61421f96faa3c7 (patch)
tree124c3c44c320855768308c338f618bcb5526b395
parented14a50f8ff71d1b6c0ddaab9465b689482fff4d (diff)
parent561d0af146666fde424da06a994b9f9016ba6e05 (diff)
downloadsparse-13252024246cc03fc8cc0d812c61421f96faa3c7.tar.gz
Merge branch 'sync-cas' into next
* fix evaluation of __sync_{bool,val}_compare_and_swap()
-rw-r--r--builtin.c60
-rw-r--r--evaluate.c7
-rw-r--r--evaluate.h7
-rw-r--r--validation/builtin-sync-cas.c25
4 files changed, 93 insertions, 6 deletions
diff --git a/builtin.c b/builtin.c
index f29b4a8d..2e9be8be 100644
--- a/builtin.c
+++ b/builtin.c
@@ -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 }},
{ }
diff --git a/evaluate.c b/evaluate.c
index a9adc72f..9990b57b 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -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);
diff --git a/evaluate.h b/evaluate.h
index f68f7fb7..a16e9703 100644
--- a/evaluate.h
+++ b/evaluate.h
@@ -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
+ */