tinycc-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Tinycc-devel] [PATCH] stdatomic: i386/x86_64 support


From: Dmitry Selyutin
Subject: [Tinycc-devel] [PATCH] stdatomic: i386/x86_64 support
Date: Wed, 17 Mar 2021 00:48:23 +0300

Here is an alternative way to implement support for atomics, this time via
inline assembler and macros (ab)use. The main idea is that we can implement
most of the atomic operations via cmpxchg. The only exception is atomic_load
routine, which should not update the value, according to its prototype. This
patch also makes such an assumption for atomic_store routine, even though it is
possible to implement it via cmpxchg as well. With this patch, most of the
atomic routines are generated in an architecture-agnostic way, unless some
specific architecture explicitly desires to override such behavior.

This patch provides a simple and somewhat hacky implementation for i386; x86_64
basically takes this implementation and adds three routines atop of it.

I'd like to discuss this code; there are parts I don't particularly like,
for example, the inclusion of C source code via preprocessor directives.

Ideas and remarks are welcome, as usual.

---
 lib/Makefile        |  4 ++--
 lib/atomic-gen32.c  | 25 +++++++++++++++++++++++++
 lib/atomic-gen64.c  |  8 ++++++++
 lib/atomic-i386.c   | 19 +++++++++++++++++++
 lib/atomic-x86.h    | 31 +++++++++++++++++++++++++++++++
 lib/atomic-x86_64.c | 12 ++++++++++++
 lib/atomic.h        | 39 +++++++++++++++++++++++++++++++++++++++
 7 files changed, 136 insertions(+), 2 deletions(-)
 create mode 100644 lib/atomic-gen32.c
 create mode 100644 lib/atomic-gen64.c
 create mode 100644 lib/atomic-i386.c
 create mode 100644 lib/atomic-x86.h
 create mode 100644 lib/atomic-x86_64.c
 create mode 100644 lib/atomic.h

diff --git a/lib/Makefile b/lib/Makefile
index 9121d33..fe2fd32 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -42,8 +42,8 @@ $(X)BT_O += tcov.o

 DSO_O = dsohandle.o

-I386_O = libtcc1.o alloca86.o alloca86-bt.o $(BT_O)
-X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o $(BT_O)
+I386_O = libtcc1.o alloca86.o alloca86-bt.o $(BT_O) atomic-i386.o
+X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o $(BT_O) atomic-x86_64.o
 ARM_O = libtcc1.o armeabi.o alloca-arm.o armflush.o fetch_and_add_arm.o $(BT_O)
 ARM64_O = lib-arm64.o fetch_and_add_arm64.o $(BT_O)
 RISCV64_O = lib-arm64.o fetch_and_add_riscv64.o $(BT_O)
