diff --git a/include/stdatomic.h b/include/stdatomic.h index ebec3e1c..b910d128 100644 --- a/include/stdatomic.h +++ b/include/stdatomic.h @@ -72,57 +72,59 @@ typedef struct { #define ATOMIC_FLAG_INIT {0} #define atomic_flag_test_and_set(object) \ - __c11_atomic_exchange(&(object)->value, 1, __ATOMIC_SEQ_CST) + __atomic_exchange(&(object)->value, 1, __ATOMIC_SEQ_CST) #define atomic_flag_test_and_set_explicit(object, order) \ - __c11_atomic_exchange(&(object)->value, 1, order) + __atomic_exchange(&(object)->value, 1, order) #define atomic_flag_clear(object) \ - __c11_atomic_store(&(object)->value, 0, __ATOMIC_SEQ_CST) + __atomic_store(&(object)->value, 0, __ATOMIC_SEQ_CST) #define atomic_flag_clear_explicit(object, order) \ - __c11_atomic_store(&(object)->value, 0, order) + __atomic_store(&(object)->value, 0, order) /* Generic routines */ #define atomic_init(object, desired) \ - __c11_atomic_init(object, desired) + __atomic_store(object, desired, __ATOMIC_RELAXED) #define atomic_store(object, desired) \ - __c11_atomic_store(object, desired, __ATOMIC_SEQ_CST) -#define atomic_store_explicit __c11_atomic_store + __atomic_store(object, desired, __ATOMIC_SEQ_CST) +#define atomic_store_explicit __atomic_store #define atomic_load(object) \ - __c11_atomic_load(object, __ATOMIC_SEQ_CST) -#define atomic_load_explicit __c11_atomic_load + __atomic_load(object, __ATOMIC_SEQ_CST) +#define atomic_load_explicit __atomic_load #define atomic_exchange(object, desired) \ - __c11_atomic_exchange(object, desired, __ATOMIC_SEQ_CST) -#define atomic_exchange_explicit __c11_atomic_exchange + __atomic_exchange(object, desired, __ATOMIC_SEQ_CST) +#define atomic_exchange_explicit __atomic_exchange #define atomic_compare_exchange_strong(object, expected, desired) \ - __c11_atomic_compare_exchange_strong(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) -#define atomic_compare_exchange_strong_explicit __c11_atomic_compare_exchange_strong + __atomic_compare_exchange(object, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) +#define atomic_compare_exchange_strong_explicit(object, expected, desired, success, failure) \ + __atomic_compare_exchange(object, expected, desired, 0, success, failure) #define atomic_compare_exchange_weak(object, expected, desired) \ - __c11_atomic_compare_exchange_weak(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) -#define atomic_compare_exchange_weak_explicit __c11_atomic_compare_exchange_weak + __atomic_compare_exchange(object, expected, desired, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) +#define atomic_compare_exchange_weak_explicit(object, expected, desired, success, failure) \ + __atomic_compare_exchange(object, expected, desired, 1, success, failure) #define atomic_fetch_add(object, operand) \ - __c11_atomic_fetch_add(object, operand, __ATOMIC_SEQ_CST) -#define atomic_fetch_add_explicit __c11_atomic_fetch_add + __atomic_fetch_add(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_add_explicit __atomic_fetch_add #define atomic_fetch_sub(object, operand) \ - __c11_atomic_fetch_sub(object, operand, __ATOMIC_SEQ_CST) -#define atomic_fetch_sub_explicit __c11_atomic_fetch_sub + __atomic_fetch_sub(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_sub_explicit __atomic_fetch_sub #define atomic_fetch_or(object, operand) \ - __c11_atomic_fetch_or(object, operand, __ATOMIC_SEQ_CST) -#define atomic_fetch_or_explicit __c11_atomic_fetch_or + __atomic_fetch_or(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_or_explicit __atomic_fetch_or #define atomic_fetch_xor(object, operand) \ - __c11_atomic_fetch_xor(object, operand, __ATOMIC_SEQ_CST) -#define atomic_fetch_xor_explicit __c11_atomic_fetch_xor + __atomic_fetch_xor(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_xor_explicit __atomic_fetch_xor #define atomic_fetch_and(object, operand) \ - __c11_atomic_fetch_and(object, operand, __ATOMIC_SEQ_CST) -#define atomic_fetch_and_explicit __c11_atomic_fetch_and + __atomic_fetch_and(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_and_explicit __atomic_fetch_and #endif /* _STDATOMIC_H */ diff --git a/tccgen.c b/tccgen.c index 31c4f472..545369bd 100644 --- a/tccgen.c +++ b/tccgen.c @@ -5755,94 +5755,86 @@ static inline int is_memory_model(const SValue *sv) * Ideally we should check whether the model matches 1:1. * If it is possible, we should check by the name of the value. */ - return (((sv->type.t & VT_BTYPE) == VT_INT) && (sv->c.i < 6)); + return 1; } +#define ATOMIC_ID(ATOK) \ + (ATOK - TOK___atomic_store) + static void parse_atomic(int atok) { - size_t op; + int mode; size_t arg; - size_t argc; - CType *atom = NULL; - char const *params = NULL; - static struct { - int const tok; - char const *const params; - } const ops[] = { + SValue *call; + CType atom = {}; + static const char const *templates[] = { /* - * a -- atomic - * A -- read-only atomic - * p -- pointer to memory - * P -- pointer to read-only memory - * v -- value - * m -- memory model + * Each entry consists of callback and function template. + * The template represents argument types and return type. + * + * ? void (return-only) + * b bool + * a atomic + * A read-only atomic + * p pointer to memory + * v value + * m memory model */ - {TOK___c11_atomic_init, "-av"}, - {TOK___c11_atomic_store, "-avm"}, - {TOK___c11_atomic_load, "am"}, - {TOK___c11_atomic_exchange, "avm"}, - {TOK___c11_atomic_compare_exchange_strong, "apvmm"}, - {TOK___c11_atomic_compare_exchange_weak, "apvmm"}, - {TOK___c11_atomic_fetch_add, "avm"}, - {TOK___c11_atomic_fetch_sub, "avm"}, - {TOK___c11_atomic_fetch_or, "avm"}, - {TOK___c11_atomic_fetch_xor, "avm"}, - {TOK___c11_atomic_fetch_and, "avm"}, + [ATOMIC_ID(TOK___atomic_store)] = "avm?", + [ATOMIC_ID(TOK___atomic_load)] = "Amv", + [ATOMIC_ID(TOK___atomic_exchange)] = "avmv", + [ATOMIC_ID(TOK___atomic_compare_exchange)] = "apvbmmb", + [ATOMIC_ID(TOK___atomic_fetch_add)] = "avmv", + [ATOMIC_ID(TOK___atomic_fetch_sub)] = "avmv", + [ATOMIC_ID(TOK___atomic_fetch_or)] = "avmv", + [ATOMIC_ID(TOK___atomic_fetch_xor)] = "avmv", + [ATOMIC_ID(TOK___atomic_fetch_and)] = "avmv", }; + const char *template = templates[ATOMIC_ID(atok)]; + const size_t argc = (strlen(template) - 1); next(); - for (op = 0; op < (sizeof(ops) / sizeof(*ops)); ++op) { - if (ops[op].tok == atok) { - params = ops[op].params; - break; - } - } - if (!params) - tcc_error("unknown atomic operation"); - - argc = strlen(params); - if (params[0] == '-') { - ++params; - --argc; - } - - vpushi(0); - vpushi(0); /* function address */ + vpush_helper_func(atok); + call = vtop; skip('('); + if ((*template != 'a') && (*template != 'A')) + expect_arg("pointer to atomic", 0); for (arg = 0; arg < argc; ++arg) { expr_eq(); - switch (params[arg]) { + switch (template[arg]) { + case '?': + /* void makes sense only for return value. */ + if (arg != (argc - 1)) + tcc_error("illegal atomic built-in template"); + break; + + case 'b': + break; + case 'a': case 'A': - if (atom) - expect_arg("exactly one pointer to atomic", arg); if ((vtop->type.t & VT_BTYPE) != VT_PTR) - expect_arg("pointer to atomic expected", arg); - atom = pointed_type(&vtop->type); - if (!(atom->t & VT_ATOMIC)) - expect_arg("qualified pointer to atomic", arg); - if ((params[arg] == 'a') && (atom->t & VT_CONSTANT)) + expect_arg("pointer to atomic value", arg); + memcpy(&atom, pointed_type(&vtop->type), sizeof(CType)); + if (!(atom.t & VT_ATOMIC)) + expect_arg("qualified pointer to atomic value", arg); + if ((template[arg] == 'a') && (atom.t & VT_CONSTANT)) expect_arg("pointer to writable atomic", arg); - atom->t &= ~VT_ATOMIC; - switch (btype_size(atom->t & VT_BTYPE)) { - case 1: atok += 1; break; - case 2: atok += 2; break; - case 4: atok += 3; break; - case 8: atok += 4; break; + switch (btype_size(atom.t & VT_BTYPE)) { + case 8: mode = 4; break; + case 4: mode = 3; break; + case 2: mode = 2; break; + case 1: mode = 1; break; default: tcc_error("only integer-sized types are supported"); } - vswap(); - vpop(); - vpush_helper_func(atok); - vswap(); break; case 'p': if (((vtop->type.t & VT_BTYPE) != VT_PTR) - || !is_compatible_unqualified_types(atom, pointed_type(&vtop->type))) + || !is_compatible_unqualified_types(&atom, pointed_type(&vtop->type))) expect_arg("pointer to compatible type", arg); break; @@ -5870,7 +5862,17 @@ static void parse_atomic(int atok) expect("less parameters"); skip(')'); + call->sym = external_helper_sym(atok + mode); gfunc_call(argc); + vpushi(0); + + switch (template[argc]) { + case 'b': PUT_R_RET(vtop, VT_BOOL); break; + case 'v': PUT_R_RET(vtop, atom.t); break; + case 'p': PUT_R_RET(vtop, VT_SIZE_T); break; + case '?': PUT_R_RET(vtop, VT_VOID); break; + default: tcc_error("incorrect atomic template"); + } } ST_FUNC void unary(void) @@ -6255,17 +6257,15 @@ ST_FUNC void unary(void) #endif /* atomic operations */ - case TOK___c11_atomic_init: - case TOK___c11_atomic_store: - case TOK___c11_atomic_load: - case TOK___c11_atomic_exchange: - case TOK___c11_atomic_compare_exchange_strong: - case TOK___c11_atomic_compare_exchange_weak: - case TOK___c11_atomic_fetch_add: - case TOK___c11_atomic_fetch_sub: - case TOK___c11_atomic_fetch_or: - case TOK___c11_atomic_fetch_xor: - case TOK___c11_atomic_fetch_and: + case TOK___atomic_store: + case TOK___atomic_load: + case TOK___atomic_exchange: + case TOK___atomic_compare_exchange: + case TOK___atomic_fetch_add: + case TOK___atomic_fetch_sub: + case TOK___atomic_fetch_or: + case TOK___atomic_fetch_xor: + case TOK___atomic_fetch_and: parse_atomic(tok); break; diff --git a/tcctok.h b/tcctok.h index 0fe3a8f1..a5d893e1 100644 --- a/tcctok.h +++ b/tcctok.h @@ -174,25 +174,23 @@ DEF(TOK_builtin_va_start, "__builtin_va_start") #endif -#define DEF_ATOMIC(id, str) \ - DEF(id, str) \ - DEF(id##_8, str "_8") \ - DEF(id##_16, str "_16") \ - DEF(id##_32, str "_32") \ - DEF(id##_64, str "_64") - /* atomic operations */ - DEF_ATOMIC(TOK___c11_atomic_init, "__c11_atomic_init") - DEF_ATOMIC(TOK___c11_atomic_store, "__c11_atomic_store") - DEF_ATOMIC(TOK___c11_atomic_load, "__c11_atomic_load") - DEF_ATOMIC(TOK___c11_atomic_exchange, "__c11_atomic_exchange") - DEF_ATOMIC(TOK___c11_atomic_compare_exchange_strong, "__c11_atomic_compare_exchange_strong") - DEF_ATOMIC(TOK___c11_atomic_compare_exchange_weak, "__c11_atomic_compare_exchange_weak") - DEF_ATOMIC(TOK___c11_atomic_fetch_add, "__c11_atomic_fetch_add") - DEF_ATOMIC(TOK___c11_atomic_fetch_sub, "__c11_atomic_fetch_sub") - DEF_ATOMIC(TOK___c11_atomic_fetch_or, "__c11_atomic_fetch_or") - DEF_ATOMIC(TOK___c11_atomic_fetch_xor, "__c11_atomic_fetch_xor") - DEF_ATOMIC(TOK___c11_atomic_fetch_and, "__c11_atomic_fetch_and") +#define DEF_ATOMIC(ID) \ + DEF(TOK_##__##ID, "__"#ID) \ + DEF(TOK_##__##ID##_1, "__"#ID"_1") \ + DEF(TOK_##__##ID##_2, "__"#ID"_2") \ + DEF(TOK_##__##ID##_4, "__"#ID"_4") \ + DEF(TOK_##__##ID##_8, "__"#ID"_8") + + DEF_ATOMIC(atomic_store) + DEF_ATOMIC(atomic_load) + DEF_ATOMIC(atomic_exchange) + DEF_ATOMIC(atomic_compare_exchange) + DEF_ATOMIC(atomic_fetch_add) + DEF_ATOMIC(atomic_fetch_sub) + DEF_ATOMIC(atomic_fetch_or) + DEF_ATOMIC(atomic_fetch_xor) + DEF_ATOMIC(atomic_fetch_and) #undef DEF_ATOMIC