stdatomic: atomic builtins parsing support

This commit is contained in:
Dmitry Selyutin 2021-01-26 16:29:07 +03:00
parent 557b4a1f6d
commit a110287c31
4 changed files with 184 additions and 0 deletions

4
tcc.h
View file

@ -1051,6 +1051,9 @@ struct filespec {
#define IS_ENUM_VAL(t) ((t & VT_STRUCT_MASK) == VT_ENUM_VAL) #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 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) */ /* type mask (except storage) */
#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE) #define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE)
#define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK)) #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 int tcc_preprocess(TCCState *s1);
ST_FUNC void skip(int c); ST_FUNC void skip(int c);
ST_FUNC NORETURN void expect(const char *msg); ST_FUNC NORETURN void expect(const char *msg);
ST_FUNC NORETURN void expect_arg(const char *msg, size_t arg);
/* space excluding newline */ /* space excluding newline */
static inline int is_space(int ch) { static inline int is_space(int ch) {

153
tccgen.c
View file

@ -5160,6 +5160,20 @@ static int parse_btype(CType *type, AttributeDef *ad)
goto basic_type2; goto basic_type2;
/* type modifiers */ /* 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_CONST1:
case TOK_CONST2: case TOK_CONST2:
case TOK_CONST3: case TOK_CONST3:
@ -5515,6 +5529,9 @@ static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td)
redo: redo:
next(); next();
switch(tok) { switch(tok) {
case TOK__Atomic:
qualifiers |= VT_ATOMIC;
goto redo;
case TOK_CONST1: case TOK_CONST1:
case TOK_CONST2: case TOK_CONST2:
case TOK_CONST3: case TOK_CONST3:
@ -5710,6 +5727,117 @@ static void parse_builtin_params(int nc, const char *args)
nocode_wanted--; 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) ST_FUNC void unary(void)
{ {
int n, t, align, size, r, sizeof_caller; int n, t, align, size, r, sizeof_caller;
@ -6086,6 +6214,31 @@ ST_FUNC void unary(void)
} }
#endif #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 */ /* pre operations */
case TOK_INC: case TOK_INC:
case TOK_DEC: case TOK_DEC:

View file

@ -107,6 +107,11 @@ ST_FUNC void expect(const char *msg)
tcc_error("%s expected", 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 */ /* Custom allocator for tiny objects */

View file

@ -17,6 +17,7 @@
DEF(TOK_SWITCH, "switch") DEF(TOK_SWITCH, "switch")
DEF(TOK_CASE, "case") DEF(TOK_CASE, "case")
DEF(TOK__Atomic, "_Atomic")
DEF(TOK_CONST1, "const") DEF(TOK_CONST1, "const")
DEF(TOK_CONST2, "__const") /* gcc keyword */ DEF(TOK_CONST2, "__const") /* gcc keyword */
DEF(TOK_CONST3, "__const__") /* gcc keyword */ DEF(TOK_CONST3, "__const__") /* gcc keyword */
@ -173,6 +174,27 @@
DEF(TOK_builtin_va_start, "__builtin_va_start") DEF(TOK_builtin_va_start, "__builtin_va_start")
#endif #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 */ /* pragma */
DEF(TOK_pack, "pack") DEF(TOK_pack, "pack")
#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_X86_64) && \ #if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_X86_64) && \