diff --git a/.gitignore b/.gitignore index 83458ab2057..14ddc1ff1e7 100644 --- a/.gitignore +++ b/.gitignore @@ -59,6 +59,7 @@ python/doc/ .vscode .idea/ +.icodemate/ .pytest_cache/ pkgs docker_cache diff --git a/cpp/cmake_modules/DefineOptions.cmake b/cpp/cmake_modules/DefineOptions.cmake index b58ab3cd381..a61cfc2a4e0 100644 --- a/cpp/cmake_modules/DefineOptions.cmake +++ b/cpp/cmake_modules/DefineOptions.cmake @@ -171,6 +171,10 @@ takes precedence over ccache if a storage backend is configured" ON) "SVE128" # fixed size SVE "SVE256" # " "SVE512" # " + "RVV" # size agnostic RVV + "RVV128" # fixed size RVV + "RVV256" # " + "RVV512" # " "DEFAULT") define_option_string(ARROW_RUNTIME_SIMD_LEVEL @@ -183,6 +187,9 @@ takes precedence over ccache if a storage backend is configured" ON) "SVE128" # fixed size SVE "SVE256" # " "SVE512" # " + "RVV128" # fixed size RVV + "RVV256" # " + "RVV512" # " "MAX") define_option(ARROW_ALTIVEC "Build with Altivec if compiler has support" ON) diff --git a/cpp/cmake_modules/SetupCxxFlags.cmake b/cpp/cmake_modules/SetupCxxFlags.cmake index 750e3bef29c..5aa3ea7d7df 100644 --- a/cpp/cmake_modules/SetupCxxFlags.cmake +++ b/cpp/cmake_modules/SetupCxxFlags.cmake @@ -167,6 +167,24 @@ elseif(ARROW_CPU_FLAG STREQUAL "aarch64") if(ARROW_SIMD_LEVEL STREQUAL "DEFAULT") set(ARROW_SIMD_LEVEL "NEON") endif() +elseif(ARROW_CPU_FLAG STREQUAL "riscv64") + set(ARROW_RVV_MARCH "rv64gcv") + check_cxx_compiler_flag("-march=${ARROW_RVV_MARCH}" CXX_SUPPORTS_RVV) + if(CXX_SUPPORTS_RVV AND ARROW_RUNTIME_SIMD_LEVEL MATCHES "^(RVV128|RVV256|RVV512|MAX)$") + set(ARROW_HAVE_RUNTIME_RVV128 ON) + add_definitions(-DARROW_HAVE_RUNTIME_RVV128) + endif() + if(CXX_SUPPORTS_RVV AND ARROW_RUNTIME_SIMD_LEVEL MATCHES "^(RVV256|RVV512|MAX)$") + set(ARROW_HAVE_RUNTIME_RVV256 ON) + add_definitions(-DARROW_HAVE_RUNTIME_RVV256) + endif() + if(CXX_SUPPORTS_RVV AND ARROW_RUNTIME_SIMD_LEVEL MATCHES "^(RVV512|MAX)$") + set(ARROW_HAVE_RUNTIME_RVV512 ON) + add_definitions(-DARROW_HAVE_RUNTIME_RVV512) + endif() + if(ARROW_SIMD_LEVEL STREQUAL "DEFAULT") + set(ARROW_SIMD_LEVEL "NONE") + endif() endif() # Support C11 @@ -548,6 +566,32 @@ if(ARROW_CPU_FLAG STREQUAL "aarch64") endif() endif() +if(ARROW_CPU_FLAG STREQUAL "riscv64") + if(ARROW_SIMD_LEVEL MATCHES "RVV") + if(NOT CXX_SUPPORTS_RVV) + message(FATAL_ERROR "RVV required but compiler doesn't support it.") + endif() + string(REGEX MATCH "[0-9]+" RVV_VECTOR_BITS ${ARROW_SIMD_LEVEL}) + if(RVV_VECTOR_BITS) + set(ARROW_RVV_FIXED_FLAGS + "-march=${ARROW_RVV_MARCH}_zvl${RVV_VECTOR_BITS}b" "-mrvv-vector-bits=zvl") + check_cxx_compiler_flag("${ARROW_RVV_FIXED_FLAGS}" CXX_SUPPORTS_RVV_FIXED) + if(NOT CXX_SUPPORTS_RVV_FIXED) + message(FATAL_ERROR "Fixed-width RVV (zvl${RVV_VECTOR_BITS}b) required but compiler doesn't support it.") + endif() + set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} ${ARROW_RVV_FIXED_FLAGS}") + set(ARROW_HAVE_RVV${RVV_VECTOR_BITS} ON) + add_definitions(-DARROW_HAVE_RVV${RVV_VECTOR_BITS}) + else() + set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -march=${ARROW_RVV_MARCH}") + set(ARROW_HAVE_RVV_SIZELESS ON) + add_definitions(-DARROW_HAVE_RVV_SIZELESS) + endif() + elseif(NOT ARROW_SIMD_LEVEL STREQUAL "NONE") + message(WARNING "ARROW_SIMD_LEVEL=${ARROW_SIMD_LEVEL} not supported by riscv64.") + endif() +endif() + if(NOT WIN32 AND NOT APPLE) if(ARROW_USE_MOLD) find_program(LD_MOLD ld.mold) diff --git a/cpp/src/arrow/util/cpu_info.cc b/cpp/src/arrow/util/cpu_info.cc index 2f7cd2408df..a7e9c5fbc44 100644 --- a/cpp/src/arrow/util/cpu_info.cc +++ b/cpp/src/arrow/util/cpu_info.cc @@ -98,6 +98,14 @@ void OsRetrieveCpuInfo(int64_t* hardware_flags, CpuInfo::Vendor* vendor) { *hardware_flags |= (sve && sve_size == 32) ? CpuInfo::SVE256 : 0; *hardware_flags |= (sve && sve_size == 64) ? CpuInfo::SVE512 : 0; + // RVV and length + const bool rvv = cpu.rvv(); + const auto rvv_size = cpu.rvv_size_bytes(); + *hardware_flags |= rvv ? CpuInfo::RVV : 0; + *hardware_flags |= (rvv && rvv_size == 16) ? CpuInfo::RVV128 : 0; + *hardware_flags |= (rvv && rvv_size == 32) ? CpuInfo::RVV256 : 0; + *hardware_flags |= (rvv && rvv_size == 64) ? CpuInfo::RVV512 : 0; + // x86 only switch (cpu.known_manufacturer()) { case (xsimd::x86_manufacturer::intel): @@ -363,6 +371,49 @@ void ArchVerifyCpuRequirements(const CpuInfo* ci) { } } +#elif XSIMD_TARGET_RISCV +//------------------------------ RISCV64 ------------------------------// +bool ArchParseUserSimdLevel(const std::string& simd_level, int64_t* hardware_flags) { + enum { + USER_SIMD_NONE, + USER_SIMD_RVV, + USER_SIMD_RVV128, + USER_SIMD_RVV256, + USER_SIMD_RVV512, + USER_SIMD_MAX, + }; + + int level = USER_SIMD_MAX; + if (simd_level == "RVV") { + level = USER_SIMD_RVV; + } else if (simd_level == "RVV128") { + level = USER_SIMD_RVV128; + } else if (simd_level == "RVV256") { + level = USER_SIMD_RVV256; + } else if (simd_level == "RVV512") { + level = USER_SIMD_RVV512; + } else if (simd_level == "NONE") { + level = USER_SIMD_NONE; + } else { + return false; + } + + if (level < USER_SIMD_RVV512) *hardware_flags &= ~CpuInfo::RVV512; + if (level < USER_SIMD_RVV256) *hardware_flags &= ~CpuInfo::RVV256; + if (level < USER_SIMD_RVV128) *hardware_flags &= ~CpuInfo::RVV128; + if (level < USER_SIMD_RVV) *hardware_flags &= ~CpuInfo::RVV; + return true; +} + +void ArchVerifyCpuRequirements(const CpuInfo* ci) { +# if defined(ARROW_HAVE_RVV128) || defined(ARROW_HAVE_RVV256) || \ + defined(ARROW_HAVE_RVV512) || defined(ARROW_HAVE_RVV_SIZELESS) + if (!ci->IsDetected(CpuInfo::RVV)) { + DCHECK(false) << "CPU does not support the RISC-V Vector instruction set"; + } +# endif +} + #else //------------------------------ PPC, ... ------------------------------// bool ArchParseUserSimdLevel(const std::string& simd_level, int64_t* hardware_flags) { diff --git a/cpp/src/arrow/util/cpu_info.h b/cpp/src/arrow/util/cpu_info.h index 7e4ca4c7f14..6f451787688 100644 --- a/cpp/src/arrow/util/cpu_info.h +++ b/cpp/src/arrow/util/cpu_info.h @@ -57,6 +57,12 @@ class ARROW_EXPORT CpuInfo { static constexpr int64_t SVE256 = (1LL << 34); static constexpr int64_t SVE512 = (1LL << 35); + /// RISC-V features + static constexpr int64_t RVV = (1LL << 37); + static constexpr int64_t RVV128 = (1LL << 38); + static constexpr int64_t RVV256 = (1LL << 39); + static constexpr int64_t RVV512 = (1LL << 40); + /// Cache enums for L1 (data), L2 and L3 enum class CacheLevel { L1 = 0, L2, L3, Last = L3 }; diff --git a/cpp/src/arrow/util/dispatch_internal.h b/cpp/src/arrow/util/dispatch_internal.h index 36e5152ee65..a8118ea9a37 100644 --- a/cpp/src/arrow/util/dispatch_internal.h +++ b/cpp/src/arrow/util/dispatch_internal.h @@ -38,6 +38,9 @@ enum class DispatchLevel : int { SVE128, SVE256, SVE512, + RVV128, + RVV256, + RVV512, MAX }; @@ -221,6 +224,36 @@ constexpr DynamicDispatchTarget BestDispatchTarget( # define ARROW_DISPATCH_TARGET_SVE512(func) #endif +#if defined(ARROW_HAVE_RVV128) || defined(ARROW_HAVE_RUNTIME_RVV128) +# define ARROW_DISPATCH_TARGET_RVV128(func) \ + ::arrow::internal::DynamicDispatchTarget{ \ + ::arrow::internal::DispatchLevel::RVV128, \ + (func), \ + }, +#else +# define ARROW_DISPATCH_TARGET_RVV128(func) +#endif + +#if defined(ARROW_HAVE_RVV256) || defined(ARROW_HAVE_RUNTIME_RVV256) +# define ARROW_DISPATCH_TARGET_RVV256(func) \ + ::arrow::internal::DynamicDispatchTarget{ \ + ::arrow::internal::DispatchLevel::RVV256, \ + (func), \ + }, +#else +# define ARROW_DISPATCH_TARGET_RVV256(func) +#endif + +#if defined(ARROW_HAVE_RVV512) || defined(ARROW_HAVE_RUNTIME_RVV512) +# define ARROW_DISPATCH_TARGET_RVV512(func) \ + ::arrow::internal::DynamicDispatchTarget{ \ + ::arrow::internal::DispatchLevel::RVV512, \ + (func), \ + }, +#else +# define ARROW_DISPATCH_TARGET_RVV512(func) +#endif + /// A concept to specify how dynamic dispatch should be handled. /// /// A requirement is that the list of available targets must be compile time @@ -352,6 +385,12 @@ class DynamicDispatch { return cpu_info->IsSupported(CpuInfo::SVE256); case DispatchLevel::SVE512: return cpu_info->IsSupported(CpuInfo::SVE512); + case DispatchLevel::RVV128: + return cpu_info->IsSupported(CpuInfo::RVV128); + case DispatchLevel::RVV256: + return cpu_info->IsSupported(CpuInfo::RVV256); + case DispatchLevel::RVV512: + return cpu_info->IsSupported(CpuInfo::RVV512); default: return false; } diff --git a/cpp/src/arrow/util/io_util_test.cc b/cpp/src/arrow/util/io_util_test.cc index 44188b3f2ee..2015b6b74a1 100644 --- a/cpp/src/arrow/util/io_util_test.cc +++ b/cpp/src/arrow/util/io_util_test.cc @@ -1109,6 +1109,14 @@ TEST(CpuInfo, Basic) { ASSERT_EQ(ci->hardware_flags(), 0); ci_rw->EnableFeature(original_hardware_flags, true); ASSERT_EQ(ci->hardware_flags(), original_hardware_flags); + +#if defined(__riscv) && __riscv_xlen == 64 + if (ci->IsDetected(CpuInfo::RVV)) { + EXPECT_NE(ci->hardware_flags() & CpuInfo::RVV, 0); + EXPECT_NE( + ci->hardware_flags() & (CpuInfo::RVV128 | CpuInfo::RVV256 | CpuInfo::RVV512), 0); + } +#endif } TEST(Memory, TotalMemory) {