History

win32: define arm64 Interlocked helpers in winnt.h

Move the TinyCC/Windows ARM64 Interlocked workaround from the semlock call site into the bundled WinAPI header. This keeps tcc.h using the normal Interlocked API while avoiding unresolved Interlocked imports when tcc -run self-compiles on Windows ARM64. Update lib/bt-exe.c as well so its ARM64 runtime object does not define a second InterlockedExchange fallback now provided by winnt.h.

Mounir IDRASSI committed 5 months ago

Commit 3b1fe971 parent 904e95c7 files · +122 −47Browse files

Unified · Split

7 files
  1. lib/bt-exe.c +0 −10
  2. tcc.h +3 −37
  3. tests/tests2/145_winarm64_interlocked.c +35 −0
  4. tests/tests2/145_winarm64_interlocked.expect +8 −0
  5. tests/tests2/Makefile +5 −0
  6. win32/include/winapi/winbase.h +8 −0
  7. win32/include/winapi/winnt.h +63 −0
lib/bt-exe.c+0−10
@@ -85,13 +85,3 @@ ST_FUNC char *pstrcpy(char *buf, size_t buf_size, const char *s) · 84 unmodified lines
8585 buf[l] = 0;
8686 return buf;
8787 }
88−
89−#if defined(_WIN64) && defined(__aarch64__)
90−/* The bt-only Windows ARM64 build should not rely on importing this helper. */
91−LONG InterlockedExchange(LONG volatile *Target, LONG Value)
92−{
93− LONG Old = *Target;
94− *Target = Value;
95− return Old;
96−}
97−#endif
tcc.h+3−37
@@ -1930,46 +1930,12 @@ dwarf_read_sleb128(unsigned char **ln, unsigned char *end) · 1929 unmodified lines
19301930 #if CONFIG_TCC_SEMLOCK
19311931 #if defined _WIN32
19321932 typedef struct { volatile LONG init; CRITICAL_SECTION cs; } TCCSem;
1933−#if defined __TINYC__ && (defined __aarch64__ || defined __arm64__)
1934−/* Windows/arm64 Interlocked* names are compiler intrinsics, not
1935− kernel32 exports, so tcc -run must not emit calls to them. */
1936−# define TCC_SEM_USE_ATOMICS 1
1937−enum { TCC_SEM_ATOMIC_SEQ_CST = 5 };
1938−#endif
1939−static inline LONG tcc_sem_cmpxchg(volatile LONG *ptr, LONG val, LONG cmp) {
1940−#ifdef TCC_SEM_USE_ATOMICS
1941− LONG old = cmp;
1942− __atomic_compare_exchange((LONG *)ptr, &old, &val, 0,
1943− TCC_SEM_ATOMIC_SEQ_CST,
1944− TCC_SEM_ATOMIC_SEQ_CST);
1945− return old;
1946−#else
1947− return InterlockedCompareExchange(ptr, val, cmp);
1948−#endif
1949−}
1950−static inline void tcc_sem_store(volatile LONG *ptr, LONG val) {
1951−#ifdef TCC_SEM_USE_ATOMICS
1952− __atomic_store((LONG *)ptr, &val, TCC_SEM_ATOMIC_SEQ_CST);
1953−#else
1954− InterlockedExchange(ptr, val);
1955−#endif
1956−}
1957−static inline LONG tcc_sem_load(volatile LONG *ptr) {
1958−#ifdef TCC_SEM_USE_ATOMICS
1959− LONG val;
1960− __atomic_load((LONG *)ptr, &val, TCC_SEM_ATOMIC_SEQ_CST);
1961− return val;
1962−#else
1963− return InterlockedCompareExchange(ptr, 0, 0);
1964−#endif
1965−}
19661933 static inline void wait_sem(TCCSem *p) {
1967− if (tcc_sem_cmpxchg(&p->init, 1, 0) == 0) {
1934+ if (InterlockedCompareExchange(&p->init, 1, 0) == 0) {
19681935 InitializeCriticalSection(&p->cs);
1969− tcc_sem_store(&p->init, 2);
1936+ InterlockedExchange(&p->init, 2);
19701937 } else {
1971− /* On tcc/arm64, __atomic_load maps to the acquire helper path. */
1972− while (tcc_sem_load(&p->init) != 2)
1938+ while (InterlockedCompareExchange(&p->init, 2, 2) != 2)
19731939 Sleep(0);
19741940 }
19751941 EnterCriticalSection(&p->cs);
tests/tests2/145_winarm64_interlocked.c+35−0
@@ -0,0 +1,35 @@
1+#include <stdio.h>
2+#include <windows.h>
3+
4+#define PTR(x) ((PVOID)(ULONG_PTR)(x))
5+#define CHECK(name, expr) printf("%s: %s\n", name, (expr) ? "yes" : "no")
6+
7+int main(void)
8+{
9+ PVOID volatile slot = PTR(0x1111222233334444ULL);
10+ PVOID old;
11+
12+ old = InterlockedExchangePointer(&slot, PTR(0x5555666677778888ULL));
13+ CHECK("exchange old", old == PTR(0x1111222233334444ULL));
14+ CHECK("exchange stored", slot == PTR(0x5555666677778888ULL));
15+
16+ old = InterlockedCompareExchangePointer(&slot,
17+ PTR(0x9999aaaabbbbccccULL),
18+ PTR(0x5555666677778888ULL));
19+ CHECK("compare old", old == PTR(0x5555666677778888ULL));
20+ CHECK("compare stored", slot == PTR(0x9999aaaabbbbccccULL));
21+
22+ old = InterlockedCompareExchangePointerAcquire(&slot,
23+ PTR(0xdddd111122223333ULL),
24+ PTR(0x0123456789abcdefULL));
25+ CHECK("acquire old", old == PTR(0x9999aaaabbbbccccULL));
26+ CHECK("acquire stored", slot == PTR(0x9999aaaabbbbccccULL));
27+
28+ old = InterlockedCompareExchangePointerRelease(&slot,
29+ PTR(0xdddd111122223333ULL),
30+ PTR(0x9999aaaabbbbccccULL));
31+ CHECK("release old", old == PTR(0x9999aaaabbbbccccULL));
32+ CHECK("release stored", slot == PTR(0xdddd111122223333ULL));
33+
34+ return 0;
35+}
tests/tests2/145_winarm64_interlocked.expect+8−0
@@ -0,0 +1,8 @@
1+exchange old: yes
2+exchange stored: yes
3+compare old: yes
4+compare stored: yes
5+acquire old: yes
6+acquire stored: yes
7+release old: yes
8+release stored: yes
tests/tests2/Makefile+5−0
@@ -65,6 +65,11 @@ ifeq (,$(filter arm64 aarch64,$(ARCH))) · 64 unmodified lines
6565 SKIP += 139_arm64_errors.test
6666 SKIP += 140_arm64_extasm.test
6767 endif
68+ifneq ($(CONFIG_WIN32),yes)
69+ SKIP += 145_winarm64_interlocked.test
70+else ifeq (,$(filter arm64 aarch64,$(ARCH)))
71+ SKIP += 145_winarm64_interlocked.test
72+endif
6873 ifeq (,$(filter riscv64,$(ARCH)))
6974 SKIP += 141_riscv_asm.test # riscv64 asm
7075 endif
win32/include/winapi/winbase.h+8−0
@@ -972,7 +972,9 @@ extern "C" { · 971 unmodified lines
972972 LONG WINAPI InterlockedDecrement(LONG volatile *lpAddend);
973973 LONG WINAPI InterlockedExchange(LONG volatile *Target,LONG Value);
974974
975+#ifndef InterlockedExchangePointer
975976 #define InterlockedExchangePointer(Target,Value) (PVOID)InterlockedExchange((PLONG)(Target),(LONG)(Value))
977+#endif
976978
977979 LONG WINAPI InterlockedExchangeAdd(LONG volatile *Addend,LONG Value);
978980 LONG WINAPI InterlockedCompareExchange(LONG volatile *Destination,LONG Exchange,LONG Comperand);
@@ -1035,6 +1037,7 @@ extern "C" { · 56 unmodified lines
10351037 return Old;
10361038 }
10371039
1040+#ifndef InterlockedCompareExchangePointer
10381041 #ifdef __cplusplus
10391042 __CRT_INLINE PVOID __cdecl __InlineInterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID ExChange,PVOID Comperand) {
10401043 return((PVOID)(LONG_PTR)InterlockedCompareExchange((LONG volatile *)Destination,(LONG)(LONG_PTR)ExChange,(LONG)(LONG_PTR)Comperand));
@@ -1043,6 +1046,7 @@ extern "C" { · 2 unmodified lines
10431046 #else
10441047 #define InterlockedCompareExchangePointer(Destination,ExChange,Comperand)(PVOID)(LONG_PTR)InterlockedCompareExchange((LONG volatile *)(Destination),(LONG)(LONG_PTR)(ExChange),(LONG)(LONG_PTR)(Comperand))
10451048 #endif
1049+#endif
10461050
10471051 #define InterlockedIncrementAcquire InterlockedIncrement
10481052 #define InterlockedIncrementRelease InterlockedIncrement
@@ -1054,9 +1058,13 @@ extern "C" { · 5 unmodified lines
10541058 #define InterlockedCompareExchangeRelease InterlockedCompareExchange
10551059 #define InterlockedCompareExchangeAcquire64 InterlockedCompareExchange64
10561060 #define InterlockedCompareExchangeRelease64 InterlockedCompareExchange64
1061+#ifndef InterlockedCompareExchangePointerAcquire
10571062 #define InterlockedCompareExchangePointerAcquire InterlockedCompareExchangePointer
1063+#endif
1064+#ifndef InterlockedCompareExchangePointerRelease
10581065 #define InterlockedCompareExchangePointerRelease InterlockedCompareExchangePointer
10591066 #endif
1067+#endif
10601068
10611069 #if defined(_SLIST_HEADER_) && !defined(_NTOSP_)
10621070 WINBASEAPI VOID WINAPI InitializeSListHead(PSLIST_HEADER ListHead);
win32/include/winapi/winnt.h+63−0
@@ -1419,6 +1419,69 @@ typedef DWORD LCID; · 1418 unmodified lines
14191419 #define OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME "OutOfProcessFunctionTableCallback"
14201420 #endif /* defined(__x86_64) && !defined(RC_INVOKED) */
14211421
1422+#if defined(__TINYC__) && (defined(__aarch64__) || defined(__arm64__)) && !defined(RC_INVOKED)
1423+
1424+#define __TCC_WINNT_ATOMIC_SEQ_CST 5
1425+/* TCC lowers __atomic_compare_exchange's fourth argument as weak, but the
1426+ ARM64 helper reads it as success_memorder. Strong CAS passes weak == 0,
1427+ so keep Interlocked's barriers explicit here. */
1428+#define __TCC_WINNT_MEMORY_BARRIER() __asm__ __volatile__("dmb ish" : : : "memory")
1429+
1430+/* This covers the LONG operations needed by TCC's semaphore code and the
1431+ pointer helpers that winbase.h exposes through Interlocked pointer macros.
1432+ Add local helpers before relying on increment/decrement, add/exchange-add,
1433+ bitwise, or 64-bit Interlocked forms on Windows ARM64 with TCC. */
1434+
1435+ __CRT_INLINE LONG InterlockedExchange(LONG volatile *Target,LONG Value) {
1436+ LONG Old;
1437+ __atomic_load(Target,&Old,__TCC_WINNT_ATOMIC_SEQ_CST);
1438+ __TCC_WINNT_MEMORY_BARRIER();
1439+ while (!__atomic_compare_exchange(Target,&Old,&Value,0,
1440+ __TCC_WINNT_ATOMIC_SEQ_CST,__TCC_WINNT_ATOMIC_SEQ_CST))
1441+ ;
1442+ __TCC_WINNT_MEMORY_BARRIER();
1443+ return Old;
1444+ }
1445+ __CRT_INLINE LONG InterlockedCompareExchange(LONG volatile *Destination,LONG ExChange,LONG Comperand) {
1446+ LONG Old = Comperand;
1447+ __TCC_WINNT_MEMORY_BARRIER();
1448+ __atomic_compare_exchange(Destination,&Old,&ExChange,0,
1449+ __TCC_WINNT_ATOMIC_SEQ_CST,__TCC_WINNT_ATOMIC_SEQ_CST);
1450+ __TCC_WINNT_MEMORY_BARRIER();
1451+ return Old;
1452+ }
1453+ __CRT_INLINE PVOID __TCC_WINNT_InterlockedExchangePointer(PVOID volatile *Target,PVOID Value) {
1454+ PVOID Old;
1455+ __atomic_load(Target,&Old,__TCC_WINNT_ATOMIC_SEQ_CST);
1456+ __TCC_WINNT_MEMORY_BARRIER();
1457+ while (!__atomic_compare_exchange(Target,&Old,&Value,0,
1458+ __TCC_WINNT_ATOMIC_SEQ_CST,__TCC_WINNT_ATOMIC_SEQ_CST))
1459+ ;
1460+ __TCC_WINNT_MEMORY_BARRIER();
1461+ return Old;
1462+ }
1463+ __CRT_INLINE PVOID __TCC_WINNT_InterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID ExChange,PVOID Comperand) {
1464+ PVOID Old = Comperand;
1465+ __TCC_WINNT_MEMORY_BARRIER();
1466+ __atomic_compare_exchange(Destination,&Old,&ExChange,0,
1467+ __TCC_WINNT_ATOMIC_SEQ_CST,__TCC_WINNT_ATOMIC_SEQ_CST);
1468+ __TCC_WINNT_MEMORY_BARRIER();
1469+ return Old;
1470+ }
1471+
1472+#define InterlockedExchangePointer __TCC_WINNT_InterlockedExchangePointer
1473+#define InterlockedCompareExchangePointer __TCC_WINNT_InterlockedCompareExchangePointer
1474+#define InterlockedCompareExchangePointerAcquire InterlockedCompareExchangePointer
1475+#define InterlockedCompareExchangePointerRelease InterlockedCompareExchangePointer
1476+
1477+#define InterlockedCompareExchangeAcquire InterlockedCompareExchange
1478+#define InterlockedCompareExchangeRelease InterlockedCompareExchange
1479+
1480+#undef __TCC_WINNT_MEMORY_BARRIER
1481+#undef __TCC_WINNT_ATOMIC_SEQ_CST
1482+
1483+#endif /* defined(__TINYC__) && (defined(__aarch64__) || defined(__arm64__)) && !defined(RC_INVOKED) */
1484+
14221485 #if defined(_ARM64_)
14231486
14241487 /* ARM64 Context Definition */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t