Skip to content

Commit

Permalink
Add helper for cross-compiling Halide generators. (#6366)
Browse files Browse the repository at this point in the history
* Add helper for cross-compiling Halide generators.

Created a new function, `add_halide_generator`, that helps users write correct cross-compiling builds by establishing the following convention for creating a generator named `TARGET`:

1. Define Halide generators and libraries in the same project
2. Assume two builds: a host build and a cross build.
3. When creating a generator, check to see if we can load a pre-built version of the target.
4. If so, just use it.
5. If not, make sure the full Halide package is loaded and create a target for the generator.
     a. If `CMAKE_CROSSCOMPILING` is set, then _warn_ the user (the variable is unreliable on macOS) that something seems fishy.
     b. Create export rules for the generator. It creates a package `PACKAGE_NAME` and appends to its `EXPORT_FILE`.
     c. Create a custom target also named `PACKAGE_NAME` for building the generators.
     d. Create an alias `${PACKAGE_NAMESPACE}${TARGET}`.
6. Users are expected to use the alias in conjunction `add_halide_library`. Users can test the existence of `TARGET` to determine whether a pre-built one was loaded (and set additional properties if not).
7. Setting `${PACKAGE_NAME}_ROOT` is enough to load pre-built generators.

`PACKAGE_NAME` is `${PROJECT_NAME}-halide_generators` by default.
`PACKAGE_NAMESPACE` is `${PROJECT_NAME}::halide_generators::` by default.
`EXPORT_FILE` is `${PROJECT_BINARY_DIR}/cmake/${PACKAGE_NAME}-config.cmake` by default.

Users are free to avoid the helper if it would not fit their workflow.

* Make HANNK use the new add_halide_generator helper
  • Loading branch information
alexreinking committed Nov 1, 2021
1 parent f5ce5f3 commit 4225eba
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 135 deletions.
127 changes: 36 additions & 91 deletions apps/hannk/halide/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,45 +1,3 @@
add_custom_target(hannk-halide_generators)

# This function adds the target ${TARGET} to the hannk-halide_generators
# CMake package that exists in the build-tree of a host build. It also adds
# it to the target of the same name that can be used as a convenience for
# just building the host targets.
function(_export_host_target TARGET)
add_dependencies(hannk-halide_generators ${TARGET})
export(TARGETS ${TARGET}
NAMESPACE hannk::halide_generators::
APPEND FILE "${hannk_BINARY_DIR}/hannk-halide_generators-config.cmake")
endfunction()

# Emscripten tries to disable finding packages outside its sysroot,
# but we need our native generators. Setting CMAKE_FIND_ROOT_PATH_BOTH
# here overrides Emscripten's search preference.
find_package(hannk-halide_generators QUIET CMAKE_FIND_ROOT_PATH_BOTH)

if (hannk-halide_generators_FOUND)
message(STATUS "Using hannk-halide_generators from ${hannk-halide_generators_DIR}")
else ()
if (CMAKE_CROSSCOMPILING)
message(WARNING
"hannk-halide_generators were not found and it looks like you are cross-compiling. "
"This is likely to fail. Please set -Dhannk-halide_generators_ROOT=... at the CMake "
"command line to the build directory of a host-built hannk.")
endif ()
find_package(Halide REQUIRED)
endif ()

if (NOT TARGET hannk::halide_generators::common_halide)
add_library(common_halide STATIC common_halide.cpp)
add_library(hannk::halide_generators::common_halide ALIAS common_halide)

target_link_libraries(common_halide PRIVATE Halide::Halide)
target_include_directories(common_halide PUBLIC $<BUILD_INTERFACE:${hannk_SOURCE_DIR}>)

_export_host_target(common_halide)
endif ()

# ----------------------------

function(_begin_halide_library_set LIBRARY_SET)
add_library(${LIBRARY_SET} INTERFACE)
target_include_directories(${LIBRARY_SET} INTERFACE "$<BUILD_INTERFACE:${hannk_BINARY_DIR}>")
Expand All @@ -50,22 +8,16 @@ endfunction()
function(_add_halide_library_set LIBRARY_SET)
set(options)
set(oneValueArgs TARGET GENERATOR_NAME)
set(multiValueArgs SRCS GENERATOR_ARGS GENERATOR_DEPS FEATURES)
set(multiValueArgs SRCS GENERATOR_ARGS FEATURES)
cmake_parse_arguments(args "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

set(gen hannk::halide_generators::${args_TARGET}.generator)

if (NOT TARGET ${gen})
add_executable(${args_TARGET}.generator ${args_SRCS})
add_executable(${gen} ALIAS ${args_TARGET}.generator)

target_link_libraries(${args_TARGET}.generator PRIVATE ${args_GENERATOR_DEPS} common_halide Halide::Generator)
target_include_directories(${args_TARGET}.generator PUBLIC $<BUILD_INTERFACE:${hannk_SOURCE_DIR}>)

_export_host_target(${args_TARGET}.generator)
add_halide_generator(${args_TARGET}.generator ${args_SRCS})
if (TARGET ${args_TARGET}.generator)
target_link_libraries(${args_TARGET}.generator PRIVATE common_halide)
target_include_directories(${args_TARGET}.generator PRIVATE $<BUILD_INTERFACE:${hannk_SOURCE_DIR}>)
endif ()

add_halide_library(${args_TARGET} FROM ${gen}
add_halide_library(${args_TARGET} FROM hannk::halide_generators::${args_TARGET}.generator
NAMESPACE hannk
GENERATOR ${args_GENERATOR_NAME}
FEATURES c_plus_plus_name_mangling ${args_FEATURES}
Expand All @@ -76,7 +28,18 @@ function(_add_halide_library_set LIBRARY_SET)
endfunction()

function(_finish_halide_library_set LIBRARY_SET)
# Nothing to do for now.
# Create common sources target if it wasn't imported by add_halide_generator above.
if (NOT TARGET hannk::halide_generators::common_halide)
add_library(common_halide STATIC common_halide.cpp)
add_library(hannk::halide_generators::common_halide ALIAS common_halide)

target_link_libraries(common_halide PRIVATE Halide::Halide)
target_include_directories(common_halide PUBLIC $<BUILD_INTERFACE:${hannk_SOURCE_DIR}>)

export(TARGETS common_halide
NAMESPACE hannk::halide_generators::
APPEND FILE "${hannk_BINARY_DIR}/cmake/hannk-halide_generators-config.cmake")
endif ()
endfunction()

# ---------------------------
Expand All @@ -88,134 +51,116 @@ _add_halide_library_set(halide_op_implementations
SRCS elementwise_generator.cpp
FEATURES no_bounds_query
GENERATOR_NAME Add
GENERATOR_ARGS
GENERATOR_DEPS)
GENERATOR_ARGS)

_add_halide_library_set(halide_op_implementations
TARGET average_pool_uint8
SRCS pool_generator.cpp
GENERATOR_NAME AveragePool
GENERATOR_ARGS
GENERATOR_DEPS)
GENERATOR_ARGS)

_add_halide_library_set(halide_op_implementations
TARGET conv_u8_u8_u8
SRCS conv_generator.cpp
GENERATOR_NAME Conv
GENERATOR_ARGS output.type=uint8
GENERATOR_DEPS)
GENERATOR_ARGS output.type=uint8)

_add_halide_library_set(halide_op_implementations
TARGET conv_u8_u8_i16
SRCS conv_generator.cpp
GENERATOR_NAME Conv
GENERATOR_ARGS output.type=int16
GENERATOR_DEPS)
GENERATOR_ARGS output.type=int16)

