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 | 1930 | #if CONFIG_TCC_SEMLOCK |
| 1931 | 1931 | #if defined _WIN32 |
| 1932 | 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 | 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 | 1968 | InitializeCriticalSection(&p->cs); |
| 1936 | − InterlockedExchange(&p->init, 2); | |
| 1969 | + tcc_sem_store(&p->init, 2); | |
| 1937 | 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 | 1973 | Sleep(0); |
| 1940 | 1974 | } |
| 1941 | 1975 | EnterCriticalSection(&p->cs); |