diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c3d72e2c9..160354317 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -18,6 +18,11 @@ jobs: PYTHON: '3.12' CONDA_ENV: cienv + llvm15: + PYTHON: '3.12' + CONDA_ENV: cienv + LLVM: '15' + - template: buildscripts/azure/azure-linux-macos.yml parameters: name: Linux @@ -67,6 +72,11 @@ jobs: CONDA_ENV: cienv BUILD_DOCS: 'yes' + llvm15: + PYTHON: '3.12' + CONDA_ENV: cienv + LLVM: '15' + - template: buildscripts/azure/azure-windows.yml parameters: name: Windows diff --git a/buildscripts/azure/azure-windows.yml b/buildscripts/azure/azure-windows.yml index bfb20e177..fd61bb7a8 100644 --- a/buildscripts/azure/azure-windows.yml +++ b/buildscripts/azure/azure-windows.yml @@ -22,6 +22,10 @@ jobs: PYTHON: '3.12' CONDA_ENV: cienv + llvm15: + PYTHON: '3.12' + CONDA_ENV: cienv + LLVM: '15' steps: @@ -33,11 +37,7 @@ jobs: - script: | call C:\Miniconda3\Scripts\activate.bat - call conda list - call conda remove --all -q -y -n %CONDA_ENV% - call conda create -n %CONDA_ENV% -q -y python=%PYTHON% cmake - call activate %CONDA_ENV% - call conda install -y -q -c numba/label/dev llvmdev="14.*" libxml2 + call buildscripts\\incremental\\setup_conda_environment.cmd displayName: 'Before Install' - script: | diff --git a/buildscripts/incremental/build.cmd b/buildscripts/incremental/build.cmd index 4588d2490..182cdde8f 100644 --- a/buildscripts/incremental/build.cmd +++ b/buildscripts/incremental/build.cmd @@ -1,4 +1,23 @@ call activate %CONDA_ENV% +@rem LLVM derives the location of diaguids.lib from the build-time environment. +@rem Conda-forge packaging works around this by substituting the build-time +@rem location of Visual Studio with $ENV{VSINSTALLDIR}. In order to ensure that +@rem this environment variable is set appropriately, we activate the Visual +@rem Studio Developer Command Prompt prior to running setup.py +@rem +@rem This workaround is required whilst using LLVM from conda-forge; it may also +@rem be necessary to consider a workaround for our own llvmdev packages. +@rem +@rem For more info, see: +@rem +@rem - https://github.com/conda-forge/llvmdev-feedstock/issues/175 +@rem - https://github.com/conda-forge/llvmdev-feedstock/pull/223 +@rem - https://github.com/MicrosoftDocs/visualstudio-docs/issues/7774 +if "%LLVM%"=="15" ( + call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat" + if %errorlevel% neq 0 exit /b %errorlevel% +) + python setup.py build diff --git a/buildscripts/incremental/setup_conda_environment.cmd b/buildscripts/incremental/setup_conda_environment.cmd index e3b66574e..afd47c5f2 100644 --- a/buildscripts/incremental/setup_conda_environment.cmd +++ b/buildscripts/incremental/setup_conda_environment.cmd @@ -1,24 +1,24 @@ -@rem The cmd /C hack circumvents a regression where conda installs a conda.bat -@rem script in non-root environments. -set CONDA_INSTALL=cmd /C conda install -q -y -set PIP_INSTALL=pip install -q - @echo on -@rem Deactivate any environment -call deactivate @rem Display root environment (for debugging) -conda list +call conda list + @rem Clean up any left-over from a previous build -conda remove --all -q -y -n %CONDA_ENV% +call conda remove --all -q -y -n %CONDA_ENV% @rem Create and populate environment -conda create -n %CONDA_ENV% -q -y python=%PYTHON% cmake +call conda create -n %CONDA_ENV% -q -y python=%PYTHON% cmake if %errorlevel% neq 0 exit /b %errorlevel% call activate %CONDA_ENV% if %errorlevel% neq 0 exit /b %errorlevel% @rem Install llvmdev -%CONDA_INSTALL% -c numba/label/dev llvmdev="14.*" +if "%LLVM%"=="15" ( + set LLVMDEV_CHANNEL="conda-forge" +) else ( + set LLVMDEV_CHANNEL="numba/label/dev" +) + +call conda install -y -q -c %LLVMDEV_CHANNEL% llvmdev="%LLVM%" libxml2 if %errorlevel% neq 0 exit /b %errorlevel% diff --git a/buildscripts/incremental/setup_conda_environment.sh b/buildscripts/incremental/setup_conda_environment.sh index 20008b264..7dd431848 100755 --- a/buildscripts/incremental/setup_conda_environment.sh +++ b/buildscripts/incremental/setup_conda_environment.sh @@ -27,7 +27,11 @@ source activate $CONDA_ENV set -v # Install llvmdev (separate channel, for now) -$CONDA_INSTALL -c numba/label/dev llvmdev="14.*" +if [ "$LLVM" == "15" ]; then + $CONDA_INSTALL -c conda-forge llvmdev="15" +else + $CONDA_INSTALL -c numba/label/dev llvmdev="14.*" +fi # Install the compiler toolchain, for osx, bootstrapping needed # which happens in build.sh diff --git a/ffi/CMakeLists.txt b/ffi/CMakeLists.txt index 6dce3d152..907b1e1ec 100755 --- a/ffi/CMakeLists.txt +++ b/ffi/CMakeLists.txt @@ -11,6 +11,10 @@ if(NOT MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -g") endif() +# Work around llvm/llvm-project#83802 - LLVM's Findzstd.cmake uses variables +# that require including `GNUInstallDirs`, but it does not include it itself. +include(GNUInstallDirs) + find_package(LLVM REQUIRED CONFIG) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") diff --git a/ffi/build.py b/ffi/build.py index f4f8c69fa..97bdda426 100755 --- a/ffi/build.py +++ b/ffi/build.py @@ -53,6 +53,13 @@ def run_llvm_config(llvm_config, args): return out +def show_warning(message): + header = ' * '.join(("WARNING",) * 8) + blk = '=' * 80 + warning = f'{blk}\n{header}\n{blk}' + print(f"{warning}\n{message}\n{warning}") + + def find_windows_generator(): """ Find a suitable cmake "generator" under Windows. @@ -156,16 +163,16 @@ def main_posix(kind, library_ext): "overridden.\nThis is unsupported behaviour, llvmlite may not " "work as intended.\nRequested LLVM version: {}".format( out.strip())) - warn = ' * '.join(("WARNING",) * 8) - blk = '=' * 80 - warning = '{}\n{}\n{}'.format(blk, warn, blk) - print(warning) - print(msg) - print(warning + '\n') + show_warning(msg) else: (version, _) = out.split('.', 1) version = int(version) - if version != 14: + if version == 15: + msg = ("Building with LLVM 15; note that LLVM 15 support is " + "presently experimental") + show_warning(msg) + elif version != 14: + msg = ("Building llvmlite requires LLVM 14, got " "{!r}. Be sure to set LLVM_CONFIG to the right executable " "path.\nRead the documentation at " diff --git a/ffi/core.cpp b/ffi/core.cpp index 4afc7f7fd..0a4c5bb10 100644 --- a/ffi/core.cpp +++ b/ffi/core.cpp @@ -21,10 +21,22 @@ API_EXPORT(void) LLVMPY_DisposeString(const char *msg) { free(const_cast(msg)); } API_EXPORT(LLVMContextRef) -LLVMPY_GetGlobalContext() { return LLVMGetGlobalContext(); } +LLVMPY_GetGlobalContext() { + auto context = LLVMGetGlobalContext(); +#if LLVM_VERSION_MAJOR > 14 + LLVMContextSetOpaquePointers(context, false); +#endif + return context; +} API_EXPORT(LLVMContextRef) -LLVMPY_ContextCreate() { return LLVMContextCreate(); } +LLVMPY_ContextCreate() { + LLVMContextRef context = LLVMContextCreate(); +#if LLVM_VERSION_MAJOR > 14 + LLVMContextSetOpaquePointers(context, false); +#endif + return context; +} API_EXPORT(void) LLVMPY_ContextDispose(LLVMContextRef context) { diff --git a/ffi/core.h b/ffi/core.h index 4888f8001..2d54d4453 100644 --- a/ffi/core.h +++ b/ffi/core.h @@ -2,6 +2,11 @@ #define LLVMPY_CORE_H_ #include "llvm-c/Core.h" + +// Needed for macros that control version-specific behaviour - included here so +// that they are available in all ffi translation units +#include "llvm/Config/llvm-config.h" + #include #include diff --git a/ffi/orcjit.cpp b/ffi/orcjit.cpp index eac3f96b7..60a4d8f3a 100644 --- a/ffi/orcjit.cpp +++ b/ffi/orcjit.cpp @@ -158,7 +158,12 @@ LLVMPY_LLJITLookup(std::shared_ptr *lljit, const char *dylib_name, return nullptr; } +#if LLVM_VERSION_MAJOR > 14 + *addr = sym->getValue(); +#else *addr = sym->getAddress(); +#endif + return new JITDylibTracker(*lljit, *dylib, std::move(dylib->createResourceTracker())); } @@ -334,7 +339,11 @@ LLVMPY_LLJIT_Link(std::shared_ptr *lljit, const char *libraryName, LLVMDisposeErrorMessage(message); return nullptr; } +#if LLVM_VERSION_MAJOR > 14 + exports[export_idx].address = lookup->getValue(); +#else exports[export_idx].address = lookup->getAddress(); +#endif } return new JITDylibTracker(*lljit, *dylib, std::move(dylib->getDefaultResourceTracker())); diff --git a/ffi/passmanagers.cpp b/ffi/passmanagers.cpp index 1e14660ae..da4a076b4 100644 --- a/ffi/passmanagers.cpp +++ b/ffi/passmanagers.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include using namespace llvm; @@ -161,8 +162,13 @@ LLVMPY_AddCallGraphDOTPrinterPass(LLVMPassManagerRef PM) { API_EXPORT(void) LLVMPY_AddDotDomPrinterPass(LLVMPassManagerRef PM, bool showBody) { +#if LLVM_VERSION_MAJOR > 14 + unwrap(PM)->add(showBody ? llvm::createDomPrinterWrapperPassPass() + : llvm::createDomOnlyPrinterWrapperPassPass()); +#else unwrap(PM)->add(showBody ? llvm::createDomPrinterPass() : llvm::createDomOnlyPrinterPass()); +#endif } API_EXPORT(void) @@ -172,8 +178,13 @@ LLVMPY_AddGlobalsModRefAAPass(LLVMPassManagerRef PM) { API_EXPORT(void) LLVMPY_AddDotPostDomPrinterPass(LLVMPassManagerRef PM, bool showBody) { +#if LLVM_VERSION_MAJOR > 14 + unwrap(PM)->add(showBody ? llvm::createPostDomPrinterWrapperPassPass() + : llvm::createPostDomOnlyPrinterWrapperPassPass()); +#else unwrap(PM)->add(showBody ? llvm::createPostDomPrinterPass() : llvm::createPostDomOnlyPrinterPass()); +#endif } API_EXPORT(void) @@ -244,10 +255,12 @@ LLVMPY_AddAlwaysInlinerPass(LLVMPassManagerRef PM, bool insertLifetime) { unwrap(PM)->add(llvm::createAlwaysInlinerLegacyPass(insertLifetime)); } +#if LLVM_VERSION_MAJOR < 15 API_EXPORT(void) LLVMPY_AddArgPromotionPass(LLVMPassManagerRef PM, unsigned int maxElements) { unwrap(PM)->add(llvm::createArgumentPromotionPass(maxElements)); } +#endif API_EXPORT(void) LLVMPY_AddBreakCriticalEdgesPass(LLVMPassManagerRef PM) { @@ -336,8 +349,12 @@ LLVMPY_AddLoopUnrollAndJamPass(LLVMPassManagerRef PM) { API_EXPORT(void) LLVMPY_AddLoopUnswitchPass(LLVMPassManagerRef PM, bool optimizeForSize, bool hasBranchDivergence) { +#if LLVM_VERSION_MAJOR > 14 + unwrap(PM)->add(createSimpleLoopUnswitchLegacyPass(optimizeForSize)); +#else unwrap(PM)->add( createLoopUnswitchPass(optimizeForSize, hasBranchDivergence)); +#endif } API_EXPORT(void) diff --git a/ffi/value.cpp b/ffi/value.cpp index c29606e49..103bd3222 100644 --- a/ffi/value.cpp +++ b/ffi/value.cpp @@ -6,6 +6,9 @@ // the following is needed for WriteGraph() #include "llvm/Analysis/CFGPrinter.h" +#if LLVM_VERSION_MAJOR > 14 +#include "llvm/Support/GraphWriter.h" +#endif /* An iterator around a attribute list, including the stop condition */ struct AttributeListIterator { diff --git a/llvmlite/binding/passmanagers.py b/llvmlite/binding/passmanagers.py index c5fcf919c..af6152f63 100644 --- a/llvmlite/binding/passmanagers.py +++ b/llvmlite/binding/passmanagers.py @@ -3,6 +3,7 @@ from collections import namedtuple from enum import IntFlag from llvmlite.binding import ffi +from llvmlite.binding.initfini import llvm_version_info import os from tempfile import mkstemp from llvmlite.binding.common import _encode_string @@ -10,6 +11,8 @@ _prunestats = namedtuple('PruneStats', ('basicblock diamond fanout fanout_raise')) +llvm_version_major = llvm_version_info[0] + class PruneStats(_prunestats): """ Holds statistics from reference count pruning. @@ -258,6 +261,8 @@ def add_arg_promotion_pass(self, max_elements=3): LLVM 14: `llvm::createArgumentPromotionPass` """ # noqa E501 + if llvm_version_major > 14: + raise RuntimeError('ArgumentPromotionPass unavailable in LLVM > 14') ffi.lib.LLVMPY_AddArgPromotionPass(self, max_elements) def add_break_critical_edges_pass(self): @@ -466,9 +471,9 @@ def add_loop_unswitch_pass(self, See https://llvm.org/docs/Passes.html#loop-unswitch-unswitch-loops LLVM 14: `llvm::createLoopUnswitchPass` + LLVM 15: `llvm::createSimpleLoopUnswitchLegacyPass` """ # noqa E501 - ffi.lib.LLVMPY_AddLoopUnswitchPass(self, - optimize_for_size, + ffi.lib.LLVMPY_AddLoopUnswitchPass(self, optimize_for_size, has_branch_divergence) def add_lower_atomic_pass(self): @@ -866,7 +871,11 @@ def run_with_remarks(self, function, remarks_format='yaml', ffi.lib.LLVMPY_AddScalarEvolutionAAPass.argtypes = [ffi.LLVMPassManagerRef] ffi.lib.LLVMPY_AddAggressiveDCEPass.argtypes = [ffi.LLVMPassManagerRef] ffi.lib.LLVMPY_AddAlwaysInlinerPass.argtypes = [ffi.LLVMPassManagerRef, c_bool] -ffi.lib.LLVMPY_AddArgPromotionPass.argtypes = [ffi.LLVMPassManagerRef, c_uint] + +if llvm_version_major < 15: + ffi.lib.LLVMPY_AddArgPromotionPass.argtypes = [ + ffi.LLVMPassManagerRef, c_uint] + ffi.lib.LLVMPY_AddBreakCriticalEdgesPass.argtypes = [ffi.LLVMPassManagerRef] ffi.lib.LLVMPY_AddDeadStoreEliminationPass.argtypes = [ ffi.LLVMPassManagerRef] @@ -883,10 +892,8 @@ def run_with_remarks(self, function, remarks_format='yaml', ffi.lib.LLVMPY_AddLoopSimplificationPass.argtypes = [ffi.LLVMPassManagerRef] ffi.lib.LLVMPY_AddLoopUnrollPass.argtypes = [ffi.LLVMPassManagerRef] ffi.lib.LLVMPY_AddLoopUnrollAndJamPass.argtypes = [ffi.LLVMPassManagerRef] -ffi.lib.LLVMPY_AddLoopUnswitchPass.argtypes = [ - ffi.LLVMPassManagerRef, - c_bool, - c_bool] +ffi.lib.LLVMPY_AddLoopUnswitchPass.argtypes = [ffi.LLVMPassManagerRef, c_bool, + c_bool] ffi.lib.LLVMPY_AddLowerAtomicPass.argtypes = [ffi.LLVMPassManagerRef] ffi.lib.LLVMPY_AddLowerInvokePass.argtypes = [ffi.LLVMPassManagerRef] ffi.lib.LLVMPY_AddLowerSwitchPass.argtypes = [ffi.LLVMPassManagerRef] diff --git a/llvmlite/tests/test_binding.py b/llvmlite/tests/test_binding.py index 9583a602c..215ee0f41 100644 --- a/llvmlite/tests/test_binding.py +++ b/llvmlite/tests/test_binding.py @@ -18,6 +18,7 @@ from llvmlite.binding import ffi from llvmlite.tests import TestCase +llvm_version_major = llvm.llvm_version_info[0] # arvm7l needs extra ABI symbols to link successfully if platform.machine() == 'armv7l': @@ -653,7 +654,7 @@ def break_up_asm(self, asm): def test_rv32d_ilp32(self): self.check_riscv_target() llmod = self.fpadd_ll_module() - target = self.riscv_target_machine(features="+f,+d") + target = self.riscv_target_machine(features="+f,+d", abiname="ilp32") self.assertEqual(self.break_up_asm(target.emit_assembly(llmod)), riscv_asm_ilp32) @@ -786,9 +787,9 @@ def test_set_option(self): def test_version(self): major, minor, patch = llvm.llvm_version_info # one of these can be valid - valid = [(14, )] - self.assertIn((major,), valid) - self.assertIn(patch, range(10)) + valid = (14, 15) + self.assertIn(major, valid) + self.assertIn(patch, range(8)) def test_check_jit_execution(self): llvm.check_jit_execution() @@ -2176,7 +2177,8 @@ def test_populate(self): pm.add_aggressive_dead_code_elimination_pass() pm.add_aa_eval_pass() pm.add_always_inliner_pass() - pm.add_arg_promotion_pass(42) + if llvm_version_major < 15: + pm.add_arg_promotion_pass(42) pm.add_break_critical_edges_pass() pm.add_dead_store_elimination_pass() pm.add_reverse_post_order_function_attrs_pass() @@ -2191,7 +2193,8 @@ def test_populate(self): pm.add_loop_simplification_pass() pm.add_loop_unroll_pass() pm.add_loop_unroll_and_jam_pass() - pm.add_loop_unswitch_pass() + if llvm_version_major < 15: + pm.add_loop_unswitch_pass() pm.add_lower_atomic_pass() pm.add_lower_invoke_pass() pm.add_lower_switch_pass()