_add_halide_library_set(halide_op_implementations
TARGET copy_uint8_uint8
SRCS copy_generator.cpp
FEATURES no_bounds_query
GENERATOR_NAME Copy
GENERATOR_ARGS input.type=uint8 output.type=uint8
GENERATOR_DEPS)
GENERATOR_ARGS input.type=uint8 output.type=uint8)

_add_halide_library_set(halide_op_implementations
TARGET depthwise_conv_uint8
SRCS depthwise_conv_generator.cpp
GENERATOR_NAME DepthwiseConv
GENERATOR_ARGS inv_depth_multiplier=1
GENERATOR_DEPS)
GENERATOR_ARGS inv_depth_multiplier=1)

_add_halide_library_set(halide_op_implementations
TARGET depthwise_conv_broadcast_uint8
SRCS depthwise_conv_generator.cpp
GENERATOR_NAME DepthwiseConv
GENERATOR_ARGS inv_depth_multiplier=0
GENERATOR_DEPS)
GENERATOR_ARGS inv_depth_multiplier=0)

_add_halide_library_set(halide_op_implementations
TARGET depthwise_conv_shallow_uint8
SRCS depthwise_conv_generator.cpp
GENERATOR_NAME DepthwiseConv
GENERATOR_ARGS inv_depth_multiplier=1 shallow=true
GENERATOR_DEPS)
GENERATOR_ARGS inv_depth_multiplier=1 shallow=true)

