[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Tinycc-devel] [PATCH 1/3] stdatomic: atomic builtins parsing support
From: |
Dmitry Selyutin |
Subject: |
[Tinycc-devel] [PATCH 1/3] stdatomic: atomic builtins parsing support |
Date: |
Tue, 26 Jan 2021 23:46:08 +0300 |
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] [PATCH 1/3] stdatomic: atomic builtins parsing support,
Dmitry Selyutin <=