| # Copyright 2023 The IREE Authors |
| # |
| # Licensed under the Apache License v2.0 with LLVM Exceptions. |
| # See https://llvm.org/LICENSE.txt for license information. |
| # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| |
| # Support for configuring LLVM/MLIR and dependent sub-projects. |
| # There are three top-level entry-points: |
| # iree_llvm_configure_bundled() : Configures the bundled LLVM and |
| # sub-projects from third_party. |
| # iree_llvm_configure_installed() : Configures from installed LLVM and |
| # sub-projects. |
| # iree_add_llvm_external_project(...) : Adds an external LLVM project in |
| # a similar fashion to LLVM_EXTERNAL_PROJECTS define (but in a way that |
| # does not require a source build of LLVM). |
| |
| macro(iree_llvm_configure_bundled) |
| message(STATUS "Adding bundled LLVM source dependency") |
| iree_llvm_set_bundled_cmake_options() |
| |
| # Enable MLIR Python bindings if IREE Python bindings enabled. |
| if(IREE_BUILD_PYTHON_BINDINGS) |
| set(MLIR_ENABLE_BINDINGS_PYTHON ON) |
| set(MHLO_ENABLE_BINDINGS_PYTHON ON) |
| endif() |
| |
| # Disable LLVM's warnings. |
| set(LLVM_ENABLE_WARNINGS OFF) |
| |
| # Stash cmake build type in case LLVM messes with it. |
| set(_CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}") |
| |
| # Setup LLVM lib and bin directories. |
| set(LLVM_LIBRARY_OUTPUT_INTDIR "${CMAKE_CURRENT_BINARY_DIR}/llvm-project/lib") |
| set(LLVM_RUNTIME_OUTPUT_INTDIR "${CMAKE_CURRENT_BINARY_DIR}/llvm-project/bin") |
| |
| message(STATUS "Configuring third_party/llvm-project") |
| list(APPEND CMAKE_MESSAGE_INDENT " ") |
| set(_BUNDLED_LLVM_CMAKE_SOURCE_SUBDIR "third_party/llvm-project/llvm") |
| add_subdirectory("${_BUNDLED_LLVM_CMAKE_SOURCE_SUBDIR}" "llvm-project" EXCLUDE_FROM_ALL) |
| get_directory_property(LLVM_VERSION_MAJOR DIRECTORY "${_BUNDLED_LLVM_CMAKE_SOURCE_SUBDIR}" LLVM_VERSION_MAJOR) |
| if (NOT LLVM_VERSION_MAJOR) |
| message(SEND_ERROR "Failed to read LLVM_VERSION_MAJOR property on LLVM directory. Should have been set since https://github.com/llvm/llvm-project/pull/83346.") |
| endif() |
| |
| list(POP_BACK CMAKE_MESSAGE_INDENT) |
| |
| # Reset CMAKE_BUILD_TYPE to its previous setting. |
| set(CMAKE_BUILD_TYPE "${_CMAKE_BUILD_TYPE}" ) |
| |
| # Set some CMake variables that mirror things exported in the find_package |
| # world. Source of truth for these is in an installed LLVMConfig.cmake, |
| # MLIRConfig.cmake, LLDConfig.cmake (etc) and in the various standalone |
| # build segments of each project's top-level CMakeLists. |
| set(LLVM_CMAKE_DIR "${IREE_BINARY_DIR}/llvm-project/lib/cmake/llvm") |
| list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") |
| # TODO: Fix MLIR upstream so it doesn't spew into the containing project |
| # binary dir. See mlir/cmake/modules/CMakeLists.txt |
| # (and other LLVM sub-projects). |
| set(MLIR_CMAKE_DIR "${CMAKE_BINARY_DIR}/lib/cmake/mlir") |
| if(NOT EXISTS "${MLIR_CMAKE_DIR}/AddMLIR.cmake") |
| message(SEND_ERROR "Could not find AddMLIR.cmake in ${MLIR_CMAKE_DIR}: LLVM sub-projects may have changed their layout. See the mlir_cmake_builddir variable in mlir/cmake/modules/CMakeLists.txt") |
| endif() |
| list(APPEND CMAKE_MODULE_PATH "${MLIR_CMAKE_DIR}") |
| |
| set(LLVM_INCLUDE_DIRS |
| ${IREE_SOURCE_DIR}/${_BUNDLED_LLVM_CMAKE_SOURCE_SUBDIR}/include |
| ${IREE_BINARY_DIR}/llvm-project/include |
| ) |
| set(MLIR_INCLUDE_DIRS |
| ${IREE_SOURCE_DIR}/third_party/llvm-project/mlir/include |
| ${IREE_BINARY_DIR}/llvm-project/tools/mlir/include |
| ) |
| set(LLD_INCLUDE_DIRS |
| ${IREE_SOURCE_DIR}/third_party/llvm-project/lld/include |
| ${IREE_BINARY_DIR}/llvm-project/tools/lld/include |
| ) |
| |
| set(LLVM_BINARY_DIR "${IREE_BINARY_DIR}/llvm-project") |
| set(LLVM_TOOLS_BINARY_DIR "${LLVM_BINARY_DIR}/bin") |
| set(LLVM_EXTERNAL_LIT "${IREE_SOURCE_DIR}/${_BUNDLED_LLVM_CMAKE_SOURCE_SUBDIR}/utils/lit/lit.py") |
| |
| set(IREE_LLVM_LINK_BINARY "$<TARGET_FILE:${IREE_LLVM_LINK_TARGET}>") |
| set(IREE_LLD_BINARY "$<TARGET_FILE:${IREE_LLD_TARGET}>") |
| set(IREE_CLANG_BINARY "$<TARGET_FILE:${IREE_CLANG_TARGET}>") |
| set(IREE_CLANG_BUILTIN_HEADERS_PATH "${LLVM_BINARY_DIR}/lib/clang/${LLVM_VERSION_MAJOR}/include/") |
| endmacro() |
| |
| macro(iree_llvm_configure_installed) |
| message(STATUS "Using installed LLVM components") |
| find_package(LLVM REQUIRED) |
| list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") |
| include_directories(${LLVM_INCLUDE_DIRS}) |
| |
| find_package(MLIR REQUIRED) |
| list(APPEND CMAKE_MODULE_PATH "${MLIR_CMAKE_DIR}") |
| include_directories(${MLIR_INCLUDE_DIRS}) |
| |
| find_package(LLD REQUIRED) |
| list(APPEND CMAKE_MODULE_PATH "${LLD_CMAKE_DIR}") |
| include_directories(${LLD_INCLUDE_DIRS}) |
| |
| find_package(Clang REQUIRED) |
| list(APPEND CMAKE_MODULE_PATH "${CLANG_CMAKE_DIR}") |
| include_directories(${CLANG_INCLUDE_DIRS}) |
| |
| # Lit never gets installed with LLVM. So we have to reach into our copy |
| # of the monorepo to get it. I'm sorry. If this doesn't work for you, |
| # feel free to -DLLVM_EXTERNAL_LIT to provide your own. |
| # Note that LLVM style lit test helpers use LLVM_EXTERNAL_LIT, if provided, |
| # so this is consistent between the projects. |
| if(NOT LLVM_EXTERNAL_LIT) |
| set(LLVM_EXTERNAL_LIT "${IREE_SOURCE_DIR}/third_party/llvm-project/llvm/utils/lit/lit.py") |
| endif() |
| |
| set(IREE_LLVM_LINK_BINARY "$<TARGET_FILE:llvm-link>") |
| set(IREE_LLD_BINARY "$<TARGET_FILE:lld>") |
| set(IREE_CLANG_BINARY "$<TARGET_FILE:clang>") |
| set(IREE_CLANG_BUILTIN_HEADERS_PATH "${LLVM_LIBRARY_DIR}/clang/${LLVM_VERSION_MAJOR}/include") |
| if(NOT EXISTS "${IREE_CLANG_BUILTIN_HEADERS_PATH}") |
| message(WARNING "Could not find installed clang-resource-headers (tried ${IREE_CLANG_BUILTIN_HEADERS_PATH})") |
| endif() |
| endmacro() |
| |
| # iree_llvm_set_bundled_cmake_options() |
| # Hard-code various LLVM CMake options needed for an in-tree bundled build. |
| macro(iree_llvm_set_bundled_cmake_options) |
| # When enabling an IREE CPU backend, automatically enable these targets. |
| set(IREE_DEFAULT_CPU_LLVM_TARGETS "X86;ARM;AArch64;RISCV" |
| CACHE STRING "Initialization value for default LLVM CPU targets.") |
| |
| # These defaults are moderately important to us, but the user *can* |
| # override them (enabling some of these brings in deps that will conflict, |
| # so ymmv). |
| set(LLVM_INCLUDE_EXAMPLES OFF CACHE BOOL "") |
| set(LLVM_INCLUDE_TESTS OFF CACHE BOOL "") |
| set(LLVM_INCLUDE_BENCHMARKS OFF CACHE BOOL "") |
| set(LLVM_APPEND_VC_REV OFF CACHE BOOL "") |
| set(LLVM_ENABLE_IDE ON CACHE BOOL "") |
| set(LLVM_ENABLE_BINDINGS OFF CACHE BOOL "") |
| |
| # Force LLVM to avoid dependencies, which we don't ever really want in our |
| # limited builds. |
| set(LLVM_ENABLE_LIBEDIT OFF CACHE BOOL "Default disable") |
| set(LLVM_ENABLE_LIBXML2 OFF CACHE BOOL "Default disable") |
| set(LLVM_ENABLE_TERMINFO OFF CACHE BOOL "Default disable") |
| set(LLVM_ENABLE_ZLIB OFF CACHE BOOL "Default disable") |
| set(LLVM_ENABLE_ZSTD OFF CACHE BOOL "Default disable") |
| set(LLVM_FORCE_ENABLE_STATS ON CACHE BOOL "Default enable") |
| |
| # LLVM defaults to building all targets. We always enable targets that we need |
| # as we need them, so default to none. The user can override this as needed, |
| # which is fine. |
| set(LLVM_TARGETS_TO_BUILD "" CACHE STRING "") |
| |
| # We enable LLVM projects as needed. The user can override this. |
| set(LLVM_ENABLE_PROJECTS "" CACHE STRING "") |
| set(LLVM_EXTERNAL_PROJECTS "" CACHE STRING "") |
| |
| # Default Python bindings to off (for all sub-projects). |
| set(MLIR_ENABLE_BINDINGS_PYTHON OFF CACHE BOOL "") |
| set(MHLO_ENABLE_BINDINGS_PYTHON OFF CACHE BOOL "") |
| |
| # If we are building clang/lld/etc, these will be the targets. |
| # Otherwise, empty so scripts can detect unavailability. |
| set(IREE_CLANG_TARGET) |
| set(IREE_LLD_TARGET) |
| |
| # Unconditionally enable some other cheap LLVM tooling. |
| set(IREE_LLVM_LINK_TARGET llvm-link) |
| set(IREE_FILECHECK_TARGET FileCheck) |
| set(IREE_NOT_TARGET not) |
| |
| # Unconditionally enable mlir. |
| list(APPEND LLVM_ENABLE_PROJECTS mlir) |
| |
| # Configure LLVM based on enabled IREE target backends. |
| message(STATUS "IREE compiler target backends:") |
| if(IREE_TARGET_BACKEND_CUDA) |
| message(STATUS " - cuda") |
| list(APPEND LLVM_TARGETS_TO_BUILD NVPTX) |
| set(IREE_CLANG_TARGET clang) |
| endif() |
| if(IREE_TARGET_BACKEND_LLVM_CPU) |
| message(STATUS " - llvm-cpu") |
| list(APPEND LLVM_TARGETS_TO_BUILD "${IREE_DEFAULT_CPU_LLVM_TARGETS}") |
| set(IREE_CLANG_TARGET clang) |
| set(IREE_LLD_TARGET lld) |
| endif() |
| if(IREE_TARGET_BACKEND_LLVM_CPU_WASM) |
| message(STATUS " - llvm-cpu (wasm)") |
| list(APPEND LLVM_TARGETS_TO_BUILD WebAssembly) |
| set(IREE_CLANG_TARGET clang) |
| set(IREE_LLD_TARGET lld) |
| endif() |
| if(IREE_TARGET_BACKEND_METAL_SPIRV) |
| message(STATUS " - metal-spirv") |
| endif() |
| if(IREE_TARGET_BACKEND_ROCM) |
| message(STATUS " - rocm") |
| list(APPEND LLVM_TARGETS_TO_BUILD AMDGPU) |
| set(IREE_CLANG_TARGET clang) |
| endif() |
| if(IREE_TARGET_BACKEND_VULKAN_SPIRV) |
| message(STATUS " - vulkan-spirv") |
| endif() |
| if(IREE_TARGET_BACKEND_VMVX) |
| message(STATUS " - vmvx") |
| endif() |
| if(IREE_TARGET_BACKEND_WEBGPU_SPIRV) |
| message(STATUS " - webgpu-spirv") |
| endif() |
| |
| if(IREE_CLANG_TARGET) |
| list(APPEND LLVM_ENABLE_PROJECTS clang) |
| endif() |
| if(IREE_LLD_TARGET) |
| list(APPEND LLVM_ENABLE_PROJECTS lld) |
| endif() |
| |
| list(REMOVE_DUPLICATES LLVM_ENABLE_PROJECTS) |
| list(REMOVE_DUPLICATES LLVM_TARGETS_TO_BUILD) |
| message(VERBOSE "Building LLVM Targets: ${LLVM_TARGETS_TO_BUILD}") |
| message(VERBOSE "Building LLVM Projects: ${LLVM_ENABLE_PROJECTS}") |
| endmacro() |
| |
| # iree_add_llvm_external_project(name location) |
| # Adds a project as if by appending to the LLVM_EXTERNAL_PROJECTS CMake |
| # variable. This is done by setting the same top-level variables that the LLVM |
| # machinery is expected to export and including the sub directory explicitly. |
| # The project binary dir will be llvm-external-projects/${name} |
| # Call this after appropriate LLVM/MLIR packages have been loaded. |
| function(iree_llvm_add_external_project name location) |
| message(STATUS "Adding LLVM external project ${name} -> ${location}") |
| if(NOT EXISTS "${location}/CMakeLists.txt") |
| message(FATAL_ERROR "External project location ${location} is not valid") |
| endif() |
| add_subdirectory(${location} "llvm-external-projects/${name}" EXCLUDE_FROM_ALL) |
| endfunction() |
| |
| # iree_llvm_add_usage_requirements(llvm_library usage_library) |
| # Adds |usage_library| as a link dependency of |llvm_library| in a way that |
| # is legal regardless of whether imported or built. |
| function(iree_llvm_add_usage_requirements llvm_library usage_library) |
| get_target_property(_imported ${llvm_library} IMPORTED) |
| if(_imported) |
| set_property(TARGET ${llvm_library} |
| APPEND PROPERTY IMPORTED_LINK_INTERFACE_LIBRARIES ${usage_library}) |
| else() |
| # We can't easily add an out-of-project link library directly, because |
| # then it needs to be installed/exported, etc. Big mess. So just splice |
| # the include directories from the usage_library onto the llvm_library. |
| get_property(_includes TARGET ${usage_library} PROPERTY INTERFACE_INCLUDE_DIRECTORIES) |
| set_property(TARGET ${llvm_library} APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES |
| $<BUILD_INTERFACE:${_includes}> |
| ) |
| endif() |
| endfunction() |