Be aware that we support many platforms. For atomic is probably means dedicated code for i386/x86_64/arm/arm64/riscv. C. From: Dmitry Selyutin [mailto:ghostman.sd@gmail.com] Sent: Tuesday, January 26, 2021 22:03 To: jullien@eligis.com Cc: tinycc-devel@nongnu.org Subject: Re: [Tinycc-devel] [PATCH 1/3] stdatomic: atomic builtins parsing support Yes, I was thinking of implementing tests which can at least check whether the compiler emits the relevant calls. I'm not sure how to check the future implementation, though; there is no -fsanitize=threads, and I have yet to check whether tcc works with valgrind correctly. As well as for the code generator, the tests suite is another area I still have to check. It's been two evenings only since I started checking the code base, I have yet much to learn. :-) Do you plan to add tests? If would be nice.
Tia
Christian
-----Original Message----- From: Tinycc-devel [mailto:tinycc-devel-bounces+eligis=orange.fr@nongnu.org] On Behalf Of Dmitry Selyutin Sent: Tuesday, January 26, 2021 21:46 To: tinycc-devel@nongnu.org Subject: [Tinycc-devel] [PATCH 1/3] stdatomic: atomic builtins parsing support
Dear all,
I'm one of tcc users; thank you for this wonderful compiler! Recently I decided that it'd be great to contribute to the project, and one of the things I found missing is stdatomic.h support. For now I've implemented the very basic parts required on the syntax side; all atomic intrinsics currently is supposed to emit a call to the internal function, based on the type of the arguments.
Since I'm new to tcc code, some parts can certainly be improved; I'd be glad to know your remarks and opinion. If you find these patches useful, please let me know.
I'm not entirely sure of the approach with internal calls; it seems reasonable to generate the assembly instead. However, I haven't checked the assembly code generation yet; any tips and suggestions are welcome.
P.S. The code is also available at stdatomic branch.
--- tcc.h | 4 ++ tccgen.c | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ tccpp.c | 5 ++ tcctok.h | 22 ++++++++ 4 files changed, 184 insertions(+)
diff --git a/tcc.h b/tcc.h index 7879d6e..691f649 100644 --- a/tcc.h +++ b/tcc.h @@ -1051,6 +1051,9 @@ struct filespec { #define IS_ENUM_VAL(t) ((t & VT_STRUCT_MASK) == VT_ENUM_VAL) #define IS_UNION(t) ((t & (VT_STRUCT_MASK|VT_BTYPE)) == VT_UNION)
+#define VT_ATOMIC VT_VOLATILE +#define VT_MEMMODEL (VT_STATIC | VT_ENUM_VAL | VT_TYPEDEF) + /* type mask (except storage) */ #define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE) #define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK)) @@ -1418,6 +1421,7 @@ ST_FUNC void tccpp_delete(TCCState *s); ST_FUNC int tcc_preprocess(TCCState *s1); ST_FUNC void skip(int c); ST_FUNC NORETURN void expect(const char *msg); +ST_FUNC NORETURN void expect_arg(const char *msg, size_t arg);
/* space excluding newline */ static inline int is_space(int ch) { diff --git a/tccgen.c b/tccgen.c index 1f1af70..86b0e86 100644 --- a/tccgen.c +++ b/tccgen.c @@ -5160,6 +5160,20 @@ static int parse_btype(CType *type, AttributeDef *ad) goto basic_type2;
/* type modifiers */ + case TOK__Atomic: + next(); + type->t = t; + parse_btype_qualify(type, VT_ATOMIC); + t = type->t; + if (tok == '(') { + parse_expr_type(&type1); + /* remove all storage modifiers except typedef */ + type1.t &= ~(VT_STORAGE&~VT_TYPEDEF); + if (type1.ref) + sym_to_attr(ad, type1.ref); + goto basic_type2; + } + break; case TOK_CONST1: case TOK_CONST2: case TOK_CONST3: @@ -5515,6 +5529,9 @@ static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td) redo: next(); switch(tok) { + case TOK__Atomic: + qualifiers |= VT_ATOMIC; + goto redo; case TOK_CONST1: case TOK_CONST2: case TOK_CONST3: @@ -5710,6 +5727,117 @@ static void parse_builtin_params(int nc, const char *args) nocode_wanted--; }
+static void parse_memory_model(int mtok) +{ + next(); + + switch (mtok) { + case TOK___ATOMIC_RELAXED: vpushs(0); break; + case TOK___ATOMIC_CONSUME: vpushs(1); break; + case TOK___ATOMIC_ACQUIRE: vpushs(2); break; + case TOK___ATOMIC_RELEASE: vpushs(3); break; + case TOK___ATOMIC_ACQ_REL: vpushs(4); break; + case TOK___ATOMIC_SEQ_CST: vpushs(5); break; + } + + vtop->type.t |= (VT_UNSIGNED | VT_MEMMODEL); +} + +static void parse_atomic(int atok) +{ + size_t arg; + size_t argc; + int param; + char const *params; + CType *atom = NULL; + + next(); + + /* + * a -- atomic + * A -- read-only atomic + * p -- pointer to memory + * P -- pointer to read-only memory + * v -- value + * m -- memory model + */ + switch (atok) { + case TOK___atomic_init: params = "-a"; break; + case TOK___atomic_store: params = "-avm"; break; + case TOK___atomic_load: params = "am"; break; + case TOK___atomic_exchange: params = "avm"; break; + case TOK___atomic_compare_exchange_strong: params = "apvmm"; break; + case TOK___atomic_compare_exchange_weak: params = "apvmm"; break; + case TOK___atomic_fetch_add: params = "avm"; break; + case TOK___atomic_fetch_sub: params = "avm"; break; + case TOK___atomic_fetch_or: params = "avm"; break; + case TOK___atomic_fetch_xor: params = "avm"; break; + case TOK___atomic_fetch_and: params = "avm"; break; + } + + argc = strlen(params); + if (params[0] == '-') { + ++params; + --argc; + } + + skip('('); + for (arg = 0; arg < argc; ++arg) { + expr_eq(); + + param = params[arg]; + switch (param) { + 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 ((param == 'a') && (atom->t & VT_CONSTANT)) + expect_arg("pointer to writable atomic", arg); + if (!is_integer_btype(atom->t & VT_BTYPE)) + expect_arg("only atomic integers are supported", arg); + atom->t &= ~VT_ATOMIC; + break; + + case 'p': + if (((vtop->type.t & VT_BTYPE) != VT_PTR) + || !is_compatible_unqualified_types(atom, pointed_type(&vtop->type))) + expect_arg("pointer to compatible type", arg); + break; + + case 'v': + if (!is_integer_btype(vtop->type.t & VT_BTYPE)) + expect_arg("only atomic integers are supported", arg); + break; + + case 'm': + if ((vtop->type.t & VT_MEMMODEL) != VT_MEMMODEL) + expect_arg("memory model constant", arg); + vtop->type.t &= ~VT_MEMMODEL; + break; + + default: + tcc_error("unknown parameter type"); + } + if (tok == ')') + break; + skip(','); + } + if (arg < (argc - 1)) + expect("more parameters"); + if (arg > (argc - 1)) + expect("less parameters"); + skip(')'); + + for (arg = 0; arg < (argc - 1); ++arg) + vpop(); + tcc_error("atomics are not supported yet"); +} + ST_FUNC void unary(void) { int n, t, align, size, r, sizeof_caller; @@ -6086,6 +6214,31 @@ ST_FUNC void unary(void) } #endif
+ /* memory models */ + case TOK___ATOMIC_RELAXED: + case TOK___ATOMIC_CONSUME: + case TOK___ATOMIC_ACQUIRE: + case TOK___ATOMIC_RELEASE: + case TOK___ATOMIC_ACQ_REL: + case TOK___ATOMIC_SEQ_CST: + parse_memory_model(tok); + break; + + /* atomic operations */ + case TOK___atomic_init: + case TOK___atomic_store: + case TOK___atomic_load: + case TOK___atomic_exchange: + case TOK___atomic_compare_exchange_strong: + case TOK___atomic_compare_exchange_weak: + 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; + /* pre operations */ case TOK_INC: case TOK_DEC: diff --git a/tccpp.c b/tccpp.c index b21210d..20328a1 100644 --- a/tccpp.c +++ b/tccpp.c @@ -107,6 +107,11 @@ ST_FUNC void expect(const char *msg) tcc_error("%s expected", msg); }
+ST_FUNC void expect_arg(const char *msg, size_t arg) +{ + tcc_error("%s expected as arg #%zu", msg, arg); +} + /* ------------------------------------------------------------------------- */ /* Custom allocator for tiny objects */
diff --git a/tcctok.h b/tcctok.h index 390eca3..3ac525e 100644 --- a/tcctok.h +++ b/tcctok.h @@ -17,6 +17,7 @@ DEF(TOK_SWITCH, "switch") DEF(TOK_CASE, "case")
+ DEF(TOK__Atomic, "_Atomic") DEF(TOK_CONST1, "const") DEF(TOK_CONST2, "__const") /* gcc keyword */ DEF(TOK_CONST3, "__const__") /* gcc keyword */ @@ -173,6 +174,27 @@ DEF(TOK_builtin_va_start, "__builtin_va_start") #endif
+/* memory models */ + DEF(TOK___ATOMIC_RELAXED, "__ATOMIC_RELAXED") + DEF(TOK___ATOMIC_CONSUME, "__ATOMIC_CONSUME") + DEF(TOK___ATOMIC_ACQUIRE, "__ATOMIC_ACQUIRE") + DEF(TOK___ATOMIC_RELEASE, "__ATOMIC_RELEASE") + DEF(TOK___ATOMIC_ACQ_REL, "__ATOMIC_ACQ_REL") + DEF(TOK___ATOMIC_SEQ_CST, "__ATOMIC_SEQ_CST") + +/* atomic operations */ + DEF(TOK___atomic_init, "__atomic_init") + DEF(TOK___atomic_store, "__atomic_store") + DEF(TOK___atomic_load, "__atomic_load") + DEF(TOK___atomic_exchange, "__atomic_exchange") + DEF(TOK___atomic_compare_exchange_strong, "__atomic_compare_exchange_strong") + DEF(TOK___atomic_compare_exchange_weak, "__atomic_compare_exchange_weak") + DEF(TOK___atomic_fetch_add, "__atomic_fetch_add") + DEF(TOK___atomic_fetch_sub, "__atomic_fetch_sub") + DEF(TOK___atomic_fetch_or, "__atomic_fetch_or") + DEF(TOK___atomic_fetch_xor, "__atomic_fetch_xor") + DEF(TOK___atomic_fetch_and, "__atomic_fetch_and") + /* pragma */ DEF(TOK_pack, "pack") #if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_X86_64) && \ -- 2.30.0
-- Best regards, Dmitry Selyutin
_______________________________________________ Tinycc-devel mailing list Tinycc-devel@nongnu.org https://lists.nongnu.org/mailman/listinfo/tinycc-devel
|