From c3cdf434f32e3f158b8caedd45113384bf4aed14 Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Thu, 27 Apr 2023 01:40:15 -0700 Subject: [PATCH] Add supporting RISC-V cross compilation workflows Add RISC-V cross-compilation test Enable RVV support at compile time --- .github/workflows/cmake.yml | 14 +++++++++++ CMakeLists.txt | 19 +++++++++++++++ README.md | 3 ++- arch/riscv/README.md | 45 +++++++++++++++++++++++++++++++++++ arch/riscv/riscv_features.c | 15 ++++++++++++ arch/riscv/riscv_features.h | 18 ++++++++++++++ cmake/detect-intrinsics.cmake | 18 ++++++++++++++ cmake/toolchain-riscv.cmake | 28 ++++++++++++++++++++++ cpu_features.c | 2 ++ cpu_features.h | 4 ++++ 10 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 arch/riscv/README.md create mode 100644 arch/riscv/riscv_features.c create mode 100644 arch/riscv/riscv_features.h create mode 100644 cmake/toolchain-riscv.cmake diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index d50a2dcfab..bbed1db0ca 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -378,6 +378,12 @@ jobs: # https://github.com/llvm/llvm-project/issues/55785 msan-options: use_sigaltstack=0 + - name: Ubuntu Clang RISC-V + os: ubuntu-latest + cmake-args: -GNinja -DCMAKE_TOOLCHAIN_FILE=./cmake/toolchain-riscv.cmake -DTOOLCHAIN_PATH=${PWD}/prebuilt-riscv-toolchain-qemu/riscv-clang -DQEMU_PATH=${PWD}/prebuilt-riscv-toolchain-qemu/riscv-qemu/bin/qemu-riscv64 + packages: build-essential cmake ninja-build + codecov: ubuntu_clang_toolchain_riscv + - name: Ubuntu Emscripten WASM32 os: ubuntu-latest chost: wasm32 @@ -502,6 +508,14 @@ jobs: sudo apt-get update sudo apt-get install -y --allow-downgrades --no-install-recommends ${{ matrix.packages }} + - name: Download prebuilt RISC-V Clang toolchain & QEMU emulator + if: runner.os == 'Linux' && contains(matrix.name, 'RISC-V') + run: | + gh release download ubuntu20.04_llvm16.0.0_qemu7.0.0 --repo sifive/prepare-riscv-toolchain-qemu + tar zxvf prebuilt-riscv-toolchain-qemu.tar.gz + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Install packages (Windows) if: runner.os == 'Windows' run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index cdb38311dd..a6199d35ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,6 +105,8 @@ elseif(BASEARCH_PPC_FOUND) option(WITH_ALTIVEC "Build with AltiVec (VMX) optimisations for PowerPC" ON) option(WITH_POWER8 "Build with optimisations for POWER8" ON) option(WITH_POWER9 "Build with optimisations for POWER9" ON) +elseif(BASEARCH_RISCV_FOUND) + option(WITH_RVV "Build with RVV intrinsics" ON) elseif(BASEARCH_S360_FOUND) option(WITH_DFLTCC_DEFLATE "Build with DFLTCC intrinsics for compression on IBM Z" OFF) option(WITH_DFLTCC_INFLATE "Build with DFLTCC intrinsics for decompression on IBM Z" OFF) @@ -135,6 +137,7 @@ mark_as_advanced(FORCE WITH_ALTIVEC WITH_POWER8 WITH_POWER9 + WITH_RVV WITH_INFLATE_STRICT WITH_INFLATE_ALLOW_INVALID_DIST WITH_UNALIGNED @@ -544,6 +547,8 @@ if(BASEARCH_ARM_FOUND) set(ARCHDIR "arch/arm") elseif(BASEARCH_PPC_FOUND) set(ARCHDIR "arch/power") +elseif(BASEARCH_RISCV_FOUND) + set(ARCHDIR "arch/riscv") elseif(BASEARCH_S360_FOUND) set(ARCHDIR "arch/s390") elseif(BASEARCH_X86_FOUND) @@ -718,6 +723,18 @@ if(WITH_OPTIM) set(WITH_POWER9 OFF) endif() endif() + elseif(BASEARCH_RISCV_FOUND) + if(WITH_RVV) + check_rvv_intrinsics() + if(HAVE_RVV_INTRIN) + add_definitions(-DRISCV_FEATURES) + add_definitions(-DRISCV_RVV) + list(APPEND ZLIB_ARCH_HDRS ${ARCHDIR}/riscv_features.h) + list(APPEND ZLIB_ARCH_SRCS ${ARCHDIR}/riscv_features.c) + else() + set(WITH_RVV OFF) + endif() + endif() elseif(BASEARCH_S360_FOUND) check_s390_intrinsics() if(HAVE_S390_INTRIN) @@ -1228,6 +1245,8 @@ elseif(BASEARCH_PPC_FOUND) add_feature_info(WITH_ALTIVEC WITH_ALTIVEC "Build with AltiVec optimisations") add_feature_info(WITH_POWER8 WITH_POWER8 "Build with optimisations for POWER8") add_feature_info(WITH_POWER9 WITH_POWER9 "Build with optimisations for POWER9") +elseif(BASEARCH_RISCV_FOUND) + add_feature_info(WITH_RVV WITH_RVV "Build with RVV intrinsics") elseif(BASEARCH_S360_FOUND) add_feature_info(WITH_DFLTCC_DEFLATE WITH_DFLTCC_DEFLATE "Build with DFLTCC intrinsics for compression on IBM Z") add_feature_info(WITH_DFLTCC_INFLATE WITH_DFLTCC_INFLATE "Build with DFLTCC intrinsics for decompression on IBM Z") diff --git a/README.md b/README.md index aa72365c95..367dc9463b 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Features * Comprehensive set of CMake unit tests * Code sanitizers, fuzzing, and coverage * GitHub Actions continuous integration on Windows, macOS, and Linux - * Emulated CI for ARM, AARCH64, PPC, PPC64, SPARC64, S390x using qemu + * Emulated CI for ARM, AARCH64, PPC, PPC64, RISCV, SPARC64, S390x using qemu History @@ -221,6 +221,7 @@ Advanced Build Options | WITH_NEON | --without-neon | Build with NEON intrinsics | ON | | WITH_ALTIVEC | --without-altivec | Build with AltiVec (VMX) intrinsics | ON | | WITH_POWER8 | --without-power8 | Build with POWER8 optimisations | ON | +| WITH_RVV | | Build with RVV intrinsics | ON | | WITH_CRC32_VX | --without-crc32-vx | Build with vectorized CRC32 on IBM Z | ON | | WITH_DFLTCC_DEFLATE | --with-dfltcc-deflate | Build with DFLTCC intrinsics for compression on IBM Z | OFF | | WITH_DFLTCC_INFLATE | --with-dfltcc-inflate | Build with DFLTCC intrinsics for decompression on IBM Z | OFF | diff --git a/arch/riscv/README.md b/arch/riscv/README.md new file mode 100644 index 0000000000..b4309e1a0a --- /dev/null +++ b/arch/riscv/README.md @@ -0,0 +1,45 @@ +# Building RISC-V Target with Cmake # + +> **Warning** +> We cannot detect rvv support at runtime, running the rvv code on a no-rvv target is a risk. Users should disable the rvv when the target does not support it. +> +> We will have a better solution when the kernels update `hwcap` or `hwprobe` for risc-v. + +## Prerequisite: Build RISC-V Clang Toolchain and QEMU ## + +If you don't have prebuilt clang and riscv64 qemu, you can refer to the [script](https://github.com/sifive/prepare-riscv-toolchain-qemu/blob/main/prepare_riscv_toolchain_qemu.sh) to get the source. Copy the script to the zlib-ng root directory, and run it to download the source and build them. Modify the content according to your conditions (e.g., toolchain version). + +```bash +./prepare_riscv_toolchain_qemu.sh +``` + +After running script, clang & qemu are built in `build-toolchain-qemu/riscv-clang/` & `build-toolchain-qemu/riscv-qemu/`. + +`build-toolchain-qemu/riscv-clang/` is your `TOOLCHAIN_PATH`. +`build-toolchain-qemu/riscv-qemu/bin/qemu-riscv64` is your `QEMU_PATH`. + +You can also download the prebuilt toolchain & qemu from [the release page](https://github.com/sifive/prepare-riscv-toolchain-qemu/releases), and enjoy using them. + +## Cross-Compile for RISC-V Target ## + +```bash +cmake -G Ninja -B ./build-riscv \ + -D CMAKE_TOOLCHAIN_FILE=./cmake/toolchain-riscv.cmake \ + -D CMAKE_INSTALL_PREFIX=./build-riscv/install \ + -D TOOLCHAIN_PATH={TOOLCHAIN_PATH} \ + -D QEMU_PATH={QEMU_PATH} \ + . + +cmake --build ./build-riscv +``` + +Disable the option if there is no RVV support: +``` +-D WITH_RVV=OFF +``` + +## Run Unittests on User Mode QEMU ## + +```bash +cd ./build-riscv && ctest --verbose +``` diff --git a/arch/riscv/riscv_features.c b/arch/riscv/riscv_features.c new file mode 100644 index 0000000000..362d714835 --- /dev/null +++ b/arch/riscv/riscv_features.c @@ -0,0 +1,15 @@ +#include +#include +#include + +#include "../../zbuild.h" +#include "riscv_features.h" + +/* TODO: detect risc-v cpu info at runtime when the kernel updates hwcap or hwprobe for risc-v */ +void Z_INTERNAL riscv_check_features(struct riscv_cpu_features *features) { +#if defined(__riscv_v) && defined(__linux__) + features->has_rvv = 1; +#else + features->has_rvv = 0; +#endif +} diff --git a/arch/riscv/riscv_features.h b/arch/riscv/riscv_features.h new file mode 100644 index 0000000000..f933fc9acb --- /dev/null +++ b/arch/riscv/riscv_features.h @@ -0,0 +1,18 @@ +/* riscv_features.h -- check for riscv features. + * + * Copyright (C) 2023 SiFive, Inc. All rights reserved. + * Contributed by Alex Chiang + * + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef RISCV_H_ +#define RISCV_H_ + +struct riscv_cpu_features { + int has_rvv; +}; + +void Z_INTERNAL riscv_check_features(struct riscv_cpu_features *features); + +#endif /* RISCV_H_ */ diff --git a/cmake/detect-intrinsics.cmake b/cmake/detect-intrinsics.cmake index 0491d53bf8..c20c9e1607 100644 --- a/cmake/detect-intrinsics.cmake +++ b/cmake/detect-intrinsics.cmake @@ -347,6 +347,24 @@ macro(check_power8_intrinsics) set(CMAKE_REQUIRED_FLAGS) endmacro() +macro(check_rvv_intrinsics) + if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") + if(NOT NATIVEFLAG) + set(RISCVFLAG "-march=rv64gcv") + endif() + endif() + # Check whether compiler supports RVV + set(CMAKE_REQUIRED_FLAGS "${RISCVFLAG} ${NATIVEFLAG}") + check_c_source_compiles( + "#include + int main() { + return 0; + }" + HAVE_RVV_INTRIN + ) + set(CMAKE_REQUIRED_FLAGS) +endmacro() + macro(check_s390_intrinsics) check_c_source_compiles( "#include diff --git a/cmake/toolchain-riscv.cmake b/cmake/toolchain-riscv.cmake new file mode 100644 index 0000000000..9cf8fdb7fe --- /dev/null +++ b/cmake/toolchain-riscv.cmake @@ -0,0 +1,28 @@ +set(CMAKE_CROSSCOMPILING TRUE) +set(CMAKE_SYSTEM_NAME "Linux") +set(CMAKE_SYSTEM_PROCESSOR "riscv64") + +# Avoid to use system path for cross-compile +set(CMAKE_FIND_USE_CMAKE_SYSTEM_PATH FALSE) + +set(TOOLCHAIN_PATH "" CACHE STRING "The toolchain path.") +if(NOT TOOLCHAIN_PATH) + set(TOOLCHAIN_PATH ${CMAKE_SOURCE_DIR}/prebuilt-riscv-toolchain-qemu/riscv-clang) +endif() + +set(TOOLCHAIN_PREFIX "riscv64-unknown-linux-gnu-" CACHE STRING "The toolchain prefix.") +set(QEMU_PATH "" CACHE STRING "The qemu path.") +if(NOT QEMU_PATH) + set(QEMU_PATH ${CMAKE_SOURCE_DIR}/prebuilt-riscv-toolchain-qemu/riscv-qemu/bin/qemu-riscv64) +endif() + +# toolchain setting +set(CMAKE_C_COMPILER "${TOOLCHAIN_PATH}/bin/${TOOLCHAIN_PREFIX}clang") +set(CMAKE_CXX_COMPILER "${TOOLCHAIN_PATH}/bin/${TOOLCHAIN_PREFIX}clang++") + +# disable auto-vectorizer +add_compile_options(-fno-vectorize -fno-slp-vectorize) + +# emulator setting +set(QEMU_CPU_OPTION "rv64,zba=true,zbb=true,zbc=true,zbs=true,v=true,vlen=512,elen=64,vext_spec=v1.0") +set(CMAKE_CROSSCOMPILING_EMULATOR ${QEMU_PATH} -cpu ${QEMU_CPU_OPTION} -L ${TOOLCHAIN_PATH}/sysroot/) diff --git a/cpu_features.c b/cpu_features.c index b69a01304a..3585172e5d 100644 --- a/cpu_features.c +++ b/cpu_features.c @@ -17,5 +17,7 @@ Z_INTERNAL void cpu_check_features(struct cpu_features *features) { power_check_features(&features->power); #elif defined(S390_FEATURES) s390_check_features(&features->s390); +#elif defined(RISCV_FEATURES) + riscv_check_features(&features->riscv); #endif } diff --git a/cpu_features.h b/cpu_features.h index 2e1a888e38..647d027f6e 100644 --- a/cpu_features.h +++ b/cpu_features.h @@ -18,6 +18,8 @@ # include "arch/power/power_features.h" #elif defined(S390_FEATURES) # include "arch/s390/s390_features.h" +#elif defined(RISCV_FEATURES) +# include "arch/riscv/riscv_features.h" #endif struct cpu_features { @@ -29,6 +31,8 @@ struct cpu_features { struct power_cpu_features power; #elif defined(S390_FEATURES) struct s390_cpu_features s390; +#elif defined(RISCV_FEATURES) + struct riscv_cpu_features riscv; #else char empty; #endif