Skip to content

Commit

Permalink
Rework LLVM into Find module and enact new component policy. (#8379)
Browse files Browse the repository at this point in the history
Our usage of LLVM now requires at least the X86 and WebAssembly
backends. We also now unconditionally enable all backends supported
by the LLVM we found.
  • Loading branch information
alexreinking authored Aug 9, 2024
1 parent 8643007 commit 0058528
Show file tree
Hide file tree
Showing 18 changed files with 298 additions and 324 deletions.
13 changes: 4 additions & 9 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,6 @@ else ()
set(Halide_ANY_SANITIZERS_ENABLED 0)
endif ()

# Enable the SPIR-V target if requested (must declare before processing dependencies)
option(TARGET_SPIRV "Include SPIR-V target" OFF)
option(TARGET_VULKAN "Include Vulkan target" ON)
if (TARGET_VULKAN)
set(TARGET_SPIRV ON) # required
endif()

# Helper function to set C++ compiler warnings in a sane way
function(set_halide_compiler_warnings NAME)
target_compile_options(
Expand Down Expand Up @@ -193,8 +186,10 @@ endfunction()
option(THREADS_PREFER_PTHREAD_FLAG "When enabled, prefer to use the -pthread flag to explicit linking" ON)
find_package(Threads REQUIRED)

## Complex dependencies
add_subdirectory(dependencies/llvm)
## LLVM
find_package(Halide_LLVM 17...20 REQUIRED
COMPONENTS WebAssembly X86
OPTIONAL_COMPONENTS AArch64 AMDGPU ARM Hexagon NVPTX PowerPC RISCV)

## Image formats

Expand Down
4 changes: 2 additions & 2 deletions CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
"displayName": "Debian (Debug)",
"description": "Debug build assuming Debian-provided dependencies",
"cacheVariables": {
"Halide_SHARED_LLVM": "ON"
"Halide_LLVM_SHARED_LIBS": "ON"
}
},
{
Expand Down Expand Up @@ -109,7 +109,7 @@
"inherits": "release",
"cacheVariables": {
"CMAKE_PREFIX_PATH": "/opt/homebrew;/opt/homebrew/opt/llvm;/opt/homebrew/opt/jpeg",
"Halide_SHARED_LLVM": "YES"
"Halide_LLVM_SHARED_LIBS": "YES"
}
},
{
Expand Down
12 changes: 6 additions & 6 deletions README_cmake.md
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ compiled.
|------------------------------------------|-----------------------|------------------------------------------------------------------------------------------------------------------|
| [`BUILD_SHARED_LIBS`][build_shared_libs] | `ON` | Standard CMake variable that chooses whether to build as a static or shared library. |
| `Halide_BUNDLE_LLVM` | `OFF` | When building Halide as a static library, unpack the LLVM static libraries and add those objects to libHalide.a. |
| `Halide_SHARED_LLVM` | `OFF` | Link to the shared version of LLVM. Not available on Windows. |
| `Halide_LLVM_SHARED_LIBS` | `OFF` | Link to the shared version of LLVM. Not available on Windows. |
| `Halide_ENABLE_RTTI` | _inherited from LLVM_ | Enable RTTI when building Halide. Recommended to be set to `ON` |
| `Halide_ENABLE_EXCEPTIONS` | `ON` | Enable exceptions when building Halide |
| `Halide_TARGET` | _empty_ | The default target triple to use for `add_halide_library` (and the generator tests, by extension) |
Expand Down Expand Up @@ -589,7 +589,7 @@ If Halide is not globally installed, you will need to add the root of the Halide
installation directory to [`CMAKE_PREFIX_PATH`][cmake_prefix_path] at the CMake
command line.

```
```console
dev@ubuntu:~/myproj$ cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="/path/to/Halide-install" -S . -B build
```

Expand Down Expand Up @@ -784,10 +784,10 @@ Variables set by the package:

Variables that control package behavior:

| Variable | Description |
|----------------------------|-------------|
| `Halide_PYTHON_LAUNCHER` | Semicolon separated list containing a command to launch the Python interpreter. Can be used to set environment variables for Python generators. |
| `Halide_NO_DEFAULT_FLAGS` | Off by default. When enabled, suppresses recommended compiler flags that would be added by `add_halide_generator` |
| Variable | Description |
|---------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------|
| `Halide_PYTHON_LAUNCHER` | Semicolon separated list containing a command to launch the Python interpreter. Can be used to set environment variables for Python generators. |
| `Halide_NO_DEFAULT_FLAGS` | Off by default. When enabled, suppresses recommended compiler flags that would be added by `add_halide_generator` |


### Imported targets
Expand Down
150 changes: 150 additions & 0 deletions cmake/FindHalide_LLVM.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# This file wraps the upstream package config modules for LLVM, Clang, and LLD
# to fix pathological issues in their implementations. It creates imported targets
# that wrap the key features needed by Halide.

set(REASON_FAILURE_MESSAGE "")

# Fallback configurations for weirdly built LLVMs
set(CMAKE_MAP_IMPORTED_CONFIG_MINSIZEREL MinSizeRel Release RelWithDebInfo "")
set(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBINFO RelWithDebInfo Release MinSizeRel "")
set(CMAKE_MAP_IMPORTED_CONFIG_RELEASE Release MinSizeRel RelWithDebInfo "")

find_package(LLVM ${PACKAGE_FIND_VERSION} CONFIG)

set(Halide_LLVM_VERSION "${LLVM_PACKAGE_VERSION}")

# TODO: deprecated in Halide 19.0.0, remove in Halide 20.0.0
if (NOT DEFINED Halide_LLVM_SHARED_LIBS AND DEFINED Halide_SHARED_LLVM)
set(Halide_LLVM_SHARED_LIBS "${Halide_SHARED_LLVM}")
message(DEPRECATION
"Halide_SHARED_LLVM has been renamed to Halide_LLVM_SHARED_LIBS.")
endif ()

if (NOT DEFINED Halide_LLVM_SHARED_LIBS)
# Normally, we don't like making decisions for our users. However,
# this avoids an incompatible scenario that is checked below. So
# if we didn't do this, the package would fail to be found and
# the user would have to either rebuild LLVM or flip this value.
if (LLVM_FOUND AND "WebAssembly" IN_LIST LLVM_TARGETS_TO_BUILD AND LLVM_LINK_LLVM_DYLIB)
set(Halide_LLVM_SHARED_LIBS YES)
else ()
set(Halide_LLVM_SHARED_LIBS NO)
endif ()
endif ()

option(Halide_LLVM_SHARED_LIBS "Enable to link to shared libLLVM" "${Halide_LLVM_SHARED_LIBS}")

if (LLVM_FOUND)
find_package(Clang HINTS "${LLVM_INSTALL_PREFIX}" "${LLVM_DIR}/../clang" "${LLVM_DIR}/../lib/cmake/clang")

foreach (comp IN LISTS LLVM_TARGETS_TO_BUILD)
if (comp STREQUAL "WebAssembly")
set(Halide_LLVM_${comp}_FOUND 0)

find_package(LLD HINTS "${LLVM_INSTALL_PREFIX}" "${LLVM_DIR}/../lld" "${LLVM_DIR}/../lib/cmake/lld")
if (NOT LLD_FOUND)
string(APPEND REASON_FAILURE_MESSAGE
"WebAssembly was not found because liblld is missing. Did you install liblld-dev?\n")
continue()
endif ()

# LLVM has a mis-feature that allows it to build and export both static and shared libraries at the same
# time, while inconsistently linking its own static libraries (for lldWasm and others) to the shared
# library. Ignoring this causes Halide to link to both the static AND the shared LLVM libs and it breaks at
# runtime. See: https://github.com/halide/Halide/issues/5471
if (LLVM_LINK_LLVM_DYLIB AND NOT Halide_LLVM_SHARED_LIBS)
string(APPEND REASON_FAILURE_MESSAGE
"WebAssembly was not found because LLD required by was linked to shared LLVM "
"(LLVM_LINK_LLVM_DYLIB=${LLVM_LINK_LLVM_DYLIB}) but static LLVM was requested "
"(Halide_LLVM_SHARED_LIBS=${Halide_LLVM_SHARED_LIBS}).\n")
continue()
endif ()
endif ()

set(Halide_LLVM_${comp}_FOUND 1)
endforeach ()

set(Halide_LLVM_SHARED_LIBRARY "LLVM")
if (Halide_LLVM_SHARED_LIBS AND NOT TARGET "${Halide_LLVM_SHARED_LIBRARY}")
string(APPEND Halide_LLVM_SHARED_LIBRARY "-NOTFOUND")
string(APPEND REASON_FAILURE_MESSAGE
"Halide_LLVM_SHARED_LIBS=${Halide_LLVM_SHARED_LIBS} but the shared LLVM target does not exist.\n")
endif ()
endif ()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(
Halide_LLVM
REQUIRED_VARS LLVM_CONFIG Clang_CONFIG Halide_LLVM_SHARED_LIBRARY
VERSION_VAR Halide_LLVM_VERSION
REASON_FAILURE_MESSAGE "${REASON_FAILURE_MESSAGE}"
HANDLE_COMPONENTS
HANDLE_VERSION_RANGE
NAME_MISMATCHED
)

function(_Halide_LLVM_link target visibility)
llvm_map_components_to_libnames(comps ${ARGN})
target_link_libraries("${target}" "${visibility}" ${comps})
endfunction()

if (Halide_LLVM_FOUND)
set(Halide_LLVM_COMPONENTS "")
foreach (comp IN LISTS Halide_LLVM_FIND_COMPONENTS)
if (Halide_LLVM_${comp}_FOUND)
list(APPEND Halide_LLVM_COMPONENTS "${comp}")
endif ()
endforeach ()

if (NOT TARGET Halide_LLVM::Core)
add_library(Halide_LLVM::Core INTERFACE IMPORTED)

# LLVM_DEFINITIONS is a space-separated list instead of a more typical
# CMake semicolon-separated list. For a long time, CMake could handle
# this transparently but, since LLVM 17, the flag -D_FILE_OFFSET_BITS=64
# appears on 32-bit Linux. The presence of the `=` here stops CMake
# from splitting on spaces, instead corrupting the command line by
# folding the other flags into the value of -D_FILE_OFFSET_BITS=64.
# For better or worse, since the flag also appears twice, the second
# `=` is folded into the value of the first and we get errors of the
# form:
#
# <command-line>: error: token "=" is not valid in preprocessor expressions
#
separate_arguments(LLVM_DEFINITIONS NATIVE_COMMAND "${LLVM_DEFINITIONS}")
list(REMOVE_ITEM LLVM_DEFINITIONS "-D_GLIBCXX_ASSERTIONS") # work around https://reviews.llvm.org/D142279
list(APPEND LLVM_DEFINITIONS "LLVM_VERSION=${LLVM_VERSION_MAJOR}${LLVM_VERSION_MINOR}")

target_compile_definitions(Halide_LLVM::Core INTERFACE ${LLVM_DEFINITIONS})
target_include_directories(Halide_LLVM::Core INTERFACE "${LLVM_INCLUDE_DIRS}")

set_property(TARGET Halide_LLVM::Core PROPERTY INTERFACE_CXX_RTTI "${LLVM_ENABLE_RTTI}")
set_property(TARGET Halide_LLVM::Core APPEND PROPERTY COMPATIBLE_INTERFACE_BOOL CXX_RTTI)

if (LLVM_LIBCXX GREATER -1)
target_compile_options(Halide_LLVM::Core INTERFACE "$<$<LINK_LANGUAGE:CXX>:-stdlib=libc++>")
target_link_options(Halide_LLVM::Core INTERFACE "$<$<LINK_LANGUAGE:CXX>:-stdlib=libc++>")
endif ()

if (Halide_LLVM_SHARED_LIBS)
target_link_libraries(Halide_LLVM::Core INTERFACE LLVM ${CMAKE_DL_LIBS})
else ()
_Halide_LLVM_link(Halide_LLVM::Core INTERFACE orcjit bitwriter linker passes)
endif ()
endif ()

foreach (comp IN LISTS Halide_LLVM_COMPONENTS)
if (NOT TARGET Halide_LLVM::${comp})
add_library(Halide_LLVM::${comp} INTERFACE IMPORTED)
target_link_libraries(Halide_LLVM::${comp} INTERFACE Halide_LLVM::Core)

if (NOT Halide_LLVM_SHARED_LIBS)
_Halide_LLVM_link(Halide_LLVM::${comp} INTERFACE ${comp})
endif ()

if (comp STREQUAL "WebAssembly")
target_link_libraries(Halide_LLVM::WebAssembly INTERFACE lldWasm)
endif ()
endif ()
endforeach ()
endif ()
5 changes: 2 additions & 3 deletions dependencies/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# Dependencies

## LLVM / WASM

These are Halide's wrappers for the LLVM and WASM CMake builds/packages.
This folder contains vendored dependencies for building Halide. They do not
form part of the API surface.

## SPIR-V

Expand Down
Loading

0 comments on commit 0058528

Please sign in to comment.