diff options
author | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2020-10-19 00:37:55 +0200 |
---|---|---|
committer | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2020-10-19 20:46:08 +0200 |
commit | 7f33e55f0b4b011543a7e529331576429270b738 (patch) | |
tree | b0acd008b6a74102e88afce1f8b755fb36065992 | |
parent | efa1869dd78b2a4f7cef19e52a586a0b2bc2b0fb (diff) | |
parent | 9e8c9fc89934bfb88e93a2e8f87a7b12b2586e44 (diff) | |
download | sparse-7f33e55f0b4b011543a7e529331576429270b738.tar.gz |
Merge branch 'builtin-atomic' into next
* fix and complete the evaluation of atomic builtins
-rw-r--r-- | builtin.c | 114 | ||||
-rw-r--r-- | predefine.c | 7 | ||||
-rw-r--r-- | symbol.c | 6 | ||||
-rw-r--r-- | symbol.h | 2 | ||||
-rw-r--r-- | validation/builtin-atomic-clear.c | 15 | ||||
-rw-r--r-- | validation/builtin-sync-fetch.c | 24 |
6 files changed, 136 insertions, 32 deletions
@@ -31,6 +31,14 @@ #include "compat/bswap.h" #include <stdarg.h> +#define dyntype incomplete_ctype +static bool is_dynamic_type(struct symbol *t) +{ + if (t->type == SYM_NODE) + t = t->ctype.base_type; + return t == &dyntype; +} + static int evaluate_to_int_const_expr(struct expression *expr) { expr->ctype = &int_ctype; @@ -83,6 +91,13 @@ error: return 0; } +static int args_prototype(struct expression *expr) +{ + struct symbol *fntype = expr->fn->ctype->ctype.base_type; + int n = symbol_list_size(fntype->arguments); + return eval_args(expr, n); +} + static int args_triadic(struct expression *expr) { return eval_args(expr, 3); @@ -355,29 +370,32 @@ static struct symbol_op overflow_p_op = { }; -static int eval_sync_compare_and_swap(struct expression *expr) +static int eval_atomic_common(struct expression *expr) { + struct symbol *fntype = expr->fn->ctype->ctype.base_type; struct symbol_list *types = NULL; struct symbol *ctype = NULL; + struct symbol *t; struct expression *arg; int n = 0; - /* the first arg is a pointer type; we'd already verified that */ + // The number of arguments has already be verified. + // The first arg must be a pointer to an integral type. + PREPARE_PTR_LIST(fntype->arguments, t); FOR_EACH_PTR(expr->args, arg) { - struct symbol *t = arg->ctype; + struct symbol *ptrtype = NULL; - 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) { + t = arg->ctype; + if (!t) + return 0; if (t->type == SYM_NODE) t = t->ctype.base_type; if (!t) return 0; if (t->type != SYM_PTR) goto err; + ptrtype = t; t = t->ctype.base_type; if (!t) return 0; @@ -388,13 +406,18 @@ static int eval_sync_compare_and_swap(struct expression *expr) 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); + t = ptrtype; + } else if (is_dynamic_type(t)) { + t = ctype; + } else if (t == &ptr_ctype) { + t = ptrtype; } + add_ptr_list(&types, t); + NEXT_PTR_LIST(t); } END_FOR_EACH_PTR(arg); + FINISH_PTR_LIST(t); - if (!expr->ctype) // __sync_val_compare_and_swap() + if (!expr->ctype) // set the return type, if needed expr->ctype = ctype; return evaluate_arguments(types, expr->args); @@ -405,9 +428,9 @@ err: return 0; } -static struct symbol_op sync_compare_and_swap_op = { - .args = args_triadic, - .evaluate = eval_sync_compare_and_swap, +static struct symbol_op atomic_op = { + .args = args_prototype, + .evaluate = eval_atomic_common, }; @@ -457,6 +480,33 @@ static void declare_builtins(int stream, const struct builtin_fn tbl[]) static const struct builtin_fn builtins_common[] = { #define size_t_ctype &size_t_alias #define va_list_ctype &ptr_ctype +#define vol_ptr &volatile_ptr_ctype + { "__atomic_add_fetch", NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op }, + { "__atomic_always_lock_free", &bool_ctype, 0, { size_t_ctype, vol_ptr }}, + { "__atomic_and_fetch", NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op }, + { "__atomic_clear", &void_ctype, 0, { &volatile_bool_ptr_ctype, &int_ctype }}, + { "__atomic_compare_exchange", &bool_ctype, 0, { vol_ptr, &ptr_ctype, &ptr_ctype, &bool_ctype, &int_ctype, &int_ctype }, .op = &atomic_op }, + { "__atomic_compare_exchange_n", &bool_ctype, 0, { vol_ptr, &ptr_ctype, &dyntype, &bool_ctype, &int_ctype, &int_ctype }, .op = &atomic_op }, + { "__atomic_exchange", &void_ctype, 0, { vol_ptr, &ptr_ctype, &ptr_ctype, &int_ctype }, .op = &atomic_op }, + { "__atomic_exchange_n", NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op }, + { "__atomic_fetch_add", NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op }, + { "__atomic_fetch_and", NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op }, + { "__atomic_fetch_nand",NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op }, + { "__atomic_fetch_or", NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op }, + { "__atomic_fetch_sub", NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op }, + { "__atomic_fetch_xor", NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op }, + { "__atomic_is_lock_free", &bool_ctype, 0, { size_t_ctype, vol_ptr }}, + { "__atomic_load", &void_ctype, 0, { vol_ptr, &ptr_ctype, &int_ctype }, .op = &atomic_op }, + { "__atomic_load_n", NULL, 0, { vol_ptr, &int_ctype }, .op = &atomic_op }, + { "__atomic_nand_fetch",NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op }, + { "__atomic_or_fetch", NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op }, + { "__atomic_signal_fence", &void_ctype, 0, { &int_ctype }}, + { "__atomic_store", &void_ctype, 0, { vol_ptr, &ptr_ctype, &int_ctype }, .op = &atomic_op }, + { "__atomic_store_n", &void_ctype, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op }, + { "__atomic_sub_fetch", NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op }, + { "__atomic_test_and_set", &bool_ctype, 0, { vol_ptr, &int_ctype }}, + { "__atomic_thread_fence", &void_ctype, 0, { &int_ctype }}, + { "__atomic_xor_fetch", NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op }, { "__builtin_choose_expr", NULL, 1, .op = &choose_op }, { "__builtin_constant_p", NULL, 1, .op = &constant_p_op }, { "__builtin_expect", &long_ctype, 0, { &long_ctype ,&long_ctype }, .op = &expect_op }, @@ -605,23 +655,23 @@ static const struct builtin_fn builtins_common[] = { { "__builtin___vsnprintf_chk", &int_ctype, 0, { &string_ctype, size_t_ctype, &int_ctype, size_t_ctype, &const_string_ctype, va_list_ctype }}, { "__builtin___vsprintf_chk", &int_ctype, 0, { &string_ctype, &int_ctype, size_t_ctype, &const_string_ctype, va_list_ctype }}, - { "__sync_add_and_fetch", &int_ctype, 1, { &ptr_ctype }}, - { "__sync_and_and_fetch", &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 }}, - { "__sync_fetch_and_or", &int_ctype, 1, { &ptr_ctype }}, - { "__sync_fetch_and_sub", &int_ctype, 1, { &ptr_ctype }}, - { "__sync_fetch_and_xor", &int_ctype, 1, { &ptr_ctype }}, - { "__sync_lock_release", &void_ctype, 1, { &ptr_ctype }}, - { "__sync_lock_test_and_set", &int_ctype, 1, { &ptr_ctype }}, - { "__sync_nand_and_fetch", &int_ctype, 1, { &ptr_ctype }}, - { "__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", NULL, 1, { &ptr_ctype }, .op = &sync_compare_and_swap_op }, - { "__sync_xor_and_fetch", &int_ctype, 1, { &ptr_ctype }}, + { "__sync_add_and_fetch", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op }, + { "__sync_and_and_fetch", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op }, + { "__sync_bool_compare_and_swap", &bool_ctype, 1, { vol_ptr, &dyntype, &dyntype }, .op = &atomic_op}, + { "__sync_fetch_and_add", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op }, + { "__sync_fetch_and_and", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op }, + { "__sync_fetch_and_nand", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op }, + { "__sync_fetch_and_or", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op }, + { "__sync_fetch_and_sub", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op }, + { "__sync_fetch_and_xor", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op }, + { "__sync_lock_release", &void_ctype, 1, { vol_ptr }, .op = &atomic_op }, + { "__sync_lock_test_and_set", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op }, + { "__sync_nand_and_fetch", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op }, + { "__sync_or_and_fetch", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op }, + { "__sync_sub_and_fetch", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op }, + { "__sync_synchronize", &void_ctype, 1 }, + { "__sync_val_compare_and_swap", NULL, 1, { vol_ptr, &dyntype, &dyntype }, .op = &atomic_op }, + { "__sync_xor_and_fetch", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op }, { } }; diff --git a/predefine.c b/predefine.c index f898cdfa..98e38a04 100644 --- a/predefine.c +++ b/predefine.c @@ -179,6 +179,13 @@ void predefined_macros(void) if (arch_target->has_int128) predefined_sizeof("INT128", "", 128); + predefine("__ATOMIC_RELAXED", 0, "0"); + predefine("__ATOMIC_CONSUME", 0, "1"); + predefine("__ATOMIC_ACQUIRE", 0, "3"); + predefine("__ATOMIC_RELEASE", 0, "4"); + predefine("__ATOMIC_ACQ_REL", 0, "7"); + predefine("__ATOMIC_SEQ_CST", 0, "8"); + predefine("__ORDER_LITTLE_ENDIAN__", 1, "1234"); predefine("__ORDER_BIG_ENDIAN__", 1, "4321"); predefine("__ORDER_PDP_ENDIAN__", 1, "3412"); @@ -805,6 +805,8 @@ struct symbol float128_ctype; struct symbol const_void_ctype, const_char_ctype; struct symbol const_ptr_ctype, const_string_ctype; struct symbol const_wchar_ctype, const_wstring_ctype; +struct symbol volatile_void_ctype, volatile_ptr_ctype; +struct symbol volatile_bool_ctype, volatile_bool_ptr_ctype; struct symbol zero_int; @@ -909,6 +911,10 @@ static const struct ctype_declare { { &const_void_ctype, T_CONST(&void_ctype, NULL, NULL) }, { &const_char_ctype, T_CONST(&char_ctype, &bits_in_char, &max_int_alignment)}, { &const_wchar_ctype, T_CONST(&int_ctype, NULL, NULL) }, + { &volatile_void_ctype,T_NODE(MOD_VOLATILE, &void_ctype, NULL, NULL) }, + { &volatile_ptr_ctype, T_PTR(&volatile_void_ctype) }, + { &volatile_bool_ctype,T_NODE(MOD_VOLATILE, &bool_ctype, NULL, NULL) }, + { &volatile_bool_ptr_ctype, T_PTR(&volatile_bool_ctype) }, { NULL, } }; @@ -310,6 +310,8 @@ extern struct symbol float128_ctype; extern struct symbol const_void_ctype, const_char_ctype; extern struct symbol const_ptr_ctype, const_string_ctype; extern struct symbol const_wchar_ctype, const_wstring_ctype; +extern struct symbol volatile_void_ctype, volatile_ptr_ctype; +extern struct symbol volatile_bool_ctype, volatile_bool_ptr_ctype; /* Special internal symbols */ extern struct symbol zero_int; diff --git a/validation/builtin-atomic-clear.c b/validation/builtin-atomic-clear.c new file mode 100644 index 00000000..ef430c64 --- /dev/null +++ b/validation/builtin-atomic-clear.c @@ -0,0 +1,15 @@ +void foo(void *ptr, _Bool *bptr, volatile void *vptr, volatile _Bool *vbptr, int mo) +{ + __atomic_clear(ptr, mo); + __atomic_clear(bptr, mo); + __atomic_clear(vptr, mo); + __atomic_clear(vbptr, mo); +} + +/* + * check-name: builtin-atomic-clear + * + * check-error-start +builtin-atomic-clear.c:1:6: warning: symbol 'foo' was not declared. Should it be static? + * check-error-end + */ diff --git a/validation/builtin-sync-fetch.c b/validation/builtin-sync-fetch.c new file mode 100644 index 00000000..45139a3c --- /dev/null +++ b/validation/builtin-sync-fetch.c @@ -0,0 +1,24 @@ +static int ok_int(int *ptr, int val) +{ + return __sync_add_and_fetch(ptr, val); +} + +static long* ok_ptr(long **ptr, long *val) +{ + return __sync_add_and_fetch(ptr, val); +} + +static void chk_ret_ok(long *ptr, long val) +{ + _Static_assert([typeof(__sync_add_and_fetch(ptr, val))] == [long], ""); +} + +static int chk_val(int *ptr, long val) +{ + // OK: val is converted to an int + return __sync_add_and_fetch(ptr, val); +} + +/* + * check-name: builtin-sync-fetch + */ |