diff --git a/.github/workflows/jit.yml b/.github/workflows/jit.yml index 754f179f105591..7717ecf33b67b2 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 @@ -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 @@ -172,8 +176,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 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 diff --git a/Tools/jit/README.md b/Tools/jit/README.md index bc6f793b296f12..801c64e4059ccc 100644 --- a/Tools/jit/README.md +++ b/Tools/jit/README.md @@ -7,49 +7,46 @@ 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: ### Linux -Install LLVM 18 on Ubuntu/Debian: +Install LLVM 19 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' +sudo dnf install 'clang(major) = 19' 'llvm(major) = 19' ``` ### 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 - -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 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") diff --git a/Tools/jit/_stencils.py b/Tools/jit/_stencils.py index bbb52f391f4b01..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 @@ -132,8 +133,18 @@ 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 +152,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 7b99d10310a645..c76971546b89f9 100644 --- a/Tools/jit/_writer.py +++ b/Tools/jit/_writer.py @@ -62,7 +62,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)}"