mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-07-30 20:18:08 +00:00
Enable RISC-V 64-bit Cross-Compiling Support for ONNX Runtime on Linux (#19238)
### Description This pull request introduces the necessary changes to enable RISC-V 64-bit cross-compiling support for the ONNX Runtime on Linux. The RISC-V architecture has gained popularity as an open standard instruction set architecture, and this contribution aims to extend ONNX Runtime's compatibility to include RISC-V, thereby broadening the reach of ONNX models to a wider range of devices. ### Motivation and Context RISC-V is a free and open-source instruction set architecture (ISA) based on established RISC principles. It is provided under open licenses without fees. Due to its extensibility and freedom in both software and hardware, RISC-V is poised for widespread adoption in the future, especially in applications related to AI, parallel computing, and data centers. ### Example Build Command ``` ./build.sh --parallel --config Debug --rv64 --riscv_toolchain_root=/path/to/toolchain/root --skip_tests ``` ### Documentation Updates Relevant sections of the documentation will be updated to reflect the newly supported RISC-V 64-bit cross-compilation feature. https://github.com/microsoft/onnxruntime/pull/19239 --------- Signed-off-by: Phoebe Chen <phoebe.chen@sifive.com>
This commit is contained in:
parent
0c2f0ba90d
commit
4477f57ee3
5 changed files with 206 additions and 3 deletions
6
cmake/external/xnnpack.cmake
vendored
6
cmake/external/xnnpack.cmake
vendored
|
|
@ -6,10 +6,14 @@ set(FP16_BUILD_BENCHMARKS OFF CACHE INTERNAL "")
|
|||
set(PTHREADPOOL_BUILD_TESTS OFF CACHE INTERNAL "")
|
||||
set(PTHREADPOOL_BUILD_BENCHMARKS OFF CACHE INTERNAL "")
|
||||
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^riscv64.*")
|
||||
set(XNNPACK_USE_SYSTEM_LIBS OFF)
|
||||
endif()
|
||||
|
||||
# BF16 instructions cause ICE in Android NDK compiler
|
||||
if(CMAKE_ANDROID_ARCH_ABI STREQUAL armeabi-v7a)
|
||||
set(XNNPACK_ENABLE_ARM_BF16 OFF)
|
||||
ENDIF()
|
||||
endif()
|
||||
|
||||
# fp16 depends on psimd
|
||||
FetchContent_Declare(psimd URL ${DEP_URL_psimd} URL_HASH SHA1=${DEP_SHA1_psimd})
|
||||
|
|
|
|||
|
|
@ -189,6 +189,8 @@ elseif(NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
|
|||
set(ARM TRUE)
|
||||
elseif(dumpmachine_output MATCHES "^aarch64.*")
|
||||
set(ARM64 TRUE)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^riscv64.*")
|
||||
set(RISCV64 TRUE)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(i.86|x86?)$")
|
||||
set(X86 TRUE)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64)$")
|
||||
|
|
@ -198,7 +200,7 @@ elseif(NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
|
|||
endif()
|
||||
|
||||
|
||||
if (ARM64 OR ARM OR X86 OR X64 OR X86_64)
|
||||
if (RISCV64 OR ARM64 OR ARM OR X86 OR X64 OR X86_64)
|
||||
if((WIN32 AND NOT CMAKE_CXX_STANDARD_LIBRARIES MATCHES kernel32.lib) OR ((ARM64 OR ARM) AND MSVC))
|
||||
# msvc compiler report syntax error with cpuinfo arm source files
|
||||
# and cpuinfo does not have code for getting arm uarch info under windows
|
||||
|
|
|
|||
35
cmake/riscv64.toolchain.cmake
Normal file
35
cmake/riscv64.toolchain.cmake
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# Copyright (c) 2024 SiFive, Inc. All rights reserved.
|
||||
# Copyright (c) 2024, Phoebe Chen <phoebe.chen@sifive.com>
|
||||
# Licensed under the MIT License.
|
||||
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_PROCESSOR riscv64)
|
||||
|
||||
list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES RISCV_TOOLCHAIN_ROOT)
|
||||
|
||||
if(NOT RISCV_TOOLCHAIN_ROOT)
|
||||
message(FATAL_ERROR "RISCV_TOOLCHAIN_ROOT is not defined. Please set the RISCV_TOOLCHAIN_ROOT variable.")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_COMPILER "${RISCV_TOOLCHAIN_ROOT}/bin/riscv64-unknown-linux-gnu-gcc")
|
||||
set(CMAKE_ASM_COMPILER "${RISCV_TOOLCHAIN_ROOT}/bin/riscv64-unknown-linux-gnu-gcc")
|
||||
set(CMAKE_CXX_COMPILER "${RISCV_TOOLCHAIN_ROOT}/bin/riscv64-unknown-linux-gnu-g++")
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH ${RISCV_TOOLCHAIN_ROOT})
|
||||
set(CMAKE_SYSROOT "${RISCV_TOOLCHAIN_ROOT}/sysroot")
|
||||
set(CMAKE_INCLUDE_PATH "${RISCV_TOOLCHAIN_ROOT}/sysroot/usr/include/")
|
||||
set(CMAKE_LIBRARY_PATH "${RISCV_TOOLCHAIN_ROOT}/sysroot/usr/lib/")
|
||||
set(CMAKE_PROGRAM_PATH "${RISCV_TOOLCHAIN_ROOT}/sysroot/usr/bin/")
|
||||
|
||||
if(RISCV_QEMU_PATH)
|
||||
message(STATUS "RISCV_QEMU_PATH=${RISCV_QEMU_PATH} is defined during compilation.")
|
||||
set(CMAKE_CROSSCOMPILING_EMULATOR "${RISCV_QEMU_PATH};-L;${CMAKE_SYSROOT}")
|
||||
endif()
|
||||
|
||||
set(CMAKE_CROSSCOMPILING TRUE)
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
||||
|
||||
|
|
@ -328,6 +328,12 @@ def parse_arguments():
|
|||
help="[cross-compiling] Create Windows x86 makefiles. Requires --update and no existing cache "
|
||||
"CMake setup. Delete CMakeCache.txt if needed",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--rv64",
|
||||
action="store_true",
|
||||
help="[cross-compiling] Create riscv64 makefiles. Requires --update and no existing cache "
|
||||
"CMake setup. Delete CMakeCache.txt if needed",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--arm",
|
||||
action="store_true",
|
||||
|
|
@ -351,6 +357,18 @@ def parse_arguments():
|
|||
action="store_true",
|
||||
help="[cross-compiling] Create ARM64X Binary.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--riscv_toolchain_root",
|
||||
type=str,
|
||||
default="",
|
||||
help="Path to RISC-V toolchain root dir. e.g. --riscv_toolchain_root=$HOME/riscv-tools/",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--riscv_qemu_path",
|
||||
type=str,
|
||||
default="",
|
||||
help="Path to RISC-V qemu. e.g. --riscv_qemu_path=$HOME/qemu-dir/qemu-riscv64",
|
||||
)
|
||||
parser.add_argument("--msvc_toolset", help="MSVC toolset to use. e.g. 14.11")
|
||||
parser.add_argument("--windows_sdk_version", help="Windows SDK version to use. e.g. 10.0.19041.0")
|
||||
parser.add_argument("--android", action="store_true", help="Build for Android")
|
||||
|
|
@ -1077,6 +1095,19 @@ def generate_build_tree(
|
|||
"-Donnxruntime_DISABLE_OPTIONAL_TYPE=" + ("ON" if disable_optional_type else "OFF"),
|
||||
]
|
||||
|
||||
if args.rv64:
|
||||
add_default_definition(cmake_extra_defines, "onnxruntime_CROSS_COMPILING", "ON")
|
||||
if not args.riscv_toolchain_root:
|
||||
raise BuildError("The --riscv_toolchain_root option is required to build for riscv64.")
|
||||
if not args.skip_tests and not args.riscv_qemu_path:
|
||||
raise BuildError("The --riscv_qemu_path option is required for testing riscv64.")
|
||||
|
||||
cmake_args += [
|
||||
"-DRISCV_TOOLCHAIN_ROOT:PATH=" + args.riscv_toolchain_root,
|
||||
"-DRISCV_QEMU_PATH:PATH=" + args.riscv_qemu_path,
|
||||
"-DCMAKE_TOOLCHAIN_FILE=" + os.path.join(source_dir, "cmake", "riscv64.toolchain.cmake"),
|
||||
]
|
||||
|
||||
# By default on Windows we currently support only cross compiling for ARM/ARM64
|
||||
# (no native compilation supported through this script).
|
||||
if args.arm64 or args.arm64ec or args.arm:
|
||||
|
|
@ -1553,7 +1584,9 @@ def generate_build_tree(
|
|||
]
|
||||
if is_linux() and platform.machine() == "x86_64":
|
||||
# The following flags needs GCC 8 and newer
|
||||
cflags += ["-fstack-clash-protection", "-fcf-protection"]
|
||||
cflags += ["-fstack-clash-protection"]
|
||||
if not args.rv64:
|
||||
cflags += ["-fcf-protection"]
|
||||
cxxflags = cflags.copy()
|
||||
if args.use_cuda:
|
||||
cudaflags = cflags.copy()
|
||||
|
|
|
|||
129
tools/scripts/build_riscv64.sh
Executable file
129
tools/scripts/build_riscv64.sh
Executable file
|
|
@ -0,0 +1,129 @@
|
|||
#!/bin/bash
|
||||
# Copyright (c) 2024 SiFive, Inc. All rights reserved.
|
||||
# Copyright (c) 2024, Phoebe Chen <phoebe.chen@sifive.com>
|
||||
# Licensed under the MIT License.
|
||||
|
||||
|
||||
# The script is a sample for RISC-V 64-bit cross compilation in
|
||||
# GNU/Linux, and you should ensure that your environment meets
|
||||
# ORT requirements. You may need to make changes before using it.
|
||||
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
# Get directory this script is in
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
OS=$(uname -s)
|
||||
|
||||
if [ "$OS" == "Linux" ]; then
|
||||
LINUX_DISTRO=$(grep -oP '(?<=^ID=).+' /etc/os-release | tr -d '"')
|
||||
if [[ "${LINUX_DISTRO}" == "ubuntu" ]] ;then
|
||||
DIR_OS="Linux"
|
||||
else
|
||||
echo "${LINUX_DISTRO} is not supported"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
echo "$OS is not supported"
|
||||
return 1
|
||||
fi
|
||||
|
||||
function cleanup {
|
||||
if [ -d "$WORK_DIR" ]; then
|
||||
rm -rf "$WORK_DIR"
|
||||
fi
|
||||
}
|
||||
|
||||
# The riscv toolchain, qemu and other platform related settings.
|
||||
ORT_ROOT_DIR=$DIR/../..
|
||||
|
||||
PREBUILT_DIR="${ORT_ROOT_DIR}/riscv_tools"
|
||||
|
||||
read -rp "Enter the riscv tools root path(press enter to use default path:${PREBUILT_DIR}): " INPUT_PATH
|
||||
if [[ "${INPUT_PATH}" ]]; then
|
||||
PREBUILT_DIR=${INPUT_PATH}
|
||||
fi
|
||||
echo "The riscv tool prefix path: ${PREBUILT_DIR}"
|
||||
|
||||
WORK_DIR=$DIR/.prebuilt
|
||||
|
||||
# The prebuit toolchain download from riscv-collab works with Ubuntu.
|
||||
RISCV_GNU_TOOLCHAIN_URL="https://github.com/riscv-collab/riscv-gnu-toolchain/releases/download"
|
||||
TOOLCHAIN_VERSION="2023.11.20"
|
||||
RISCV_TOOLCHAIN_FILE_NAME="riscv64-glibc-ubuntu-22.04-llvm-nightly-2023.11.20-nightly.tar.gz"
|
||||
RISCV_TOOLCHAIN_FILE_SHA="98d6531b757fac01e065460c19abe8974976c607a8d88631cc5c1529d90ba7ba"
|
||||
|
||||
TOOLCHAIN_PATH_PREFIX=${PREBUILT_DIR}
|
||||
|
||||
execute () {
|
||||
if ! eval "$1"; then
|
||||
echo "command:\"$1\" error"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
execute "mkdir -p $WORK_DIR"
|
||||
|
||||
# Call the cleanup function when this tool exits.
|
||||
trap cleanup EXIT
|
||||
|
||||
# Download and install the toolchain from
|
||||
# https://github.com/riscv-collab/riscv-gnu-toolchain/releases/download
|
||||
download_file() {
|
||||
local file_name="$1"
|
||||
local install_path="$2"
|
||||
local file_sha="$3"
|
||||
|
||||
echo "Install $1 to $2"
|
||||
if [[ "$(ls -A "$2")" ]]; then
|
||||
read -rp "The file already exists. Keep it (y/n)? " replaced
|
||||
case ${replaced:0:1} in
|
||||
y|Y )
|
||||
echo "Skip download $1."
|
||||
return
|
||||
;;
|
||||
* )
|
||||
rm -rf "$2"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
echo "Download ${file_name} ..."
|
||||
mkdir -p "$install_path"
|
||||
wget --progress=bar:force:noscroll --directory-prefix="${WORK_DIR}" \
|
||||
"${RISCV_GNU_TOOLCHAIN_URL}/${TOOLCHAIN_VERSION}/${file_name}" && \
|
||||
echo "${file_sha} ${WORK_DIR}/${file_name}" | sha256sum -c -
|
||||
echo "Extract ${file_name} ..."
|
||||
tar -C "${install_path}" -xf "${WORK_DIR}/${file_name}" --no-same-owner \
|
||||
--strip-components=1
|
||||
}
|
||||
|
||||
|
||||
read -rp "Install RISCV toolchain(y/n)? " answer
|
||||
case ${answer:0:1} in
|
||||
y|Y )
|
||||
download_file "${RISCV_TOOLCHAIN_FILE_NAME}" \
|
||||
"${TOOLCHAIN_PATH_PREFIX}" \
|
||||
"${RISCV_TOOLCHAIN_FILE_SHA}"
|
||||
;;
|
||||
* )
|
||||
echo "Skip install RISCV toolchain."
|
||||
;;
|
||||
esac
|
||||
echo "download finished."
|
||||
|
||||
|
||||
# RISC-V cross compilation in GNU/Linux
|
||||
RISCV_TOOLCHAIN_ROOT=${TOOLCHAIN_PATH_PREFIX}
|
||||
RISCV_QEMU_PATH=${TOOLCHAIN_PATH_PREFIX}/bin/qemu-riscv64
|
||||
python3 "${ORT_ROOT_DIR}"/tools/ci_build/build.py \
|
||||
--build_dir "${ORT_ROOT_DIR}/build/${DIR_OS}" \
|
||||
--rv64 \
|
||||
--parallel \
|
||||
--skip_tests \
|
||||
--config RelWithDebInfo \
|
||||
--cmake_generator=Ninja \
|
||||
--riscv_qemu_path="${RISCV_QEMU_PATH}" \
|
||||
--riscv_toolchain_root="${RISCV_TOOLCHAIN_ROOT}" "$@"
|
||||
|
||||
|
||||
Loading…
Reference in a new issue