From 94252cf33ea1a7f9309e47ceb8ae76b4ad31ad0f Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Sat, 14 Sep 2024 12:22:49 -0700 Subject: [PATCH 01/37] Update to LLVM 19 --- .github/workflows/jit.yml | 2 +- Tools/jit/_llvm.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/jit.yml b/.github/workflows/jit.yml index 5e3ac9e9e0fada..3dd83e33b43e86 100644 --- a/.github/workflows/jit.yml +++ b/.github/workflows/jit.yml @@ -61,7 +61,7 @@ jobs: - true - false llvm: - - 18 + - 19 include: - target: i686-pc-windows-msvc/msvc architecture: Win32 diff --git a/Tools/jit/_llvm.py b/Tools/jit/_llvm.py index 606f280a14d974..925b56ac669aa0 100644 --- a/Tools/jit/_llvm.py +++ b/Tools/jit/_llvm.py @@ -8,7 +8,7 @@ import subprocess import typing -_LLVM_VERSION = 18 +_LLVM_VERSION = 19 _LLVM_VERSION_PATTERN = re.compile(rf"version\s+{_LLVM_VERSION}\.\d+\.\d+\S*\s+") _P = typing.ParamSpec("_P") From f8dc236394fa53daef165ea320cc0a54f5d60afc Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Sat, 14 Sep 2024 13:05:55 -0700 Subject: [PATCH 02/37] update syntax in disabled gil ci --- .github/workflows/jit.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/jit.yml b/.github/workflows/jit.yml index 3dd83e33b43e86..9646a9ce9b9003 100644 --- a/.github/workflows/jit.yml +++ b/.github/workflows/jit.yml @@ -174,8 +174,8 @@ jobs: python-version: '3.11' - name: Build with JIT enabled and GIL disabled run: | - sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh 18 - export PATH="$(llvm-config-18 --bindir):$PATH" + sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ matrix.llvm }} + export PATH="$(llvm-config-${{ matrix.llvm }} --bindir):$PATH" ./configure --enable-experimental-jit --with-pydebug --disable-gil make all --jobs 4 - name: Run tests From 80a3b408131691fb0f273db38af3f3f3c7da59f3 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sat, 14 Sep 2024 20:09:41 +0000 Subject: [PATCH 03/37] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2024-09-14-20-09-39.gh-issue-123714.o1mbe4.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-14-20-09-39.gh-issue-123714.o1mbe4.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-14-20-09-39.gh-issue-123714.o1mbe4.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-14-20-09-39.gh-issue-123714.o1mbe4.rst new file mode 100644 index 00000000000000..03a2ef63238073 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-14-20-09-39.gh-issue-123714.o1mbe4.rst @@ -0,0 +1 @@ +Update JIT compilation to use LLVM 19 From 7a1133e2a935cd06520df0860806b7df85e44dce Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Tue, 24 Sep 2024 21:20:26 -0700 Subject: [PATCH 04/37] Update readme --- Tools/jit/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Tools/jit/README.md b/Tools/jit/README.md index bc6f793b296f12..b6bb8479298bd4 100644 --- a/Tools/jit/README.md +++ b/Tools/jit/README.md @@ -7,7 +7,7 @@ This version of CPython can be built with an experimental just-in-time compiler[ The JIT compiler does not require end users to install any third-party dependencies, but part of it must be *built* using LLVM[^why-llvm]. You are *not* required to build the rest of CPython using LLVM, or even the same version of LLVM (in fact, this is uncommon). -LLVM version 18 is required. Both `clang` and `llvm-readobj` need to be installed and discoverable (version suffixes, like `clang-18`, are okay). It's highly recommended that you also have `llvm-objdump` available, since this allows the build script to dump human-readable assembly for the generated code. +LLVM version 19 is required. Both `clang` and `llvm-readobj` need to be installed and discoverable (version suffixes, like `clang-19`, are okay). It's highly recommended that you also have `llvm-objdump` available, since this allows the build script to dump human-readable assembly for the generated code. It's easy to install all of the required tools: @@ -18,10 +18,10 @@ Install LLVM 18 on Ubuntu/Debian: ```sh wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh -sudo ./llvm.sh 18 +sudo ./llvm.sh 19 ``` -Install LLVM 18 on Fedora Linux 40 or newer: +Install LLVM 19 on Fedora Linux 40 or newer: ```sh sudo dnf install 'clang(major) = 18' 'llvm(major) = 18' @@ -29,22 +29,22 @@ sudo dnf install 'clang(major) = 18' 'llvm(major) = 18' ### macOS -Install LLVM 18 with [Homebrew](https://brew.sh): +Install LLVM 19 with [Homebrew](https://brew.sh): ```sh -brew install llvm@18 +brew install llvm@19 ``` Homebrew won't add any of the tools to your `$PATH`. That's okay; the build script knows how to find them. ### Windows -Install LLVM 18 [by searching for it on LLVM's GitHub releases page](https://github.com/llvm/llvm-project/releases?q=18), clicking on "Assets", downloading the appropriate Windows installer for your platform (likely the file ending with `-win64.exe`), and running it. **When installing, be sure to select the option labeled "Add LLVM to the system PATH".** +Install LLVM 19 [by searching for it on LLVM's GitHub releases page](https://github.com/llvm/llvm-project/releases?q=19), clicking on "Assets", downloading the appropriate Windows installer for your platform (likely the file ending with `-win64.exe`), and running it. **When installing, be sure to select the option labeled "Add LLVM to the system PATH".** Alternatively, you can use [chocolatey](https://chocolatey.org): ```sh -choco install llvm --version=18.1.6 +choco install llvm --version=19.1.0 ``` ### Dev Containers From d8e38db2ea2ce63321f84970c6fb6ece85bcf9bc Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Tue, 24 Sep 2024 21:27:58 -0700 Subject: [PATCH 05/37] fix free-threaded by pseudo-pinning version --- .github/workflows/jit.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/jit.yml b/.github/workflows/jit.yml index 06279c40d336e5..7717ecf33b67b2 100644 --- a/.github/workflows/jit.yml +++ b/.github/workflows/jit.yml @@ -165,6 +165,10 @@ jobs: name: Free-Threaded (Debug) needs: interpreter runs-on: ubuntu-latest + strategy: + matrix: + llvm: + - 19 steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 From b8ae2183dc4d24aff8a6f38c8618b37da2cf20d8 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Thu, 26 Sep 2024 11:40:42 -0700 Subject: [PATCH 06/37] Add check to see that registers match in stencil generation --- Tools/jit/_stencils.py | 9 ++++++++- Tools/jit/_writer.py | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Tools/jit/_stencils.py b/Tools/jit/_stencils.py index 1c6a9edb39840d..f60498188f63d2 100644 --- a/Tools/jit/_stencils.py +++ b/Tools/jit/_stencils.py @@ -132,8 +132,14 @@ class Hole: def __post_init__(self) -> None: self.func = _PATCH_FUNCS[self.kind] - def fold(self, other: typing.Self) -> typing.Self | None: + def fold(self, other: typing.Self, body: bytes) -> typing.Self | None: """Combine two holes into a single hole, if possible.""" + instruction_a = int.from_bytes(body[self.offset : self.offset + 4], byteorder=sys.byteorder) + instruction_b = int.from_bytes(body[other.offset : other.offset + 4], byteorder=sys.byteorder) + reg_a = instruction_a & 0b11111 + reg_b1 = instruction_b & 0b11111 + reg_b2 = (instruction_b >> 5) & 0b11111 + if ( self.offset + 4 == other.offset and self.value == other.value @@ -141,6 +147,7 @@ def fold(self, other: typing.Self) -> typing.Self | None: and self.addend == other.addend and self.func == "patch_aarch64_21rx" and other.func == "patch_aarch64_12x" + and reg_a == reg_b1 == reg_b2 ): # These can *only* be properly relaxed when they appear together and # patch the same value: diff --git a/Tools/jit/_writer.py b/Tools/jit/_writer.py index 9d11094f85c7ff..a45f0a15cf03f8 100644 --- a/Tools/jit/_writer.py +++ b/Tools/jit/_writer.py @@ -50,7 +50,7 @@ def _dump_stencil(opname: str, group: _stencils.StencilGroup) -> typing.Iterator if skip: skip = False continue - if pair and (folded := hole.fold(pair)): + if pair and (folded := hole.fold(pair, stencil.body)): skip = True hole = folded yield f" {hole.as_c(part)}" From 4368d5fbc192df2b9e6cdb700b1a9487c1446665 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Thu, 26 Sep 2024 11:42:50 -0700 Subject: [PATCH 07/37] Appease linters --- Tools/jit/_stencils.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Tools/jit/_stencils.py b/Tools/jit/_stencils.py index f60498188f63d2..0ba9935b2e3fd0 100644 --- a/Tools/jit/_stencils.py +++ b/Tools/jit/_stencils.py @@ -134,8 +134,12 @@ def __post_init__(self) -> None: def fold(self, other: typing.Self, body: bytes) -> typing.Self | None: """Combine two holes into a single hole, if possible.""" - instruction_a = int.from_bytes(body[self.offset : self.offset + 4], byteorder=sys.byteorder) - instruction_b = int.from_bytes(body[other.offset : other.offset + 4], byteorder=sys.byteorder) + instruction_a = int.from_bytes( + body[self.offset : self.offset + 4], byteorder=sys.byteorder + ) + instruction_b = int.from_bytes( + body[other.offset : other.offset + 4], byteorder=sys.byteorder + ) reg_a = instruction_a & 0b11111 reg_b1 = instruction_b & 0b11111 reg_b2 = (instruction_b >> 5) & 0b11111 From 12fc5cd2df0ed1a46d28363e154f82dd1f59593b Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Thu, 26 Sep 2024 11:52:28 -0700 Subject: [PATCH 08/37] Remove devcontainer instructions from readme --- Tools/jit/README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/Tools/jit/README.md b/Tools/jit/README.md index b6bb8479298bd4..f2070ff06c58b7 100644 --- a/Tools/jit/README.md +++ b/Tools/jit/README.md @@ -47,9 +47,6 @@ Alternatively, you can use [chocolatey](https://chocolatey.org): choco install llvm --version=19.1.0 ``` -### Dev Containers - -If you are working CPython in a [Codespaces instance](https://devguide.python.org/getting-started/setup-building/#using-codespaces), there's no need to install LLVM as the Fedora 40 base image includes LLVM 18 out of the box. ## Building From 7f9fe5abc17161f82d434b7dcc83e3071eb672c9 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Thu, 26 Sep 2024 14:48:23 -0700 Subject: [PATCH 09/37] Update README --- Tools/jit/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tools/jit/README.md b/Tools/jit/README.md index f2070ff06c58b7..801c64e4059ccc 100644 --- a/Tools/jit/README.md +++ b/Tools/jit/README.md @@ -13,7 +13,7 @@ It's easy to install all of the required tools: ### Linux -Install LLVM 18 on Ubuntu/Debian: +Install LLVM 19 on Ubuntu/Debian: ```sh wget https://apt.llvm.org/llvm.sh @@ -24,7 +24,7 @@ sudo ./llvm.sh 19 Install LLVM 19 on Fedora Linux 40 or newer: ```sh -sudo dnf install 'clang(major) = 18' 'llvm(major) = 18' +sudo dnf install 'clang(major) = 19' 'llvm(major) = 19' ``` ### macOS From a597ea5746f4a8e475db034621d75dd2a20567f1 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Sat, 12 Oct 2024 20:57:51 -0700 Subject: [PATCH 10/37] Remove ghccc --- Include/internal/pycore_jit.h | 2 +- Tools/jit/_llvm.py | 3 ++- Tools/jit/_targets.py | 48 +++++------------------------------ 3 files changed, 9 insertions(+), 44 deletions(-) diff --git a/Include/internal/pycore_jit.h b/Include/internal/pycore_jit.h index 4d6cc35a7a3de7..5794a8d2d9b0c5 100644 --- a/Include/internal/pycore_jit.h +++ b/Include/internal/pycore_jit.h @@ -11,7 +11,7 @@ extern "C" { #ifdef _Py_JIT -typedef _Py_CODEUNIT *(*jit_func)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate); +typedef _Py_CODEUNIT *(*jit_func)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate) __attribute__((preserve_none)); int _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction *trace, size_t length); void _PyJIT_Free(_PyExecutorObject *executor); diff --git a/Tools/jit/_llvm.py b/Tools/jit/_llvm.py index 925b56ac669aa0..303c83a346343a 100644 --- a/Tools/jit/_llvm.py +++ b/Tools/jit/_llvm.py @@ -32,7 +32,7 @@ async def wrapper( return wrapper -_CORES = asyncio.BoundedSemaphore(os.cpu_count() or 1) +_CORES = asyncio.BoundedSemaphore(1) async def _run(tool: str, args: typing.Iterable[str], echo: bool = False) -> str | None: @@ -78,6 +78,7 @@ async def _find_tool(tool: str, *, echo: bool = False) -> str | None: prefix = await _get_brew_llvm_prefix(echo=echo) if prefix is not None: path = os.path.join(prefix, "bin", tool) + print(path) if await _check_tool_version(path, echo=echo): return path # Nothing found: diff --git a/Tools/jit/_targets.py b/Tools/jit/_targets.py index 6c7b48f1f37865..5a0ed780195303 100644 --- a/Tools/jit/_targets.py +++ b/Tools/jit/_targets.py @@ -39,7 +39,6 @@ class _Target(typing.Generic[_S, _R]): _: dataclasses.KW_ONLY alignment: int = 1 args: typing.Sequence[str] = () - ghccc: bool = False prefix: str = "" stable: bool = False debug: bool = False @@ -110,7 +109,7 @@ async def _compile( self, opname: str, c: pathlib.Path, tempdir: pathlib.Path ) -> _stencils.StencilGroup: # "Compile" the trampoline to an empty stencil group if it's not needed: - if opname == "trampoline" and not self.ghccc: + if opname == "trampoline": return _stencils.StencilGroup() o = tempdir / f"{opname}.o" args = [ @@ -145,41 +144,7 @@ async def _compile( "-std=c11", *self.args, ] - if self.ghccc: - # This is a bit of an ugly workaround, but it makes the code much - # smaller and faster, so it's worth it. We want to use the GHC - # calling convention, but Clang doesn't support it. So, we *first* - # compile the code to LLVM IR, perform some text replacements on the - # IR to change the calling convention(!), and then compile *that*. - # Once we have access to Clang 19, we can get rid of this and use - # __attribute__((preserve_none)) directly in the C code instead: - ll = tempdir / f"{opname}.ll" - args_ll = args + [ - # -fomit-frame-pointer is necessary because the GHC calling - # convention uses RBP to pass arguments: - "-S", - "-emit-llvm", - "-fomit-frame-pointer", - "-o", - f"{ll}", - f"{c}", - ] - await _llvm.run("clang", args_ll, echo=self.verbose) - ir = ll.read_text() - # This handles declarations, definitions, and calls to named symbols - # starting with "_JIT_": - ir = re.sub( - r"(((noalias|nonnull|noundef) )*ptr @_JIT_\w+\()", r"ghccc \1", ir - ) - # This handles calls to anonymous callees, since anything with - # "musttail" needs to use the same calling convention: - ir = ir.replace("musttail call", "musttail call ghccc") - # Sometimes *both* replacements happen at the same site, so fix it: - ir = ir.replace("ghccc ghccc", "ghccc") - ll.write_text(ir) - args_o = args + ["-Wno-unused-command-line-argument", "-o", f"{o}", f"{ll}"] - else: - args_o = args + ["-o", f"{o}", f"{c}"] + args_o = args + ["-o", f"{o}", f"{c}"] await _llvm.run("clang", args_o, echo=self.verbose) return await self._parse(o) @@ -519,7 +484,6 @@ def _handle_relocation( def get_target(host: str) -> _COFF | _ELF | _MachO: """Build a _Target for the given host "triple" and options.""" - # ghccc currently crashes Clang when combined with musttail on aarch64. :( target: _COFF | _ELF | _MachO if re.fullmatch(r"aarch64-apple-darwin.*", host): target = _MachO(host, alignment=8, prefix="_") @@ -531,15 +495,15 @@ def get_target(host: str) -> _COFF | _ELF | _MachO: target = _ELF(host, alignment=8, args=args) elif re.fullmatch(r"i686-pc-windows-msvc", host): args = ["-DPy_NO_ENABLE_SHARED"] - target = _COFF(host, args=args, ghccc=True, prefix="_") + target = _COFF(host, args=args, prefix="_") elif re.fullmatch(r"x86_64-apple-darwin.*", host): - target = _MachO(host, ghccc=True, prefix="_") + target = _MachO(host, prefix="_") elif re.fullmatch(r"x86_64-pc-windows-msvc", host): args = ["-fms-runtime-lib=dll"] - target = _COFF(host, args=args, ghccc=True) + target = _COFF(host, args=args) elif re.fullmatch(r"x86_64-.*-linux-gnu", host): args = ["-fpic"] - target = _ELF(host, args=args, ghccc=True) + target = _ELF(host, args=args) else: raise ValueError(host) return target From 85b858dfe8689efcf2fc26b5f3005cfa44c202cf Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Sat, 12 Oct 2024 21:06:43 -0700 Subject: [PATCH 11/37] add back cpu_count --- Tools/jit/_llvm.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Tools/jit/_llvm.py b/Tools/jit/_llvm.py index 303c83a346343a..37a181f2a658f8 100644 --- a/Tools/jit/_llvm.py +++ b/Tools/jit/_llvm.py @@ -32,8 +32,7 @@ async def wrapper( return wrapper -_CORES = asyncio.BoundedSemaphore(1) - +_CORES = asyncio.BoundedSemaphore(os.cpu_count() or 1) async def _run(tool: str, args: typing.Iterable[str], echo: bool = False) -> str | None: command = [tool, *args] From 9209651ec38f45de7db371e4dad82d0774fc2963 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Sat, 12 Oct 2024 21:08:51 -0700 Subject: [PATCH 12/37] Appease linter --- Tools/jit/_llvm.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Tools/jit/_llvm.py b/Tools/jit/_llvm.py index 37a181f2a658f8..683439d01a7f29 100644 --- a/Tools/jit/_llvm.py +++ b/Tools/jit/_llvm.py @@ -34,6 +34,7 @@ async def wrapper( _CORES = asyncio.BoundedSemaphore(os.cpu_count() or 1) + async def _run(tool: str, args: typing.Iterable[str], echo: bool = False) -> str | None: command = [tool, *args] async with _CORES: From a842f905c3dd561c651f3692c12de1b969e30040 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Sat, 12 Oct 2024 21:10:23 -0700 Subject: [PATCH 13/37] Add sys import --- Tools/jit/_stencils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Tools/jit/_stencils.py b/Tools/jit/_stencils.py index 7d4fc0861d2ee4..def08176d277b6 100644 --- a/Tools/jit/_stencils.py +++ b/Tools/jit/_stencils.py @@ -2,6 +2,7 @@ import dataclasses import enum +import sys import typing import _schema From 73c725b89bc5498894cc052993dd71c0e635a6f5 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Sat, 12 Oct 2024 21:22:37 -0700 Subject: [PATCH 14/37] Move preserve_none --- Include/internal/pycore_jit.h | 2 +- Tools/jit/trampoline.c | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Include/internal/pycore_jit.h b/Include/internal/pycore_jit.h index 5794a8d2d9b0c5..4d6cc35a7a3de7 100644 --- a/Include/internal/pycore_jit.h +++ b/Include/internal/pycore_jit.h @@ -11,7 +11,7 @@ extern "C" { #ifdef _Py_JIT -typedef _Py_CODEUNIT *(*jit_func)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate) __attribute__((preserve_none)); +typedef _Py_CODEUNIT *(*jit_func)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate); int _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction *trace, size_t length); void _PyJIT_Free(_PyExecutorObject *executor); diff --git a/Tools/jit/trampoline.c b/Tools/jit/trampoline.c index a0a963f2a49656..653eb9bdd60ca4 100644 --- a/Tools/jit/trampoline.c +++ b/Tools/jit/trampoline.c @@ -4,10 +4,7 @@ #include "pycore_frame.h" #include "pycore_jit.h" -// This is where the calling convention changes, on platforms that require it. -// The actual change is patched in while the JIT compiler is being built, in -// Tools/jit/_targets.py. On other platforms, this function compiles to nothing. -_Py_CODEUNIT * +__attribute__((preserve_none)) _Py_CODEUNIT * _ENTRY(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate) { // This is subtle. The actual trace will return to us once it exits, so we From 4d8a012741a9d33b4e5b221880ad0f8d023db3af Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Mon, 14 Oct 2024 17:16:39 -0700 Subject: [PATCH 15/37] define jit_func_preserve_none --- Include/internal/pycore_jit.h | 3 ++- Python/ceval_macros.h | 2 +- Tools/jit/_llvm.py | 1 - Tools/jit/template.c | 6 +++--- Tools/jit/trampoline.c | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Include/internal/pycore_jit.h b/Include/internal/pycore_jit.h index 4d6cc35a7a3de7..67b7b47d80845e 100644 --- a/Include/internal/pycore_jit.h +++ b/Include/internal/pycore_jit.h @@ -11,7 +11,8 @@ extern "C" { #ifdef _Py_JIT -typedef _Py_CODEUNIT *(*jit_func)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate); +typedef _Py_CODEUNIT *(*jit_func_native)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate); +typedef _Py_CODEUNIT *(*jit_func_preserve_none)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate) __attribute__((preserve_none)); int _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction *trace, size_t length); void _PyJIT_Free(_PyExecutorObject *executor); diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index e0e9cc156ed62f..d55e9282c2a8fe 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -398,7 +398,7 @@ _PyFrame_SetStackPointer(frame, stack_pointer) #define GOTO_TIER_TWO(EXECUTOR) \ do { \ OPT_STAT_INC(traces_executed); \ - jit_func jitted = (EXECUTOR)->jit_code; \ + jit_func_native jitted = (EXECUTOR)->jit_code; \ next_instr = jitted(frame, stack_pointer, tstate); \ Py_DECREF(tstate->previous_executor); \ tstate->previous_executor = NULL; \ diff --git a/Tools/jit/_llvm.py b/Tools/jit/_llvm.py index 683439d01a7f29..925b56ac669aa0 100644 --- a/Tools/jit/_llvm.py +++ b/Tools/jit/_llvm.py @@ -78,7 +78,6 @@ async def _find_tool(tool: str, *, echo: bool = False) -> str | None: prefix = await _get_brew_llvm_prefix(echo=echo) if prefix is not None: path = os.path.join(prefix, "bin", tool) - print(path) if await _check_tool_version(path, echo=echo): return path # Nothing found: diff --git a/Tools/jit/template.c b/Tools/jit/template.c index 6cf15085f79933..6ba4613cbc06c4 100644 --- a/Tools/jit/template.c +++ b/Tools/jit/template.c @@ -48,8 +48,8 @@ #define GOTO_TIER_TWO(EXECUTOR) \ do { \ OPT_STAT_INC(traces_executed); \ - __attribute__((musttail)) \ - return ((jit_func)((EXECUTOR)->jit_side_entry))(frame, stack_pointer, tstate); \ + __attribute__((musttail)) \ + return ((jit_func_native)((EXECUTOR)->jit_side_entry))(frame, stack_pointer, tstate); \ } while (0) #undef GOTO_TIER_ONE @@ -72,7 +72,7 @@ do { \ do { \ PyAPI_DATA(void) ALIAS; \ __attribute__((musttail)) \ - return ((jit_func)&ALIAS)(frame, stack_pointer, tstate); \ + return ((jit_func_native)&ALIAS)(frame, stack_pointer, tstate); \ } while (0) #undef JUMP_TO_JUMP_TARGET diff --git a/Tools/jit/trampoline.c b/Tools/jit/trampoline.c index 653eb9bdd60ca4..e460bb1fa1efdc 100644 --- a/Tools/jit/trampoline.c +++ b/Tools/jit/trampoline.c @@ -4,7 +4,7 @@ #include "pycore_frame.h" #include "pycore_jit.h" -__attribute__((preserve_none)) _Py_CODEUNIT * +_Py_CODEUNIT * _ENTRY(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate) { // This is subtle. The actual trace will return to us once it exits, so we @@ -16,7 +16,7 @@ _ENTRY(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *ts Py_INCREF(executor); // Note that this is *not* a tail call: PyAPI_DATA(void) _JIT_CONTINUE; - _Py_CODEUNIT *target = ((jit_func)&_JIT_CONTINUE)(frame, stack_pointer, tstate); + _Py_CODEUNIT *target = ((jit_func_preserve_none)&_JIT_CONTINUE)(frame, stack_pointer, tstate); Py_SETREF(tstate->previous_executor, executor); return target; } From 994af9742ec957525d2b51e8ebc56a020c7283ec Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Mon, 14 Oct 2024 17:25:45 -0700 Subject: [PATCH 16/37] add comment --- Include/internal/pycore_jit.h | 3 +++ Tools/jit/template.c | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Include/internal/pycore_jit.h b/Include/internal/pycore_jit.h index 67b7b47d80845e..b80482a9ddd199 100644 --- a/Include/internal/pycore_jit.h +++ b/Include/internal/pycore_jit.h @@ -12,6 +12,9 @@ extern "C" { #ifdef _Py_JIT typedef _Py_CODEUNIT *(*jit_func_native)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate); + +// To use preserve_none in JIT builds, we need to declare a separate function pointer with __attribute__((preserve_none)) since +// this attribute is not supported in < clang 19. typedef _Py_CODEUNIT *(*jit_func_preserve_none)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate) __attribute__((preserve_none)); int _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction *trace, size_t length); diff --git a/Tools/jit/template.c b/Tools/jit/template.c index 6ba4613cbc06c4..e45e4f3c7fde56 100644 --- a/Tools/jit/template.c +++ b/Tools/jit/template.c @@ -49,7 +49,7 @@ do { \ OPT_STAT_INC(traces_executed); \ __attribute__((musttail)) \ - return ((jit_func_native)((EXECUTOR)->jit_side_entry))(frame, stack_pointer, tstate); \ + return ((jit_func_preserve_none)((EXECUTOR)->jit_side_entry))(frame, stack_pointer, tstate); \ } while (0) #undef GOTO_TIER_ONE @@ -72,7 +72,7 @@ do { \ do { \ PyAPI_DATA(void) ALIAS; \ __attribute__((musttail)) \ - return ((jit_func_native)&ALIAS)(frame, stack_pointer, tstate); \ + return ((jit_func_preserve_none)&ALIAS)(frame, stack_pointer, tstate); \ } while (0) #undef JUMP_TO_JUMP_TARGET @@ -86,7 +86,7 @@ do { \ #define TIER_TWO 2 -_Py_CODEUNIT * +__attribute__((preserve_none)) _Py_CODEUNIT * _JIT_ENTRY(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate) { // Locals that the instruction implementations expect to exist: From 0d86727d55092659eaeb65cb828a7364eb8153bd Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Mon, 14 Oct 2024 17:26:41 -0700 Subject: [PATCH 17/37] add comment --- Include/internal/pycore_jit.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Include/internal/pycore_jit.h b/Include/internal/pycore_jit.h index b80482a9ddd199..bc5df462be7d7a 100644 --- a/Include/internal/pycore_jit.h +++ b/Include/internal/pycore_jit.h @@ -13,8 +13,7 @@ extern "C" { typedef _Py_CODEUNIT *(*jit_func_native)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate); -// To use preserve_none in JIT builds, we need to declare a separate function pointer with __attribute__((preserve_none)) since -// this attribute is not supported in < clang 19. +// To use preserve_none in JIT builds, we need to declare a separate function pointer with __attribute__((preserve_none)) since this attribute is not supported in < clang 19. typedef _Py_CODEUNIT *(*jit_func_preserve_none)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate) __attribute__((preserve_none)); int _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction *trace, size_t length); From 98f05359ca6838289b834cd413bc8328acc0688c Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Mon, 14 Oct 2024 17:38:46 -0700 Subject: [PATCH 18/37] Fix whitespace --- Tools/jit/template.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/jit/template.c b/Tools/jit/template.c index e45e4f3c7fde56..59a0781a39ecd0 100644 --- a/Tools/jit/template.c +++ b/Tools/jit/template.c @@ -48,7 +48,7 @@ #define GOTO_TIER_TWO(EXECUTOR) \ do { \ OPT_STAT_INC(traces_executed); \ - __attribute__((musttail)) \ + __attribute__((musttail)) \ return ((jit_func_preserve_none)((EXECUTOR)->jit_side_entry))(frame, stack_pointer, tstate); \ } while (0) From 9a20a2e5ef10fe7fbfd2215b6921497acbd34987 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Mon, 14 Oct 2024 21:07:43 -0700 Subject: [PATCH 19/37] Move header to separate file --- Include/internal/pycore_jit.h | 3 --- Tools/jit/_targets.py | 5 +---- Tools/jit/jit_definitions.h | 24 ++++++++++++++++++++++++ Tools/jit/template.c | 2 ++ Tools/jit/trampoline.c | 2 ++ 5 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 Tools/jit/jit_definitions.h diff --git a/Include/internal/pycore_jit.h b/Include/internal/pycore_jit.h index bc5df462be7d7a..5e59f520c32b73 100644 --- a/Include/internal/pycore_jit.h +++ b/Include/internal/pycore_jit.h @@ -13,9 +13,6 @@ extern "C" { typedef _Py_CODEUNIT *(*jit_func_native)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate); -// To use preserve_none in JIT builds, we need to declare a separate function pointer with __attribute__((preserve_none)) since this attribute is not supported in < clang 19. -typedef _Py_CODEUNIT *(*jit_func_preserve_none)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate) __attribute__((preserve_none)); - int _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction *trace, size_t length); void _PyJIT_Free(_PyExecutorObject *executor); diff --git a/Tools/jit/_targets.py b/Tools/jit/_targets.py index d6422e5cdf50cf..ff80a24792c0cc 100644 --- a/Tools/jit/_targets.py +++ b/Tools/jit/_targets.py @@ -26,7 +26,6 @@ PYTHON_EXECUTOR_CASES_C_H = CPYTHON / "Python" / "executor_cases.c.h" TOOLS_JIT_TEMPLATE_C = TOOLS_JIT / "template.c" - _S = typing.TypeVar("_S", _schema.COFFSection, _schema.ELFSection, _schema.MachOSection) _R = typing.TypeVar( "_R", _schema.COFFRelocation, _schema.ELFRelocation, _schema.MachORelocation @@ -111,9 +110,6 @@ def _handle_relocation( async def _compile( self, opname: str, c: pathlib.Path, tempdir: pathlib.Path ) -> _stencils.StencilGroup: - # "Compile" the trampoline to an empty stencil group if it's not needed: - if opname == "trampoline": - return _stencils.StencilGroup() o = tempdir / f"{opname}.o" args = [ f"--target={self.triple}", @@ -127,6 +123,7 @@ async def _compile( f"-I{CPYTHON / 'Include' / 'internal'}", f"-I{CPYTHON / 'Include' / 'internal' / 'mimalloc'}", f"-I{CPYTHON / 'Python'}", + f"-I{CPYTHON / 'Tools' / 'jit'}", "-O3", "-c", # This debug info isn't necessary, and bloats out the JIT'ed code. diff --git a/Tools/jit/jit_definitions.h b/Tools/jit/jit_definitions.h new file mode 100644 index 00000000000000..e8d584bbc6ab25 --- /dev/null +++ b/Tools/jit/jit_definitions.h @@ -0,0 +1,24 @@ +#ifndef JIT_DEFINITIONS_H +#define JIT_DEFINITIONS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +#ifdef _Py_JIT + +// To use preserve_none in JIT builds, we need to declare a separate function pointer with __attribute__((preserve_none)) since this attribute is not supported in < clang 19. +// This is functionally the same as jit_func_native from Include/internal/pycore_jit.h except that it has the __attribute__((preserve_none)) attribute. +typedef _Py_CODEUNIT *(*jit_func_preserve_none)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate) __attribute__((preserve_none)); + +#endif // _Py_JIT + +#ifdef __cplusplus +} +#endif + +#endif // JIT_DEFINITIONS_H \ No newline at end of file diff --git a/Tools/jit/template.c b/Tools/jit/template.c index 59a0781a39ecd0..f764b2eb6f98e3 100644 --- a/Tools/jit/template.c +++ b/Tools/jit/template.c @@ -21,6 +21,8 @@ #include "ceval_macros.h" +#include "jit_definitions.h" + #undef CURRENT_OPARG #define CURRENT_OPARG() (_oparg) diff --git a/Tools/jit/trampoline.c b/Tools/jit/trampoline.c index e460bb1fa1efdc..6afab0808ba57a 100644 --- a/Tools/jit/trampoline.c +++ b/Tools/jit/trampoline.c @@ -4,6 +4,8 @@ #include "pycore_frame.h" #include "pycore_jit.h" +#include "jit_definitions.h" + _Py_CODEUNIT * _ENTRY(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate) { From 4a2f3c438e453ea0c7f8de2aaae6d7b6bb7a7e24 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Mon, 14 Oct 2024 21:28:23 -0700 Subject: [PATCH 20/37] Add newline --- Tools/jit/jit_definitions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/jit/jit_definitions.h b/Tools/jit/jit_definitions.h index e8d584bbc6ab25..3377498c5bdbf3 100644 --- a/Tools/jit/jit_definitions.h +++ b/Tools/jit/jit_definitions.h @@ -21,4 +21,4 @@ typedef _Py_CODEUNIT *(*jit_func_preserve_none)(_PyInterpreterFrame *frame, _PyS } #endif -#endif // JIT_DEFINITIONS_H \ No newline at end of file +#endif // JIT_DEFINITIONS_H From 4c4ca2f31a9a4fffb6a183640317e2c9bc52eb2e Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Mon, 14 Oct 2024 21:35:34 -0700 Subject: [PATCH 21/37] Add newline --- Tools/jit/jit_definitions.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Tools/jit/jit_definitions.h b/Tools/jit/jit_definitions.h index 3377498c5bdbf3..a7446b5d42216c 100644 --- a/Tools/jit/jit_definitions.h +++ b/Tools/jit/jit_definitions.h @@ -22,3 +22,4 @@ typedef _Py_CODEUNIT *(*jit_func_preserve_none)(_PyInterpreterFrame *frame, _PyS #endif #endif // JIT_DEFINITIONS_H + From 7d1745ad49659af9d0da86db1178c8c9f6c2d2eb Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Tue, 15 Oct 2024 19:10:29 -0700 Subject: [PATCH 22/37] Address PR comments --- Tools/jit/_targets.py | 6 +++++- Tools/jit/{jit_definitions.h => jit.h} | 24 +----------------------- Tools/jit/template.c | 2 +- Tools/jit/trampoline.c | 2 +- 4 files changed, 8 insertions(+), 26 deletions(-) rename Tools/jit/{jit_definitions.h => jit.h} (60%) diff --git a/Tools/jit/_targets.py b/Tools/jit/_targets.py index ff80a24792c0cc..cc97b68af80480 100644 --- a/Tools/jit/_targets.py +++ b/Tools/jit/_targets.py @@ -496,7 +496,11 @@ def get_target(host: str) -> _COFF | _ELF | _MachO: ] target = _ELF(host, alignment=8, args=args) elif re.fullmatch(r"i686-pc-windows-msvc", host): - args = ["-DPy_NO_ENABLE_SHARED"] + args = [ + "-DPy_NO_ENABLE_SHARED", + # __attribute__((preserve_none)) is not supported + "-Wno-ignored-attributes" + ] target = _COFF(host, args=args, prefix="_") elif re.fullmatch(r"x86_64-apple-darwin.*", host): target = _MachO(host, prefix="_") diff --git a/Tools/jit/jit_definitions.h b/Tools/jit/jit.h similarity index 60% rename from Tools/jit/jit_definitions.h rename to Tools/jit/jit.h index a7446b5d42216c..37b8f3f2543e21 100644 --- a/Tools/jit/jit_definitions.h +++ b/Tools/jit/jit.h @@ -1,25 +1,3 @@ -#ifndef JIT_DEFINITIONS_H -#define JIT_DEFINITIONS_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif - -#ifdef _Py_JIT - // To use preserve_none in JIT builds, we need to declare a separate function pointer with __attribute__((preserve_none)) since this attribute is not supported in < clang 19. // This is functionally the same as jit_func_native from Include/internal/pycore_jit.h except that it has the __attribute__((preserve_none)) attribute. -typedef _Py_CODEUNIT *(*jit_func_preserve_none)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate) __attribute__((preserve_none)); - -#endif // _Py_JIT - -#ifdef __cplusplus -} -#endif - -#endif // JIT_DEFINITIONS_H - +typedef _Py_CODEUNIT *(*jit_func_preserve_none)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate) __attribute__((preserve_none)); \ No newline at end of file diff --git a/Tools/jit/template.c b/Tools/jit/template.c index f764b2eb6f98e3..57c1006ab423e9 100644 --- a/Tools/jit/template.c +++ b/Tools/jit/template.c @@ -21,7 +21,7 @@ #include "ceval_macros.h" -#include "jit_definitions.h" +#include "jit.h" #undef CURRENT_OPARG #define CURRENT_OPARG() (_oparg) diff --git a/Tools/jit/trampoline.c b/Tools/jit/trampoline.c index 6afab0808ba57a..e09dac1d267bf4 100644 --- a/Tools/jit/trampoline.c +++ b/Tools/jit/trampoline.c @@ -4,7 +4,7 @@ #include "pycore_frame.h" #include "pycore_jit.h" -#include "jit_definitions.h" +#include "jit.h" _Py_CODEUNIT * _ENTRY(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate) From c8d469297955f5c6f1e4ef6fedf51635608e9be4 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Tue, 15 Oct 2024 19:18:27 -0700 Subject: [PATCH 23/37] Replace entry_symbol with string --- Tools/jit/_targets.py | 6 +----- Tools/jit/trampoline.c | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Tools/jit/_targets.py b/Tools/jit/_targets.py index cc97b68af80480..b727b575cad3d3 100644 --- a/Tools/jit/_targets.py +++ b/Tools/jit/_targets.py @@ -86,11 +86,7 @@ async def _parse(self, path: pathlib.Path) -> _stencils.StencilGroup: sections: list[dict[typing.Literal["Section"], _S]] = json.loads(output) for wrapped_section in sections: self._handle_section(wrapped_section["Section"], group) - # The trampoline's entry point is just named "_ENTRY", since on some - # platforms we later assume that any function starting with "_JIT_" uses - # the GHC calling convention: - entry_symbol = "_JIT_ENTRY" if "_JIT_ENTRY" in group.symbols else "_ENTRY" - assert group.symbols[entry_symbol] == (_stencils.HoleValue.CODE, 0) + assert group.symbols["_JIT_ENTRY"] == (_stencils.HoleValue.CODE, 0) if group.data.body: line = f"0: {str(bytes(group.data.body)).removeprefix('b')}" group.data.disassembly.append(line) diff --git a/Tools/jit/trampoline.c b/Tools/jit/trampoline.c index e09dac1d267bf4..f0cffa2f049d26 100644 --- a/Tools/jit/trampoline.c +++ b/Tools/jit/trampoline.c @@ -7,7 +7,7 @@ #include "jit.h" _Py_CODEUNIT * -_ENTRY(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate) +_JIT_ENTRY(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate) { // This is subtle. The actual trace will return to us once it exits, so we // need to make sure that we stay alive until then. If our trace side-exits From 72d5ed082b41e26df981058099957dc53d566c33 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Tue, 15 Oct 2024 19:18:53 -0700 Subject: [PATCH 24/37] Appease linter --- Tools/jit/_targets.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tools/jit/_targets.py b/Tools/jit/_targets.py index b727b575cad3d3..687320b66af623 100644 --- a/Tools/jit/_targets.py +++ b/Tools/jit/_targets.py @@ -493,9 +493,9 @@ def get_target(host: str) -> _COFF | _ELF | _MachO: target = _ELF(host, alignment=8, args=args) elif re.fullmatch(r"i686-pc-windows-msvc", host): args = [ - "-DPy_NO_ENABLE_SHARED", - # __attribute__((preserve_none)) is not supported - "-Wno-ignored-attributes" + "-DPy_NO_ENABLE_SHARED", + # __attribute__((preserve_none)) is not supported + "-Wno-ignored-attributes", ] target = _COFF(host, args=args, prefix="_") elif re.fullmatch(r"x86_64-apple-darwin.*", host): From a96af70ab7d0fb2a6337cb374bff7ea6cd2b7049 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Tue, 15 Oct 2024 19:20:24 -0700 Subject: [PATCH 25/37] Add newline --- Tools/jit/jit.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/jit/jit.h b/Tools/jit/jit.h index 37b8f3f2543e21..1d94b532bb9222 100644 --- a/Tools/jit/jit.h +++ b/Tools/jit/jit.h @@ -1,3 +1,3 @@ // To use preserve_none in JIT builds, we need to declare a separate function pointer with __attribute__((preserve_none)) since this attribute is not supported in < clang 19. // This is functionally the same as jit_func_native from Include/internal/pycore_jit.h except that it has the __attribute__((preserve_none)) attribute. -typedef _Py_CODEUNIT *(*jit_func_preserve_none)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate) __attribute__((preserve_none)); \ No newline at end of file +typedef _Py_CODEUNIT *(*jit_func_preserve_none)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate) __attribute__((preserve_none)); From 5ef69e6d1925c0a7603501f54e836b3d59681854 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Tue, 22 Oct 2024 04:18:56 +0000 Subject: [PATCH 26/37] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst new file mode 100644 index 00000000000000..3c93974a96f187 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst @@ -0,0 +1 @@ +The JIT has been updated to leverage LLVM 19’s preserve_none attribute, which natively supports the Glasgow Haskell Compiler Calling Convention (ghccc) for both x86-64 and AArch64 targets. This removes the need to manually patch the calling convention in LLVM IR, simplifying the JIT compilation process and enhancing performance. Additionally, this update enables optimizations across all platforms, except for i686-pc-windows-msvc where the attribute is not available. From 709bb0850b5a6387016f02f98f6ca0aaa0a6f101 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Mon, 21 Oct 2024 21:23:21 -0700 Subject: [PATCH 27/37] Rephrase --- .../2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst index 3c93974a96f187..e1b0490fc7a125 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst @@ -1 +1,6 @@ -The JIT has been updated to leverage LLVM 19’s preserve_none attribute, which natively supports the Glasgow Haskell Compiler Calling Convention (ghccc) for both x86-64 and AArch64 targets. This removes the need to manually patch the calling convention in LLVM IR, simplifying the JIT compilation process and enhancing performance. Additionally, this update enables optimizations across all platforms, except for i686-pc-windows-msvc where the attribute is not available. +The JIT has been updated to leverage LLVM 19’s preserve_none attribute, which +adds native support for the Glasgow Haskell Compiler Calling Convention (ghccc) +for both x86-64 and AArch64 targets. This removes the need to manually patch +the calling convention in LLVM IR, simplifying the JIT compilation process. +Additionally, this update enables the optimization across all platforms, except +for i686-pc-windows-msvc where the attribute not supported. \ No newline at end of file From 5ca8d61a0df532fb138a83312072d4e665a56f04 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Mon, 21 Oct 2024 21:26:00 -0700 Subject: [PATCH 28/37] Run pre-commit --- .../2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst index e1b0490fc7a125..6c6dc15a687cee 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst @@ -1,6 +1,6 @@ -The JIT has been updated to leverage LLVM 19’s preserve_none attribute, which -adds native support for the Glasgow Haskell Compiler Calling Convention (ghccc) -for both x86-64 and AArch64 targets. This removes the need to manually patch -the calling convention in LLVM IR, simplifying the JIT compilation process. -Additionally, this update enables the optimization across all platforms, except +The JIT has been updated to leverage LLVM 19’s preserve_none attribute, which +adds native support for the Glasgow Haskell Compiler Calling Convention (ghccc) +for both x86-64 and AArch64 targets. This removes the need to manually patch +the calling convention in LLVM IR, simplifying the JIT compilation process. +Additionally, this update enables the optimization across all platforms, except for i686-pc-windows-msvc where the attribute not supported. \ No newline at end of file From 24d9143db573abbac52f7a6debd5e4b5b75a8f5d Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Mon, 21 Oct 2024 21:28:10 -0700 Subject: [PATCH 29/37] Add newline --- .../2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst index 6c6dc15a687cee..a10a6046fc6d19 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst @@ -3,4 +3,4 @@ adds native support for the Glasgow Haskell Compiler Calling Convention (ghccc) for both x86-64 and AArch64 targets. This removes the need to manually patch the calling convention in LLVM IR, simplifying the JIT compilation process. Additionally, this update enables the optimization across all platforms, except -for i686-pc-windows-msvc where the attribute not supported. \ No newline at end of file +for i686-pc-windows-msvc where the attribute not supported. From b351303e04130b0a768b84635fca66d80f9ce566 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Tue, 22 Oct 2024 20:05:22 -0700 Subject: [PATCH 30/37] Add line to remove symlink --- .github/workflows/jit.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/jit.yml b/.github/workflows/jit.yml index 7717ecf33b67b2..5fb599b232dfb5 100644 --- a/.github/workflows/jit.yml +++ b/.github/workflows/jit.yml @@ -121,10 +121,15 @@ jobs: choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}.1.0 ./PCbuild/build.bat --experimental-jit ${{ matrix.debug && '-d' || '' }} -p ${{ matrix.architecture }} + # The `find` line is required as a result of https://github.com/actions/runner-images/issues/9966. + # This is a bug in the macOS runner image where the pre-installed Python is installed in the same + # directory as the Homebrew Python, which causes the build to fail for macos-13. This line removes + # the symlink to the pre-installed Python so that the Homebrew Python is used instead. - name: Native macOS if: runner.os == 'macOS' run: | brew update + find /usr/local/bin -lname '*/Library/Frameworks/Python.framework/*' -delete brew install llvm@${{ matrix.llvm }} SDKROOT="$(xcrun --show-sdk-path)" \ ./configure --enable-experimental-jit ${{ matrix.debug && '--with-pydebug' || '--enable-optimizations --with-lto' }} From fe58a122a8adf16476f59aaaaf3071d0fa6c8657 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Tue, 22 Oct 2024 20:13:56 -0700 Subject: [PATCH 31/37] Fix typo --- .../2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst index a10a6046fc6d19..7c12b3376de543 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst @@ -3,4 +3,4 @@ adds native support for the Glasgow Haskell Compiler Calling Convention (ghccc) for both x86-64 and AArch64 targets. This removes the need to manually patch the calling convention in LLVM IR, simplifying the JIT compilation process. Additionally, this update enables the optimization across all platforms, except -for i686-pc-windows-msvc where the attribute not supported. +for i686-pc-windows-msvc where the attribute is not supported. From 0f889556e568a37ee18d02a920a799ea057a1c6b Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Tue, 22 Oct 2024 20:16:33 -0700 Subject: [PATCH 32/37] Fix wording --- Tools/jit/jit.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/jit/jit.h b/Tools/jit/jit.h index 1d94b532bb9222..84a8461667b9e9 100644 --- a/Tools/jit/jit.h +++ b/Tools/jit/jit.h @@ -1,3 +1,3 @@ // To use preserve_none in JIT builds, we need to declare a separate function pointer with __attribute__((preserve_none)) since this attribute is not supported in < clang 19. -// This is functionally the same as jit_func_native from Include/internal/pycore_jit.h except that it has the __attribute__((preserve_none)) attribute. +// This is functionally the same as jit_func_native from Include/internal/pycore_jit.h except that it has __attribute__((preserve_none)). typedef _Py_CODEUNIT *(*jit_func_preserve_none)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate) __attribute__((preserve_none)); From bb1e65069f16e78ddf755c6ef9a92010b970db1e Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Tue, 29 Oct 2024 15:01:05 -0700 Subject: [PATCH 33/37] Update Misc/NEWS.d/next/Core_and_Builtins/2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst Co-authored-by: Brandt Bucher --- .../2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst index 7c12b3376de543..807c2e07210e7f 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-22-04-18-53.gh-issue-125498.cFjPIn.rst @@ -1,6 +1,4 @@ -The JIT has been updated to leverage LLVM 19’s preserve_none attribute, which -adds native support for the Glasgow Haskell Compiler Calling Convention (ghccc) -for both x86-64 and AArch64 targets. This removes the need to manually patch -the calling convention in LLVM IR, simplifying the JIT compilation process. -Additionally, this update enables the optimization across all platforms, except -for i686-pc-windows-msvc where the attribute is not supported. +The JIT has been updated to leverage Clang 19’s new ``preserve_none`` attribute, +which supports more platforms and is more useful than LLVM's existing ``ghccc`` +calling convention. This also removes the need to manually patch the calling +convention in LLVM IR, simplifying the JIT compilation process. From 5f3ec525986e959dadfd40c48a843ff096ffb453 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Tue, 29 Oct 2024 15:01:50 -0700 Subject: [PATCH 34/37] Apply suggestions from code review Co-authored-by: Brandt Bucher --- Tools/jit/_targets.py | 3 +++ Tools/jit/jit.h | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Tools/jit/_targets.py b/Tools/jit/_targets.py index 687320b66af623..6bf3ec109a252c 100644 --- a/Tools/jit/_targets.py +++ b/Tools/jit/_targets.py @@ -135,6 +135,9 @@ async def _compile( # Don't call stack-smashing canaries that we can't find or patch: "-fno-stack-protector", "-std=c11", + "-o", + f"{o}", + f"{c}", *self.args, ] args_o = args + ["-o", f"{o}", f"{c}"] diff --git a/Tools/jit/jit.h b/Tools/jit/jit.h index 84a8461667b9e9..719b76c514e5c9 100644 --- a/Tools/jit/jit.h +++ b/Tools/jit/jit.h @@ -1,3 +1,4 @@ -// To use preserve_none in JIT builds, we need to declare a separate function pointer with __attribute__((preserve_none)) since this attribute is not supported in < clang 19. -// This is functionally the same as jit_func_native from Include/internal/pycore_jit.h except that it has __attribute__((preserve_none)). +// To use preserve_none in JIT builds, we need to declare a separate function +// pointer with __attribute__((preserve_none)), since this attribute may not be +// supported by the compiler used to build the rest of the interpreter. typedef _Py_CODEUNIT *(*jit_func_preserve_none)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate) __attribute__((preserve_none)); From 46cee9323681bc6206fb2fb396a58e6cf43ca790 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Tue, 29 Oct 2024 15:13:51 -0700 Subject: [PATCH 35/37] Address PR comments --- Include/internal/pycore_jit.h | 2 +- Python/ceval_macros.h | 2 +- Tools/jit/_targets.py | 3 +-- Tools/jit/jit.h | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Include/internal/pycore_jit.h b/Include/internal/pycore_jit.h index 5e59f520c32b73..4d6cc35a7a3de7 100644 --- a/Include/internal/pycore_jit.h +++ b/Include/internal/pycore_jit.h @@ -11,7 +11,7 @@ extern "C" { #ifdef _Py_JIT -typedef _Py_CODEUNIT *(*jit_func_native)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate); +typedef _Py_CODEUNIT *(*jit_func)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate); int _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction *trace, size_t length); void _PyJIT_Free(_PyExecutorObject *executor); diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 3bf3eea1cc0170..c111255016f512 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -378,7 +378,7 @@ _PyFrame_SetStackPointer(frame, stack_pointer) #define GOTO_TIER_TWO(EXECUTOR) \ do { \ OPT_STAT_INC(traces_executed); \ - jit_func_native jitted = (EXECUTOR)->jit_code; \ + jit_func jitted = (EXECUTOR)->jit_code; \ next_instr = jitted(frame, stack_pointer, tstate); \ Py_DECREF(tstate->previous_executor); \ tstate->previous_executor = NULL; \ diff --git a/Tools/jit/_targets.py b/Tools/jit/_targets.py index 6bf3ec109a252c..634208da3c8157 100644 --- a/Tools/jit/_targets.py +++ b/Tools/jit/_targets.py @@ -140,8 +140,7 @@ async def _compile( f"{c}", *self.args, ] - args_o = args + ["-o", f"{o}", f"{c}"] - await _llvm.run("clang", args_o, echo=self.verbose) + await _llvm.run("clang", args, echo=self.verbose) return await self._parse(o) async def _build_stencils(self) -> dict[str, _stencils.StencilGroup]: diff --git a/Tools/jit/jit.h b/Tools/jit/jit.h index 719b76c514e5c9..3f7f9e7dab3653 100644 --- a/Tools/jit/jit.h +++ b/Tools/jit/jit.h @@ -1,4 +1,4 @@ // To use preserve_none in JIT builds, we need to declare a separate function // pointer with __attribute__((preserve_none)), since this attribute may not be // supported by the compiler used to build the rest of the interpreter. -typedef _Py_CODEUNIT *(*jit_func_preserve_none)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate) __attribute__((preserve_none)); +typedef jit_func __attribute__((preserve_none)) jit_func_preserve_none; \ No newline at end of file From c119a5d80bd1bb1b717cf1b23abf24ff237892ea Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Tue, 29 Oct 2024 15:15:40 -0700 Subject: [PATCH 36/37] Fix whitespace --- Python/ceval_macros.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index c111255016f512..6674c4ccf9f693 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -378,7 +378,7 @@ _PyFrame_SetStackPointer(frame, stack_pointer) #define GOTO_TIER_TWO(EXECUTOR) \ do { \ OPT_STAT_INC(traces_executed); \ - jit_func jitted = (EXECUTOR)->jit_code; \ + jit_func jitted = (EXECUTOR)->jit_code; \ next_instr = jitted(frame, stack_pointer, tstate); \ Py_DECREF(tstate->previous_executor); \ tstate->previous_executor = NULL; \ From cbb0ddf78d54cde73bfe043525f8a06a3c58a686 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Tue, 29 Oct 2024 15:17:08 -0700 Subject: [PATCH 37/37] Add newline to jit.h --- Tools/jit/jit.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/jit/jit.h b/Tools/jit/jit.h index 3f7f9e7dab3653..47da64cb12bd24 100644 --- a/Tools/jit/jit.h +++ b/Tools/jit/jit.h @@ -1,4 +1,4 @@ // To use preserve_none in JIT builds, we need to declare a separate function // pointer with __attribute__((preserve_none)), since this attribute may not be // supported by the compiler used to build the rest of the interpreter. -typedef jit_func __attribute__((preserve_none)) jit_func_preserve_none; \ No newline at end of file +typedef jit_func __attribute__((preserve_none)) jit_func_preserve_none;