A small note on "-" sign at the mapping table. It's not used yet for any real purpose; I've been thinking of re-using it as marker to determine whether the function returns the underlying type or returns void.
вт, 26 янв. 2021 г., 23:46 Dmitry Selyutin <ghostman...@gmail.com>: > 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