_add_halide_library_set(halide_op_implementations
TARGET fill_uint8
SRCS fill_generator.cpp
FEATURES no_bounds_query no_asserts
GENERATOR_NAME Fill
GENERATOR_ARGS
GENERATOR_DEPS)
GENERATOR_ARGS)

_add_halide_library_set(halide_op_implementations
TARGET elementwise_5xuint8_1xuint8
SRCS elementwise_generator.cpp
FEATURES no_bounds_query
GENERATOR_NAME Elementwise
GENERATOR_ARGS inputs.size=5 inputs.type=uint8 output1_type=uint8
GENERATOR_DEPS)
GENERATOR_ARGS inputs.size=5 inputs.type=uint8 output1_type=uint8)

_add_halide_library_set(halide_op_implementations
TARGET elementwise_5xint16_1xuint8int16
SRCS elementwise_generator.cpp
FEATURES no_bounds_query
GENERATOR_NAME Elementwise
GENERATOR_ARGS inputs.size=5 inputs.type=int16 output1_type=uint8 output2_type=int16
GENERATOR_DEPS)
GENERATOR_ARGS inputs.size=5 inputs.type=int16 output1_type=uint8 output2_type=int16)

_add_halide_library_set(halide_op_implementations
TARGET l2_normalization_uint8
SRCS normalizations_generator.cpp
FEATURES no_bounds_query
GENERATOR_NAME L2Normalization
GENERATOR_ARGS
GENERATOR_DEPS)
GENERATOR_ARGS)

_add_halide_library_set(halide_op_implementations
TARGET max_pool_uint8
SRCS pool_generator.cpp
GENERATOR_NAME MaxPool
GENERATOR_ARGS
GENERATOR_DEPS)
GENERATOR_ARGS)

_add_halide_library_set(halide_op_implementations
TARGET mean_uint8
SRCS reductions_generator.cpp
GENERATOR_NAME Mean
GENERATOR_ARGS
GENERATOR_DEPS)
GENERATOR_ARGS)

_add_halide_library_set(halide_op_implementations
TARGET mul_uint8_uint8_uint8
SRCS elementwise_generator.cpp
FEATURES no_bounds_query
GENERATOR_NAME Mul
GENERATOR_ARGS
GENERATOR_DEPS)
GENERATOR_ARGS)

_add_halide_library_set(halide_op_implementations
TARGET softmax_uint8
SRCS normalizations_generator.cpp
FEATURES no_bounds_query
GENERATOR_NAME Softmax
GENERATOR_ARGS
GENERATOR_DEPS)
GENERATOR_ARGS)

_add_halide_library_set(halide_op_implementations
TARGET tile_conv_filter_uint8
SRCS conv_generator.cpp
GENERATOR_NAME TileConvFilter
GENERATOR_ARGS
GENERATOR_DEPS)
GENERATOR_ARGS)

_add_halide_library_set(halide_op_implementations
TARGET upsample_channels_uint8
SRCS depthwise_conv_generator.cpp
GENERATOR_NAME UpsampleChannels
GENERATOR_ARGS
GENERATOR_DEPS)
GENERATOR_ARGS)

_finish_halide_library_set(halide_op_implementations)

84 changes: 84 additions & 0 deletions cmake/HalideGeneratorHelpers.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,90 @@ define_property(TARGET PROPERTY Halide_GENERATOR_HAS_POST_BUILD
BRIEF_DOCS "On a Halide generator target, true if Halide.dll copy command has already been added."
FULL_DOCS "On a Halide generator target, true if Halide.dll copy command has already been added.")

##
# Function to simplify writing the CMake rules for creating a generator executable
# that follows our recommended cross-compiling workflow.
##

function(add_halide_generator TARGET)
set(options "")
set(oneValueArgs PACKAGE_NAME PACKAGE_NAMESPACE EXPORT_FILE)
set(multiValueArgs SOURCES)
cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

if (NOT ARG_PACKAGE_NAME)
set(ARG_PACKAGE_NAME "${PROJECT_NAME}-halide_generators")
endif ()

if (NOT ARG_PACKAGE_NAMESPACE)
set(ARG_PACKAGE_NAMESPACE "${PROJECT_NAME}::halide_generators::")
endif ()

if (NOT ARG_EXPORT_FILE)
file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/cmake")
set(ARG_EXPORT_FILE "${PROJECT_BINARY_DIR}/cmake/${ARG_PACKAGE_NAME}-config.cmake")
endif ()

