-
Notifications
You must be signed in to change notification settings - Fork 3
Add python bindings for lighthouse #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
build | ||
.cache |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
[submodule "third_party/llvm-project"] | ||
path = third_party/llvm-project | ||
url = https://github.com/llvm/llvm-project.git | ||
[submodule "third_party/torch-mlir"] | ||
path = third_party/torch-mlir | ||
url = https://github.com/llvm/torch-mlir.git |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
# 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 | ||
|
||
cmake_minimum_required(VERSION 3.21...3.24) | ||
|
||
# LLVM requires CMP0116 for tblgen: https://reviews.llvm.org/D101083 | ||
# CMP0116: Ninja generators transform `DEPFILE`s from `add_custom_command()` | ||
# New in CMake 3.20. https://cmake.org/cmake/help/latest/policy/CMP0116.html | ||
set(CMAKE_POLICY_DEFAULT_CMP0116 OLD) | ||
if(POLICY CMP0116) | ||
cmake_policy(SET CMP0116 OLD) | ||
endif() | ||
|
||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) | ||
|
||
project(LIGHTHOUSE C CXX) | ||
|
||
set(CMAKE_C_STANDARD 11) | ||
set(CMAKE_CXX_STANDARD 17) | ||
|
||
#------------------------------------------------------------------------------- | ||
# Input Dialects | ||
#------------------------------------------------------------------------------- | ||
|
||
option(LIGHTHOUSE_INPUT_TORCH "Builds support for compiling Torch MLIR programs" ON) | ||
|
||
#------------------------------------------------------------------------------- | ||
# Python | ||
# If building features that require Python development, find them early in | ||
# one invocation (some CMake versions are sensitive to resolving out of order). | ||
#------------------------------------------------------------------------------- | ||
option(LIGHTHOUSE_BUILD_PYTHON_BINDINGS "Builds the Lighthouse python bindings" ON) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we have one "test" file to document what we expect to be build? E.g. just a Python file containing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, i need to add a test before i land this, i will do that. |
||
|
||
if (LIGHTHOUSE_BUILD_PYTHON_BINDINGS) | ||
# After CMake 3.18, we are able to limit the scope of the search to just | ||
# Development.Module. Searching for Development will fail in situations where | ||
# the Python libraries are not available. When possible, limit to just | ||
# Development.Module. | ||
# See https://pybind11.readthedocs.io/en/stable/compiling.html#findpython-mode | ||
# | ||
# Configuring the Development.Module is flaky in multi-project setups. | ||
# "Bootstrapping" by first looking for the optional Development component | ||
# seems to be robust generally. | ||
# See: https://reviews.llvm.org/D118148 | ||
# If building Python packages, we have a hard requirement on 3.9+. | ||
find_package(Python3 3.9 COMPONENTS Interpreter Development) | ||
find_package(Python3 3.9 COMPONENTS Interpreter Development.Module REQUIRED) | ||
# Some parts of the build use FindPython instead of FindPython3. Why? No | ||
# one knows, but they are different. So make sure to bootstrap this one too. | ||
# Not doing this here risks them diverging, which on multi-Python systems, | ||
# can be troublesome. Note that nanobind requires FindPython. | ||
set(Python_EXECUTABLE "${Python3_EXECUTABLE}") | ||
find_package(Python 3.9 COMPONENTS Interpreter Development.Module REQUIRED) | ||
endif() | ||
|
||
if(NOT "${Python_EXECUTABLE}" STREQUAL "${Python3_EXECUTABLE}") | ||
message(WARNING "FindPython and FindPython3 found different executables. You may need to pin -DPython_EXECUTABLE and -DPython3_EXECUTABLE (${Python_EXECUTABLE} vs ${Python3_EXECUTABLE})") | ||
endif() | ||
|
||
#------------------------------------------------------------------------------- | ||
# MLIR/LLVM Dependency | ||
#------------------------------------------------------------------------------- | ||
|
||
# Both the Lighthouse and MLIR Python bindings require nanobind. We initialize | ||
# it here at the top level so that everything uses ours consistently. | ||
if(LIGHTHOUSE_BUILD_PYTHON_BINDINGS) | ||
# TODO: Configure a flag to use system deps directly. | ||
include(FetchContent) | ||
FetchContent_Declare( | ||
nanobind | ||
GIT_REPOSITORY https://github.com/wjakob/nanobind.git | ||
GIT_TAG 0f9ce749b257fdfe701edb3cf6f7027ba029434a # v2.4.0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's movement upstream on nanobind versions. I think llvm/llvm-project#161230 is most pertinent. Before landing, let's make sure we are aligned with what upstream is doing/about to do. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We land and then integerate the commit and change. This is the correct way of doing it until the pr lands. Once it lands, we can integerate it. |
||
) | ||
FetchContent_MakeAvailable(nanobind) | ||
endif() | ||
|
||
# Get the main LLVM deps. | ||
# TODO: Add a flag to use installed llvm instead. | ||
# TODO: There are a lot of default flags that are missing here. The build | ||
# system was only configured enough to build mlir python bindings. | ||
|
||
# Enable MLIR Python bindings if requested. | ||
set(MLIR_ENABLE_BINDINGS_PYTHON OFF CACHE BOOL "") | ||
if (LIGHTHOUSE_BUILD_PYTHON_BINDINGS) | ||
set(MLIR_ENABLE_BINDINGS_PYTHON ON) | ||
endif() | ||
# Disable MLIR attempting to configure Python dev packages. We take care of | ||
# that in Lighthouse as a super-project. | ||
set(MLIR_DISABLE_CONFIGURE_PYTHON_DEV_PACKAGES ON CACHE BOOL "" FORCE) | ||
|
||
# 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 "") | ||
|
||
# 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") | ||
|
||
# Unconditionally enable mlir. | ||
set(LLVM_ENABLE_PROJECTS "" CACHE STRING "") | ||
list(APPEND LLVM_ENABLE_PROJECTS "mlir") | ||
|
||
# Setup LLVM lib and bin directories. | ||
set(LLVM_LIBRARY_OUTPUT_INTDIR "${CMAKE_BINARY_DIR}/llvm-project/lib") | ||
set(LLVM_RUNTIME_OUTPUT_INTDIR "${CMAKE_BINARY_DIR}/llvm-project/bin") | ||
|
||
set(_BUNDLED_LLVM_CMAKE_SOURCE_SUBDIR "third_party/llvm-project/llvm") | ||
add_subdirectory("${_BUNDLED_LLVM_CMAKE_SOURCE_SUBDIR}" "llvm-project" EXCLUDE_FROM_ALL) | ||
|
||
# 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 "${CMAKE_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") | ||
list(APPEND CMAKE_MODULE_PATH "${MLIR_CMAKE_DIR}") | ||
|
||
message(STATUS "LLVM_CMAKE_DIR: ${LLVM_CMAKE_DIR}") | ||
message(STATUS "MLIR_CMAKE_DIR: ${MLIR_CMAKE_DIR}") | ||
|
||
set(LLVM_INCLUDE_DIRS | ||
${CMAKE_SOURCE_DIR}/${_BUNDLED_LLVM_CMAKE_SOURCE_SUBDIR}/include | ||
${CMAKE_BINARY_DIR}/llvm-project/include | ||
) | ||
set(MLIR_INCLUDE_DIRS | ||
${CMAKE_SOURCE_DIR}/third_party/llvm-project/mlir/include | ||
${CMAKE_BINARY_DIR}/llvm-project/tools/mlir/include | ||
) | ||
|
||
include_directories(${LLVM_INCLUDE_DIRS}) | ||
include_directories(${MLIR_INCLUDE_DIRS}) | ||
|
||
#------------------------------------------------------------------------------- | ||
# Torch-MLIR Dependency | ||
#------------------------------------------------------------------------------- | ||
|
||
if (LIGHTHOUSE_INPUT_TORCH) | ||
set(TORCH_MLIR_ROOT_DIR "${CMAKE_SOURCE_DIR}/third_party/torch-mlir" CACHE PATH "") | ||
endif() | ||
|
||
#------------------------------------------------------------------------------- | ||
# Top-level libraries | ||
#------------------------------------------------------------------------------- | ||
|
||
include_directories(${CMAKE_SOURCE_DIR}/include) | ||
include_directories(${CMAKE_BINARY_DIR}/include) | ||
|
||
add_subdirectory(lib) | ||
add_subdirectory(python) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
#ifndef LIGHTHOUSE_INIT_C_H | ||
#define LIGHTHOUSE_INIT_C_H | ||
|
||
#include "mlir-c/IR.h" | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
/// Initializes poseidon. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's poseidon? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oops haha |
||
MLIR_CAPI_EXPORTED void lighthouseRegisterDialects(MlirDialectRegistry registry); | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
|
||
#endif // LIGHTHOUSE_INIT_C_H |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#include "lighthouse-c/Init.h" | ||
#include "mlir-c/Dialect/Func.h" | ||
|
||
MLIR_CAPI_EXPORTED void lighthouseRegisterDialects(MlirDialectRegistry registry) { | ||
// TODO: Probably have a function call to the C++ lib to register things | ||
// here. This is just a placeholder for now. | ||
MlirDialectHandle funcDialect = mlirGetDialectHandle__func__(); | ||
mlirDialectHandleInsertDialect(funcDialect, registry); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# Based on IREE's CAPI CMakeLists.txt : | ||
# https://github.com/iree-org/iree/blob/39c572deb0d388eb86d78295896a6e38835ccc8c/compiler/src/iree/compiler/API/CMakeLists.txt | ||
set(C_LIBS | ||
MLIRCAPIIR | ||
MLIRCAPIDebug | ||
MLIRCAPIFunc | ||
MLIRCAPIInterfaces | ||
MLIRCAPITransforms | ||
) | ||
|
||
foreach (lib ${C_LIBS}) | ||
list(APPEND _OBJECTS $<TARGET_OBJECTS:obj.${lib}>) | ||
# GENEX_EVAL is not recursive: it evaluates one level of generator | ||
# expressions. There is a way to hold it just right so that GENEX_EVAL is | ||
# used at the call site, but it is really tricky and people can't be expected | ||
# to get it right. In fact, at the time of this writing, some misc usage | ||
# in LLVM causes a second level of generator expressions in some base | ||
# libraries. For good measure, we do GENEX_EVAL four times. If you get errors | ||
# that show like generator expressions are showing up in link lines, this is | ||
# the culprit. Look at the export_objects_debug.txt to confirm. Then, add | ||
# another level of fix upstream if you like pain. | ||
list(APPEND _DEPS "$<GENEX_EVAL:$<GENEX_EVAL:$<GENEX_EVAL:$<GENEX_EVAL:$<TARGET_PROPERTY:${lib},LINK_LIBRARIES>>>>>") | ||
Groverkss marked this conversation as resolved.
Show resolved
Hide resolved
|
||
endforeach () | ||
|
||
set(CMAKE_CXX_VISIBILITY_PRESET "hidden") | ||
set(CMAKE_VISIBILITY_INLINES_HIDDEN "ON") | ||
|
||
add_library(Lighthouse-C SHARED | ||
CAPI.cpp | ||
) | ||
|
||
target_sources(Lighthouse-C PRIVATE | ||
${_OBJECTS} | ||
) | ||
|
||
target_link_libraries(Lighthouse-C PRIVATE | ||
${_DEPS} | ||
) | ||
|
||
target_link_options(Lighthouse-C PRIVATE "-Wl,-exclude-libs,ALL") |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
add_subdirectory(CAPI) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
# 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 | ||
|
||
################################################################################ | ||
# This directly uses the LLVM build system in order to create bundled API | ||
# binaries that are consistent with LLVM. Consult upstream CMake macros if you | ||
# don't understand what this does. | ||
################################################################################ | ||
|
||
include(AddMLIRPython) | ||
|
||
# Specifies that all MLIR packages are co-located under lighthouse. | ||
# TODO: Currently, we are building this under lighthouse. , but we should be | ||
# ideally building this under lighthouse.compiler. , when we have a proper | ||
# seperation between the compiler and the runtime. The runtime bindings have no | ||
# reason to ship with the mlir python bindings. | ||
# TODO: Add an upstream cmake param for this vs having a global here. | ||
add_compile_definitions("MLIR_PYTHON_PACKAGE_PREFIX=lighthouse.") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we please just use the That every project is renaming the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why would we use the mlir prefix here? MLIR is a toolkit, not a compiler. We are trying to build a compiler. At max, I would say lighthouse.mlir is a better prefix than this. We can't just go and take over mlir's namespace. I disagree with mlir.lighthouse.
I think there is good reason to rename it. Let's say you have two projects on different versions of mlir both trying to work on the same namespace. How are you going to gurantee that they work together? That just sounds like a disaster. This is not an imaginary scenario. Let's say you decide to ship 2 pytorch dynamo implementations, lighthouse-1 and lighthouse-2. They don't depend on each other at all, but you ship them under the namespace mlir.lighthouse1 and mlir.lighthouse2. Now, if your mlir things don't match up, it completly breaks. There is no dependency between these packages, but you still break.
I don't know what you are talking about here. Clearly in this pr the only bindings built are for func dialect and mlir core. I don't know what the "full upstream bindings" is. We need all of this. |
||
|
||
set(_PYTHON_BUILD_PREFIX "${CMAKE_BINARY_DIR}/python") | ||
set(_PYTHON_INSTALL_PREFIX "python_packages/lighthouse") | ||
|
||
set(CMAKE_PLATFORM_NO_VERSIONED_SONAME 1) | ||
|
||
declare_mlir_python_sources(LighthousePythonSources) | ||
|
||
# The Python bindings are monolithic and we don't have a good way for the | ||
# torch plugin to contribute Python sources, so we just gate it here | ||
# versus having more complicated indirection. May want to rethink this | ||
# if others need it. | ||
if(LIGHTHOUSE_INPUT_TORCH) | ||
declare_mlir_python_sources(LighthousePythonSources.Torch.Importers | ||
ADD_TO_PARENT LighthousePythonSources | ||
ROOT_DIR "${TORCH_MLIR_ROOT_DIR}/python/torch_mlir" | ||
SOURCES | ||
extras/fx_importer.py | ||
extras/onnx_importer.py | ||
Comment on lines
+37
to
+38
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where are these files? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That also brings to mind if this these build files have been tested in any sort of way. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is how the fx_importer works and is meant to work. torch-mlir exposes these bindings and they only depend on mlir core (which you bring from somewhere) and func dialect. When building your own aot.compile, you get a torch.export.ExportedProgram and send it down fx_importer.J Similar thing for onnx. The fx_importer sources assume that the mlir ir core stuff is in ..ir : https://github.com/llvm/torch-mlir/blob/main/python/torch_mlir/extras/fx_importer.py#L95
I need to add tests for these things, but i'm currently only working on this on weekends and whatever time i have. We don't have anything concrete setup, so i'm mainly trying to get things in and then build a aot.compile flow on top, and then work on testing. I can add tests for checking if things are correctly improted though. |
||
) | ||
endif() | ||
|
||
set(_SOURCE_COMPONENTS | ||
# Local sources. | ||
LighthousePythonSources | ||
|
||
MLIRPythonSources.Core | ||
|
||
# TODO: We currently include func, because that's what the torch importer | ||
# needs. We can include more as we need. | ||
# MLIR Dialects. | ||
MLIRPythonSources.Dialects.func | ||
) | ||
|
||
add_mlir_python_modules(LighthousePythonModules | ||
ROOT_PREFIX "${_PYTHON_BUILD_PREFIX}/lighthouse" | ||
INSTALL_PREFIX "${_PYTHON_INSTALL_PREFIX}/lighthouse" | ||
DECLARED_SOURCES ${_SOURCE_COMPONENTS} | ||
COMMON_CAPI_LINK_LIBS | ||
Lighthouse-C | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than using submodules, can we instead use files with specified commits?
TPP-MLIR has the following: https://github.com/libxsmm/tpp-mlir/blob/main/build_tools/llvm_version.txt
We have found this pattern to lead to more flexibility. Also with an eye to that we expect people to extend lighthouse in various ways, bringing in their own weird dependencies and how they choose to manage them.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why? That's just .gitmodules with extra steps.
You do an out of build tree to extend it or fork it. I don't see what you mean by bringing own weird dependencies. If you fork, you can add whatever submodules you want. the build system can support BYOLLVM, i just didn't set it up because i want something basic to start.