python / python/cpython

_Py_ThreadId() fails to compile with clang on Windows ARM64 (MSYS2 CLANGARM64)

Open
#157,212 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

build OS-windows topic-free-threading type-bug
Dominant language
Python
Stars
77.2k
Forks
35.9k
PR merge metrics
PR metrics pending

Description

Bug report

Bug description:

Building a free-threaded extension module for Windows ARM64 with MSYS2's CLANGARM64 (llvm-mingw) toolchain fails to compile Include/object.h:

object.h:200:11: error: call to undeclared function '__getReg'; ISO C99 and later do not
support implicit function declarations [-Wimplicit-function-declaration]
  200 |     tid = __getReg(18);
      |           ^

Example actions run where I tried to build jq.py.

Minimal repro

/* repro.c */
#include <Python.h>

uintptr_t repro(void) { return _Py_ThreadId(); }
$ gcc -c repro.c -O1 -Wall -DPy_GIL_DISABLED=1 -I <freethreaded-arm64-headers>
In file included from repro.c:1:
In file included from Python.h:81:
object.h:200:11: error: call to undeclared function '__getReg'; ISO C99 and later do not
support implicit function declarations [-Wimplicit-function-declaration]
  200 |     tid = __getReg(18);
      |           ^
1 error generated.

(gcc here is mingw-w64-clang-aarch64-gcc-compat, i.e. clang.)

_Py_ThreadId() reaches this branch, added in #124609 / GH-124663 for GCC:

#elif defined(__MINGW32__) && defined(_M_ARM64)
    tid = __getReg(18);

clang does not define _M_ARM64 but mingw-w64 does, in _mingw_mac.h:

#if defined(__aarch64__) && !defined(_M_ARM64)
#  define _M_ARM64 1

which is pulled in transitively by pyconfig.h. So the condition is true all aarch64 compilers. clang's predefines here are:

#define _WIN32 1
#define __GNUC__ 4
#define __MINGW32__ 1
#define __MINGW64__ 1
#define __aarch64__ 1
#define __clang__ 1

Why __getReg is unavailable to clang

  • clang's intrin.h declares unsigned __int64 __getReg(int);, but only inside #ifdef _MSC_VER. For a *-windows-gnu target the header takes the #include_next <intrin.h> path and defers to mingw-w64.
  • mingw-w64's intrin.h declares __getReg only via __MACHINEIA64 (Itanium), which expands to nothing unless __ia64__. There is no __MACHINEARM64 entry for it.
  • It is also not a clang builtin.

Note that falling through to the __aarch64__ branch is not a valid fix:

#elif defined(__aarch64__)
    __asm__ ("mrs %0, tpidr_el0" : "=r" (tid));

On Windows ARM64 tpidr_el0 reads as 0 on every thread, whereas x18 holds the TEB and is correctly per-thread:

main x18=000000cc3736d000 tpidr_el0=0000000000000000 NtCurrentTeb=000000cc3736d000
thr1 x18=000000cc37371000 tpidr_el0=0000000000000000 NtCurrentTeb=000000cc37371000
thr2 x18=000000cc37373000 tpidr_el0=0000000000000000 NtCurrentTeb=000000cc37373000

A constant 0 would collide with _Py_UNOWNED_TID, so this would compile cleanly and then misbehave silently — the same failure mode discussed in #124609.

Suggested fix

Keep __getReg for GCC and give clang a dedicated branch reading x18:

#elif defined(__MINGW32__) && defined(_M_ARM64) && !defined(__clang__)
    tid = __getReg(18);
#elif defined(__MINGW32__) && defined(_M_ARM64)
    __asm__ ("mov %0, x18" : "=r" (tid));  // Windows/ARM64 keeps the TEB in x18

I have verified that this compiles and generates the expected read.

Versions tested

  • CPython 3.14 (free-threaded)
  • Windows 11 Pro 10.0.28000 ARM64
  • clang 22.1.8 (MSYS2 CLANGARM64)
CPython versions tested on:

3.14

Operating systems tested on:

Windows

Linked PRs
  • gh-157252
  • gh-157253

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the _Py_ThreadId() platform branches in Include/object.h and reproduce the failure using the supplied repro.c example and compiler command. Review linked PRs gh-157252 and gh-157253 for work already underway. Done means the free-threaded Windows ARM64 CLANGARM64 repro compiles and reads a per-thread identifier correctly.

Written by the indexing model from the issue text.

Assessment

Tech stack
c, python
Domain
build-system, operating-systems
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.