tinycc-devel
[Top][All Lists]
Advanced

[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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]