# 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 $) 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()