aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/builtin.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin.c')
-rw-r--r--builtin.c60
1 files changed, 58 insertions, 2 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 }},
{ }