Windows/arm64 exposes Interlocked* operations as compiler intrinsics rather than kernel32 exports. When tcc -run self-compiles tcc.c, calls to InterlockedCompareExchange or InterlockedExchange can therefore remain as unresolved imports in the in-memory linker. Route the TinyCC arm64 path through the existing __atomic helpers while keeping Interlocked* for other Windows compilers. The compile-lock initialization state machine remains unchanged.
Unified · Split
| @@ -1930,12 +1930,46 @@ dwarf_read_sleb128(unsigned char **ln, unsigned char *end) · 1929 unmodified lines | |||
| 1930 | #if CONFIG_TCC_SEMLOCK | 1930 | #if CONFIG_TCC_SEMLOCK |
| 1931 | #if defined _WIN32 | 1931 | #if defined _WIN32 |
| 1932 | typedef struct { volatile LONG init; CRITICAL_SECTION cs; } TCCSem; | 1932 | 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 | } | ||
| 1933 | static inline void wait_sem(TCCSem *p) { | 1966 | static inline void wait_sem(TCCSem *p) { |
| 1934 | if (InterlockedCompareExchange(&p->init, 1, 0) == 0) { | 1967 | if (tcc_sem_cmpxchg(&p->init, 1, 0) == 0) { |
| 1935 | InitializeCriticalSection(&p->cs); | 1968 | InitializeCriticalSection(&p->cs); |
| 1936 | InterlockedExchange(&p->init, 2); | 1969 | tcc_sem_store(&p->init, 2); |
| 1937 | } else { | 1970 | } else { |
| 1938 | while (InterlockedCompareExchange(&p->init, 2, 2) != 2) | 1971 | /* On tcc/arm64, __atomic_load maps to the acquire helper path. */ |
| 1972 | while (tcc_sem_load(&p->init) != 2) | ||
| 1939 | Sleep(0); | 1973 | Sleep(0); |
| 1940 | } | 1974 | } |
| 1941 | EnterCriticalSection(&p->cs); | 1975 | EnterCriticalSection(&p->cs); |