352 lines
13 KiB
CMake
352 lines
13 KiB
CMake
# Licensed to the Apache Software Foundation (ASF) under one
|
|
# or more contributor license agreements. See the NOTICE file
|
|
# distributed with this work for additional information
|
|
# regarding copyright ownership. The ASF licenses this file
|
|
# to you under the Apache License, Version 2.0 (the
|
|
# "License"); you may not use this file except in compliance
|
|
# with the License. You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing,
|
|
# software distributed under the License is distributed on an
|
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
# KIND, either express or implied. See the License for the
|
|
# specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
include(ExternalProject)
|
|
include(cmake/modules/HexagonSDK.cmake)
|
|
|
|
set(FOUND_HEXAGON_TOOLCHAIN FALSE)
|
|
|
|
function(find_hexagon_toolchain)
|
|
if(FOUND_HEXAGON_TOOLCHAIN)
|
|
return()
|
|
endif()
|
|
if(NOT "${USE_HEXAGON_TOOLCHAIN}" STREQUAL "")
|
|
set(TRY_PATH "${USE_HEXAGON_TOOLCHAIN}")
|
|
else()
|
|
set(TRY_PATH "${USE_HEXAGON_SDK}")
|
|
endif()
|
|
message(STATUS "Looking for Hexagon toolchain in ${TRY_PATH}")
|
|
file(GLOB_RECURSE HEXAGON_CLANG "${TRY_PATH}/*/hexagon-clang++")
|
|
if(HEXAGON_CLANG)
|
|
# The path is ${HEXAGON_TOOLCHAIN}/bin/hexagon-clang++.
|
|
get_filename_component(HEXAGON_TMP0 "${HEXAGON_CLANG}" DIRECTORY)
|
|
get_filename_component(HEXAGON_TMP1 "${HEXAGON_TMP0}" DIRECTORY)
|
|
set(HEXAGON_TOOLCHAIN "${HEXAGON_TMP1}" CACHE PATH
|
|
"Path to the Hexagon toolchain")
|
|
set(FOUND_HEXAGON_TOOLCHAIN TRUE)
|
|
else()
|
|
message(SEND_ERROR "Cannot find Hexagon toolchain in ${TRY_PATH}")
|
|
endif()
|
|
endfunction()
|
|
|
|
macro(file_glob_append _output_list)
|
|
tvm_file_glob(GLOB _tmp0 ${ARGN})
|
|
set(_tmp1 ${${_output_list}})
|
|
list(APPEND _tmp1 ${_tmp0})
|
|
set(${_output_list} ${_tmp1})
|
|
endmacro()
|
|
|
|
set(TVMRT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/backend/hexagon/runtime")
|
|
set(TVM_CORE_RUNTIME_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/runtime")
|
|
|
|
if(DEFINED USE_HEXAGON_DEVICE)
|
|
message(WARNING "USE_HEXAGON_DEVICE is deprecated, use USE_HEXAGON instead")
|
|
endif()
|
|
|
|
# This .cmake file is included when building any part of TVM for any
|
|
# architecture. It shouldn't require any Hexagon-specific parameters (like
|
|
# the path to the SDK), unless it's needed. The flag USE_HEXAGON decides
|
|
# whether any Hexagon-related functionality is enabled. Specifically,
|
|
# setting USE_HEXAGON=OFF, disables any form of Hexagon support.
|
|
#
|
|
# Note on the function of USE_HEXAGON_RPC:
|
|
# - When building for Hexagon, this will build the Hexagon endpoint of the
|
|
# RPC server: the FastRPC skel library (with TVM runtime built into it),
|
|
# and the standalone RPC server for simulator.
|
|
# - When building for Android, this will build the (intermediary) RPC server,
|
|
# including the "stub" code for the FastRPC implementation of the RPC
|
|
# channel.
|
|
# - When building for x86, this will build the host-side code that instan-
|
|
# tiates the simulator.
|
|
|
|
if(NOT BUILD_FOR_HEXAGON AND NOT BUILD_FOR_ANDROID)
|
|
set(BUILD_FOR_HOST TRUE)
|
|
endif()
|
|
|
|
|
|
if(NOT USE_HEXAGON)
|
|
# USE_HEXAGON=OFF: codegen still works through the per-backend fallback
|
|
# module (src/backend/hexagon/codegen/hexagon_fallback_module.cc), which is always
|
|
# compiled into libtvm via CODEGEN_SRCS. No opt-stub registration is
|
|
# needed.
|
|
return()
|
|
endif()
|
|
|
|
# From here on, USE_HEXAGON is assumed to be TRUE.
|
|
|
|
if(BUILD_FOR_HOST AND USE_HEXAGON_QHL)
|
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DENABLE_QHL")
|
|
endif()
|
|
|
|
function(add_android_paths)
|
|
get_hexagon_sdk_property("${USE_HEXAGON_SDK}" "${USE_HEXAGON_ARCH}"
|
|
SDK_INCLUDE SDK_INCLUDE_DIRS
|
|
DSPRPC_LIB DSPRPC_LIB_DIRS
|
|
RPCMEM_ROOT RPCMEM_ROOT_DIR
|
|
)
|
|
if(NOT SDK_INCLUDE_DIRS OR NOT DSPRPC_LIB_DIRS OR NOT RPCMEM_ROOT_DIR)
|
|
message(WARNING "Could not locate some Hexagon SDK components")
|
|
endif()
|
|
|
|
include_directories(SYSTEM
|
|
${SDK_INCLUDE_DIRS}
|
|
"${RPCMEM_ROOT_DIR}/inc"
|
|
)
|
|
link_directories(${DSPRPC_LIB_DIRS})
|
|
endfunction()
|
|
|
|
function(add_hexagon_wrapper_paths)
|
|
if(NOT DEFINED HEXAGON_TOOLCHAIN)
|
|
message(FATAL_ERROR "This function must be called after find_hexagon_toolchain")
|
|
endif()
|
|
include_directories(SYSTEM
|
|
"${HEXAGON_TOOLCHAIN}/include/iss"
|
|
)
|
|
link_directories("${HEXAGON_TOOLCHAIN}/lib/iss")
|
|
endfunction()
|
|
|
|
if(BUILD_FOR_HEXAGON)
|
|
# When building FOR Hexagon (the DSP itself), all runtime sources go into
|
|
# the single libtvm_runtime (static or shared). No per-backend DSO split.
|
|
file_glob_append(RUNTIME_HEXAGON_SRCS
|
|
"${TVMRT_SOURCE_DIR}/*.cc"
|
|
)
|
|
# Add builtins to RelaxVM
|
|
tvm_file_glob(GLOB VM_BUILTIN_SRC_CC src/runtime/vm/hexagon/*.cc)
|
|
list(APPEND RUNTIME_SRCS ${VM_BUILTIN_SRC_CC})
|
|
else()
|
|
file_glob_append(RUNTIME_HEXAGON_SRCS
|
|
"${TVMRT_SOURCE_DIR}/hexagon_module.cc"
|
|
)
|
|
endif()
|
|
|
|
set(htp_supported_archs "v68" "v69" "v73" "v75")
|
|
list(FIND htp_supported_archs "${USE_HEXAGON_ARCH}" supported_arch_index)
|
|
if(${supported_arch_index} EQUAL -1)
|
|
# Exclude User DMA files when building for archs below v68
|
|
list(REMOVE_ITEM RUNTIME_HEXAGON_SRCS "${TVMRT_SOURCE_DIR}/hexagon_user_dma.cc")
|
|
endif()
|
|
|
|
if(BUILD_FOR_HEXAGON)
|
|
get_hexagon_sdk_property("${USE_HEXAGON_SDK}" "${USE_HEXAGON_ARCH}"
|
|
SDK_INCLUDE SDK_INCLUDE_DIRS
|
|
QURT_INCLUDE QURT_INCLUDE_DIRS
|
|
)
|
|
if(NOT SDK_INCLUDE_DIRS OR NOT QURT_INCLUDE_DIRS)
|
|
message(WARNING "Could not locate some Hexagon SDK components")
|
|
endif()
|
|
|
|
# Set the compiler arch flag.
|
|
add_definitions("-m${USE_HEXAGON_ARCH}")
|
|
|
|
# Add SDK and QuRT includes when building for Hexagon.
|
|
include_directories(SYSTEM ${SDK_INCLUDE_DIRS} ${QURT_INCLUDE_DIRS})
|
|
|
|
set(USE_CUSTOM_LOGGING ON) # To use a custom logger
|
|
|
|
# QHL support.
|
|
if(USE_HEXAGON_QHL)
|
|
file_glob_append(TVM_QHL_WRAPPER_SRCS
|
|
"${TVMRT_SOURCE_DIR}/qhl/*.cc"
|
|
)
|
|
|
|
include_directories(
|
|
"${USE_HEXAGON_SDK}/libs/qhl_hvx/inc/qhmath_hvx"
|
|
"${USE_HEXAGON_SDK}/libs/qhl_hvx/inc/internal/"
|
|
|
|
"${USE_HEXAGON_SDK}/libs/qhl/inc/qhmath"
|
|
"${USE_HEXAGON_SDK}/libs/qhl/src/internal/"
|
|
)
|
|
set_property(SOURCE ${TVM_QHL_WRAPPER_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS "-Wno-narrowing -mhvx -mhvx-length=128B")
|
|
|
|
list(APPEND TVM_RUNTIME_LINKER_LIBS -Wl,--whole-archive ${USE_HEXAGON_SDK}/libs/qhl_hvx/prebuilt/hexagon_toolv84_v68/libqhmath_hvx.a -Wl,--no-whole-archive)
|
|
list(APPEND TVM_RUNTIME_LINKER_LIBS -Wl,--whole-archive ${USE_HEXAGON_SDK}/libs/qhl/prebuilt/hexagon_toolv84_v68/libqhmath.a -Wl,--no-whole-archive)
|
|
|
|
endif()
|
|
|
|
# Exclude HVX implementation files when building for archs below v68
|
|
if(${supported_arch_index} GREATER -1)
|
|
# Hand-written ops
|
|
file_glob_append(RUNTIME_HEXAGON_SRCS
|
|
"${TVMRT_SOURCE_DIR}/ops/*.cc"
|
|
)
|
|
|
|
include_directories(
|
|
"${TVMRT_SOURCE_DIR}/ops"
|
|
)
|
|
|
|
set_source_files_properties(
|
|
"${TVMRT_SOURCE_DIR}/ops/conv2d_quant_hvx.cc"
|
|
PROPERTIES COMPILE_FLAGS "-mhvx"
|
|
)
|
|
|
|
set_source_files_properties(
|
|
"${TVMRT_SOURCE_DIR}/ops/conv2d_fp16_hvx.cc"
|
|
PROPERTIES COMPILE_FLAGS "-mhvx"
|
|
)
|
|
endif()
|
|
|
|
# Include hexagon external library runtime sources
|
|
if(USE_HEXAGON_EXTERNAL_LIBS)
|
|
# Check if the libs are provided as an absolute path
|
|
if(EXISTS ${USE_HEXAGON_EXTERNAL_LIBS})
|
|
# Check if the libs are provided as a git url
|
|
elseif(USE_HEXAGON_EXTERNAL_LIBS MATCHES "\.git$")
|
|
if(NOT DEFINED HEXAGON_EXTERNAL_LIBS_SHA)
|
|
message(FATAL_ERROR "HEXAGON_EXTERNA_LIBS_SHA must be set when "
|
|
"USE_HEXAGON_EXTERNAL_LIBS is set to a git repository")
|
|
endif()
|
|
include(FetchContent)
|
|
FetchContent_Declare(hexagon_external
|
|
GIT_REPOSITORY "${USE_HEXAGON_EXTERNAL_LIBS}"
|
|
GIT_TAG "${HEXAGON_EXTERNAL_LIBS_SHA}")
|
|
FetchContent_MakeAvailable(hexagon_external)
|
|
set(USE_HEXAGON_EXTERNAL_LIBS "${hexagon_external_SOURCE_DIR}")
|
|
else()
|
|
message(FATAL_ERROR "Invalid use of USE_HEXAGON_EXTERNAL_LIBS="
|
|
"${USE_HEXAGON_EXTERNAL_LIBS}; USE_HEXAGON_EXTERNAL_LIBS only "
|
|
"supports absolute paths and git repository urls")
|
|
endif()
|
|
|
|
file_glob_append(HEXAGON_EXTERNAL_RUNTIME_SRCS
|
|
"${USE_HEXAGON_EXTERNAL_LIBS}/src/runtime/hexagon/*.cc"
|
|
)
|
|
list(APPEND RUNTIME_HEXAGON_SRCS "${HEXAGON_EXTERNAL_RUNTIME_SRCS}")
|
|
if(EXISTS "${USE_HEXAGON_EXTERNAL_LIBS}/HexagonExternalCompileFlags.cmake")
|
|
# External libraries will define HEXAGON_EXTERNAL_LIBS_COMPILE_FLAGS,
|
|
# changing this variable name will break downstream external libraries.
|
|
include("${USE_HEXAGON_EXTERNAL_LIBS}/HexagonExternalCompileFlags.cmake")
|
|
set_source_files_properties(
|
|
"${HEXAGON_EXTERNAL_RUNTIME_SRCS}"
|
|
PROPERTIES COMPILE_FLAGS "${HEXAGON_EXTERNAL_LIBS_COMPILE_FLAGS}"
|
|
)
|
|
endif()
|
|
endif()
|
|
endif()
|
|
|
|
if(USE_HEXAGON_RPC)
|
|
function(build_rpc_idl)
|
|
get_hexagon_sdk_property("${USE_HEXAGON_SDK}" "${USE_HEXAGON_ARCH}"
|
|
SDK_INCLUDE SDK_INCLUDE_DIRS
|
|
QAIC_EXE QAIC_EXE_PATH
|
|
)
|
|
foreach(INCDIR IN LISTS SDK_INCLUDE_DIRS)
|
|
list(APPEND QAIC_FLAGS "-I${INCDIR}")
|
|
endforeach()
|
|
|
|
add_custom_command(
|
|
OUTPUT
|
|
"${TVMRT_SOURCE_DIR}/rpc/hexagon_rpc.h"
|
|
"${TVMRT_SOURCE_DIR}/rpc/hexagon_rpc_skel.c"
|
|
"${TVMRT_SOURCE_DIR}/rpc/hexagon_rpc_stub.c"
|
|
COMMAND
|
|
${QAIC_EXE_PATH} ${QAIC_FLAGS}
|
|
"${TVMRT_SOURCE_DIR}/rpc/hexagon_rpc.idl"
|
|
-o "${TVMRT_SOURCE_DIR}/rpc"
|
|
MAIN_DEPENDENCY "${TVMRT_SOURCE_DIR}/rpc/hexagon_rpc.idl"
|
|
)
|
|
|
|
if("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
|
|
# We can't easily fix this at the source-code level, because the .c file is generated
|
|
# by the qaic program. But it should be safe to ignore the warning:
|
|
# https://stackoverflow.com/questions/13905200/is-it-wise-to-ignore-gcc-clangs-wmissing-braces-warning
|
|
set_source_files_properties("${TVMRT_SOURCE_DIR}/rpc/hexagon_rpc_stub.c"
|
|
PROPERTY COMPILE_FLAGS "-Wno-missing-braces")
|
|
endif()
|
|
endfunction()
|
|
|
|
if(BUILD_FOR_ANDROID)
|
|
# Android part
|
|
add_android_paths()
|
|
build_rpc_idl()
|
|
file_glob_append(RUNTIME_HEXAGON_SRCS
|
|
"${TVMRT_SOURCE_DIR}/rpc/android/*.cc"
|
|
)
|
|
# Add this file separately, because it's auto-generated, and glob won't
|
|
# find it during cmake-time.
|
|
list(APPEND RUNTIME_HEXAGON_SRCS
|
|
"${TVMRT_SOURCE_DIR}/rpc/hexagon_rpc_stub.c"
|
|
)
|
|
list(APPEND TVM_RUNTIME_LINKER_LIBS cdsprpc)
|
|
|
|
elseif(BUILD_FOR_HEXAGON)
|
|
# Hexagon part
|
|
find_hexagon_toolchain()
|
|
build_rpc_idl()
|
|
|
|
# Include the generic RPC code into the TVM runtime.
|
|
list(APPEND RUNTIME_HEXAGON_SRCS
|
|
"${TVM_CORE_RUNTIME_SOURCE_DIR}/rpc/minrpc/minrpc_server.h"
|
|
"${TVM_CORE_RUNTIME_SOURCE_DIR}/rpc/minrpc/rpc_reference.h"
|
|
"${TVM_CORE_RUNTIME_SOURCE_DIR}/rpc/rpc_module.cc"
|
|
"${TVM_CORE_RUNTIME_SOURCE_DIR}/rpc/rpc_endpoint.cc"
|
|
"${TVM_CORE_RUNTIME_SOURCE_DIR}/rpc/rpc_session.cc"
|
|
# TODO(masahi): Remove rpc_local_session.cc after verifying that things work without it
|
|
"${TVM_CORE_RUNTIME_SOURCE_DIR}/rpc/rpc_local_session.cc"
|
|
)
|
|
set(HEXAGON_PROFILER_DIR "${TVMRT_SOURCE_DIR}/profiler")
|
|
# Add the hardware-specific RPC code into the skel library.
|
|
set_property(SOURCE ${HEXAGON_PROFILER_DIR}/lwp_handler.S PROPERTY LANGUAGE C)
|
|
add_library(hexagon_rpc_skel SHARED
|
|
"${TVMRT_SOURCE_DIR}/rpc/hexagon/rpc_server.cc"
|
|
"${TVMRT_SOURCE_DIR}/rpc/hexagon_rpc_skel.c"
|
|
"${HEXAGON_PROFILER_DIR}/prof_utils.cc"
|
|
"${HEXAGON_PROFILER_DIR}/lwp_handler.S"
|
|
)
|
|
target_include_directories(hexagon_rpc_skel
|
|
SYSTEM PRIVATE "${TVMRT_SOURCE_DIR}/rpc"
|
|
)
|
|
# Add the simulator-specific RPC code into a shared library to be
|
|
# executed via run_main_on_sim.
|
|
add_library(hexagon_rpc_sim SHARED
|
|
"${TVMRT_SOURCE_DIR}/rpc/simulator/rpc_server.cc"
|
|
"${HEXAGON_PROFILER_DIR}/prof_utils.cc"
|
|
"${HEXAGON_PROFILER_DIR}/lwp_handler.S"
|
|
)
|
|
target_link_libraries(hexagon_rpc_sim
|
|
-Wl,--whole-archive tvm_runtime -Wl,--no-whole-archive
|
|
)
|
|
|
|
elseif(BUILD_FOR_HOST)
|
|
find_hexagon_toolchain()
|
|
add_hexagon_wrapper_paths()
|
|
file_glob_append(RUNTIME_HEXAGON_SRCS
|
|
"${TVMRT_SOURCE_DIR}/rpc/simulator/session.cc"
|
|
)
|
|
list(APPEND TVM_RUNTIME_LINKER_LIBS "-lwrapper")
|
|
endif()
|
|
endif() # USE_HEXAGON_RPC
|
|
|
|
# When building for the Hexagon DSP itself, all sources fold into
|
|
# libtvm_runtime (static/shared). When building for a host with
|
|
# USE_HEXAGON=ON, create a separate libtvm_runtime_hexagon.so.
|
|
if(BUILD_FOR_HEXAGON)
|
|
list(APPEND RUNTIME_SRCS ${RUNTIME_HEXAGON_SRCS} ${TVM_QHL_WRAPPER_SRCS})
|
|
elseif(USE_HEXAGON)
|
|
message(STATUS "Build hexagon device runtime")
|
|
add_library(tvm_runtime_hexagon_objs OBJECT ${RUNTIME_HEXAGON_SRCS} ${TVM_QHL_WRAPPER_SRCS})
|
|
target_link_libraries(tvm_runtime_hexagon_objs PUBLIC tvm_ffi_header)
|
|
set_target_properties(tvm_runtime_hexagon_objs PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
|
if(TVM_VISIBILITY_FLAG)
|
|
target_compile_options(tvm_runtime_hexagon_objs PRIVATE "${TVM_VISIBILITY_FLAG}")
|
|
endif()
|
|
add_library(tvm_runtime_hexagon SHARED $<TARGET_OBJECTS:tvm_runtime_hexagon_objs>)
|
|
list(APPEND TVM_RUNTIME_BACKEND_LIBS tvm_runtime_hexagon)
|
|
target_link_libraries(tvm_runtime_hexagon PUBLIC tvm_runtime)
|
|
tvm_configure_target_library(tvm_runtime_hexagon RUNTIME_MODULE)
|
|
endif()
|