diff --git a/lib/atomic-gen32.c b/lib/atomic-gen32.c
new file mode 100644
index 0000000..64575cd
--- /dev/null
+++ b/lib/atomic-gen32.c
@@ -0,0 +1,25 @@
+#include "atomic.h"
+
+ATOMIC_EXCHANGE(uint8_t, 1)
+ATOMIC_EXCHANGE(uint16_t, 2)
+ATOMIC_EXCHANGE(uint32_t, 4)
+
+ATOMIC_FETCH_ADD(uint8_t, 1)
+ATOMIC_FETCH_ADD(uint16_t, 2)
+ATOMIC_FETCH_ADD(uint32_t, 4)
+
+ATOMIC_FETCH_SUB(uint8_t, 1)
+ATOMIC_FETCH_SUB(uint16_t, 2)
+ATOMIC_FETCH_SUB(uint32_t, 4)
+
+ATOMIC_FETCH_AND(uint8_t, 1)
+ATOMIC_FETCH_AND(uint16_t, 2)
+ATOMIC_FETCH_AND(uint32_t, 4)
+
+ATOMIC_FETCH_OR(uint8_t, 1)
+ATOMIC_FETCH_OR(uint16_t, 2)
+ATOMIC_FETCH_OR(uint32_t, 4)
+
+ATOMIC_FETCH_XOR(uint8_t, 1)
+ATOMIC_FETCH_XOR(uint16_t, 2)
+ATOMIC_FETCH_XOR(uint32_t, 4)
diff --git a/lib/atomic-gen64.c b/lib/atomic-gen64.c
new file mode 100644
index 0000000..edd8263
--- /dev/null
+++ b/lib/atomic-gen64.c
@@ -0,0 +1,8 @@
+#include "atomic.h"
+
+ATOMIC_EXCHANGE(uint64_t, 8)
+ATOMIC_FETCH_ADD(uint64_t, 8)
+ATOMIC_FETCH_SUB(uint64_t, 8)
+ATOMIC_FETCH_AND(uint64_t, 8)
+ATOMIC_FETCH_OR(uint64_t, 8)
+ATOMIC_FETCH_XOR(uint64_t, 8)
diff --git a/lib/atomic-i386.c b/lib/atomic-i386.c
new file mode 100644
index 0000000..ca8b2a4
--- /dev/null
+++ b/lib/atomic-i386.c
@@ -0,0 +1,19 @@
+#pragma once
+
+#include <stdint.h>
+
+#include "atomic-x86.h"
+
+ATOMIC_X86_STORE(uint8_t, 1)
+ATOMIC_X86_STORE(uint16_t, 2)
+ATOMIC_X86_STORE(uint32_t, 4)
+
+ATOMIC_X86_LOAD(uint8_t, 1)
+ATOMIC_X86_LOAD(uint16_t, 2)
+ATOMIC_X86_LOAD(uint32_t, 4)
+
+ATOMIC_X86_COMPARE_EXCHANGE(uint8_t, 1, "b")
+ATOMIC_X86_COMPARE_EXCHANGE(uint16_t, 2, "w")
+ATOMIC_X86_COMPARE_EXCHANGE(uint32_t, 4, "l")
+
+#include "atomic-gen32.c"
diff --git a/lib/atomic-x86.h b/lib/atomic-x86.h
new file mode 100644
index 0000000..ad4e1f0
--- /dev/null
+++ b/lib/atomic-x86.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define ATOMIC_X86_COMPARE_EXCHANGE(TYPE, MODE, SUFFIX) \
+    bool __atomic_compare_exchange_##MODE(_Atomic(TYPE) *atom, TYPE
*ref, TYPE xchg) \
+    { \
+        TYPE rv; \
+        TYPE cmp = *ref; \
+        asm volatile( \
+            "lock cmpxchg" SUFFIX " %2,%1\n" \
+            : "=a" (rv), "+m" (*atom) \
+            : "q" (xchg), "0" (cmp) \
+            : "memory" \
+        ); \
+        *ref = rv; \
+        return (rv == cmp); \
+    }
+
+#define ATOMIC_X86_LOAD(TYPE, MODE) \
+    TYPE __atomic_load_##MODE(const _Atomic(TYPE) *atom) \
+    { \
+        return *(volatile TYPE *)atom; \
+    }
+
+#define ATOMIC_X86_STORE(TYPE, MODE) \
+    void __atomic_store_##MODE(_Atomic(TYPE) *atom, TYPE value) \
+    { \
+        *(volatile TYPE *)atom = value; \
+    }
diff --git a/lib/atomic-x86_64.c b/lib/atomic-x86_64.c
new file mode 100644
index 0000000..974615d
--- /dev/null
+++ b/lib/atomic-x86_64.c
@@ -0,0 +1,12 @@
+#pragma once
+
+#include <stdint.h>
+
+#include "atomic-x86.h"
+#include "atomic-i386.c"
+
+ATOMIC_X86_STORE(uint64_t, 8)
+ATOMIC_X86_LOAD(uint64_t, 8)
+ATOMIC_X86_COMPARE_EXCHANGE(uint64_t, 8, "q")
+
+#include "atomic-gen64.c"
diff --git a/lib/atomic.h b/lib/atomic.h
new file mode 100644
index 0000000..6c9190a
--- /dev/null
+++ b/lib/atomic.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define ATOMIC_GEN_OP(TYPE, MODE, NAME, OP) \
+    TYPE __atomic_##NAME##_##MODE(_Atomic(TYPE) *atom, TYPE value) \
+    { \
+        TYPE xchg; \
+        TYPE cmp = __atomic_load(atom, __ATOMIC_RELAXED); \
+        do { \
+            xchg = (OP); \
+        } while (!__atomic_compare_exchange(atom, &cmp, xchg, true,
__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)); \
+        return cmp; \
+    }
+
+#ifndef ATOMIC_EXCHANGE
+#    define ATOMIC_EXCHANGE(TYPE, MODE)     ATOMIC_GEN_OP(TYPE, MODE,
exchange, value)
+#endif
+
+#ifndef ATOMIC_FETCH_ADD
+#    define ATOMIC_FETCH_ADD(TYPE, MODE)    ATOMIC_GEN_OP(TYPE, MODE,
fetch_add, (cmp + value))
+#endif
+
+#ifndef ATOMIC_FETCH_SUB
+#    define ATOMIC_FETCH_SUB(TYPE, MODE)    ATOMIC_GEN_OP(TYPE, MODE,
fetch_sub, (cmp - value))
+#endif
+
+#ifndef ATOMIC_FETCH_AND
+#    define ATOMIC_FETCH_AND(TYPE, MODE)    ATOMIC_GEN_OP(TYPE, MODE,
fetch_and, (cmp & value))
+#endif
+
+#ifndef ATOMIC_FETCH_OR
+#    define ATOMIC_FETCH_OR(TYPE, MODE)     ATOMIC_GEN_OP(TYPE, MODE,
fetch_or, (cmp | value))
+#endif
+
+#ifndef ATOMIC_FETCH_XOR
+#    define ATOMIC_FETCH_XOR(TYPE, MODE)    ATOMIC_GEN_OP(TYPE, MODE,
fetch_xor, (cmp ^ value))
+#endif
--
2.30.1



reply via email to

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