if (NOT ARG_SOURCES)
set(ARG_SOURCES "${ARG_UNPARSED_ARGUMENTS}")
endif ()

_Halide_try_load_generators()

# Communicate found information to the caller
set(${ARG_PACKAGE_NAME}_FOUND "${${ARG_PACKAGE_NAME}_FOUND}" PARENT_SCOPE)

set(gen "${ARG_PACKAGE_NAMESPACE}${TARGET}")
if (NOT TARGET "${gen}")
if (NOT TARGET "${ARG_PACKAGE_NAME}")
add_custom_target("${ARG_PACKAGE_NAME}")
endif ()

if (NOT Halide_FOUND)
find_package(Halide REQUIRED)
endif ()

add_executable(${TARGET} ${ARG_SOURCES})
add_executable(${gen} ALIAS ${TARGET})
target_link_libraries(${TARGET} PRIVATE Halide::Generator)

add_dependencies("${ARG_PACKAGE_NAME}" ${TARGET})
export(TARGETS ${TARGET}
NAMESPACE ${ARG_PACKAGE_NAMESPACE}
APPEND FILE "${ARG_EXPORT_FILE}")
endif ()
endfunction()

# NOTE: this function must only be called by add_halide_generator
# since it reads from its scope.
function(_Halide_try_load_generators)
# Don't repeatedly run the search for the tools package.
if (NOT DEFINED ${ARG_PACKAGE_NAME}_FOUND)
# Some toolchains, like Emscripten, try to disable finding packages
# outside their sysroots, but we always want to find the native
# generators. Setting CMAKE_FIND_ROOT_PATH_BOTH here overrides
# the toolchain search preference. This is okay since a user can
# always override this call by setting ${ARG_PACKAGE_NAME}_ROOT.
find_package(${ARG_PACKAGE_NAME} QUIET
CMAKE_FIND_ROOT_PATH_BOTH)

# Communicate found information to the caller
set(${ARG_PACKAGE_NAME}_FOUND "${${ARG_PACKAGE_NAME}_FOUND}" PARENT_SCOPE)

if (NOT ${ARG_PACKAGE_NAME}_FOUND AND CMAKE_CROSSCOMPILING)
message(WARNING
"${ARG_PACKAGE_NAME} were not found and it looks like you are cross-compiling. "
"This is likely to fail. Please set -D${ARG_PACKAGE_NAME}_ROOT=... at the CMake "
"command line to the build directory of a host-built ${PROJECT_NAME}.")
endif ()
endif ()
endfunction()

##
# Function to simplify writing the CMake rules for invoking a generator executable
# and getting a usable CMake library out of it.
##

function(add_halide_library TARGET)
##
# Set up argument parsing for extra outputs.
Expand Down
2 changes: 1 addition & 1 deletion test/integration/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ if (CMAKE_HOST_SYSTEM_NAME MATCHES "Linux")
--build-options
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_LIST_DIR}/../../cmake/toolchain.linux-aarch64.cmake
-DCMAKE_BUILD_TYPE=Release
"-Dxc-generators_ROOT=${CMAKE_CURRENT_BINARY_DIR}/xc-host"
"-Dxc-halide_generators_ROOT=${CMAKE_CURRENT_BINARY_DIR}/xc-host"
--test-command ${CMAKE_CTEST_COMMAND} --output-on-failure)

set_tests_properties(cross_compile_host PROPERTIES FIXTURES_SETUP xc-host)
Expand Down
17 changes: 11 additions & 6 deletions test/integration/xc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ project(xc)

enable_testing()

if (CMAKE_CROSSCOMPILING)
find_package(xc-generators REQUIRED)
else ()
add_subdirectory(generators)
endif ()
# Only need the platform-independent / source-only helpers.
find_package(HalideHelpers REQUIRED)

add_subdirectory(add)
add_halide_generator(add_gen add.cpp)
add_halide_library(add FROM xc::halide_generators::add_gen
REGISTRATION add_reg_cpp)

add_executable(run_add ${add_reg_cpp})
target_link_libraries(run_add PRIVATE add Halide::RunGenMain)

add_test(NAME run_add
COMMAND run_add --output_extents=[10,10] --benchmarks=all)
File renamed without changes.
13 changes: 0 additions & 13 deletions test/integration/xc/add/CMakeLists.txt

This file was deleted.

Loading

0 comments on commit 4225eba

Please sign in to comment.