diff --git a/GraphBLAS/CMakeLists.txt b/GraphBLAS/CMakeLists.txt index dd146ad193..f296adbd1a 100644 --- a/GraphBLAS/CMakeLists.txt +++ b/GraphBLAS/CMakeLists.txt @@ -162,6 +162,26 @@ if ( DEFINED GBAVX512F ) endif ( ) endif ( ) +#------------------------------------------------------------------------------- +# RISC-V +#------------------------------------------------------------------------------- + +if ( DEFINED GBRISCV64 ) + if ( GBRISCV64 ) + set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGBRISCV64=1 " ) + else ( ) + set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGBRISCV64=0 " ) + endif ( ) +endif ( ) + +if ( DEFINED GBRVV ) + if ( GBRVV ) + set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGBRVV=1 " ) + else ( ) + set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGBRVV=0 " ) + endif ( ) +endif ( ) + #------------------------------------------------------------------------------- # check compiler features #------------------------------------------------------------------------------- diff --git a/GraphBLAS/FactoryKernels/GB_AxB__plus_times_fp32.c b/GraphBLAS/FactoryKernels/GB_AxB__plus_times_fp32.c index f2fa0f0bfc..17d00f1083 100644 --- a/GraphBLAS/FactoryKernels/GB_AxB__plus_times_fp32.c +++ b/GraphBLAS/FactoryKernels/GB_AxB__plus_times_fp32.c @@ -7,6 +7,9 @@ //------------------------------------------------------------------------------ +#ifdef GBRISCV64 +#include +#endif #include "GB.h" #include "GB_control.h" #include "mxm/GB_AxB_saxpy.h" @@ -14,6 +17,14 @@ #include "assign/GB_bitmap_assign_methods.h" #include "FactoryKernels/GB_AxB__include2.h" +// riscv intrinsics + +#define VSETVL(x) __riscv_vsetvl_e32m8(x) +#define VLE(x,y) __riscv_vle32_v_f32m8(x, y) +#define VFMACC(x,y,z,w) __riscv_vfmacc_vf_f32m8(x, y, z, w) +#define VSE(x,y,z) __riscv_vse32_v_f32m8(x, y, z) +#define VECTORTYPE vfloat32m8_t + // semiring operators: #define GB_MULTADD(z,a,b,i,k,j) z += (a*b) #define GB_MULT(z,a,b,i,k,j) z = (a*b) @@ -43,6 +54,7 @@ // special case semirings: #define GB_SEMIRING_HAS_AVX_IMPLEMENTATION 1 +#define GB_SEMIRING_HAS_RVV_IMPLEMENTATION 1 // monoid properties: #define GB_Z_TYPE float @@ -282,6 +294,27 @@ GrB_Info GB (_Asaxpy4B__plus_times_fp32) #endif + //---------------------------------------------------------------------- + // saxpy5 method with RISC-V vectors + //--------------------------------------------------------------------- + + #if GB_COMPILER_SUPPORTS_RVV1 + + GB_TARGET_RVV1 static inline void GB_AxB_saxpy5_unrolled_rvv + ( + GrB_Matrix C, + const GrB_Matrix A, + const GrB_Matrix B, + const int ntasks, + const int nthreads, + const int64_t *B_slice + ) + { + #include "mxm/template/GB_AxB_saxpy5_lv.c" + } + + #endif + //---------------------------------------------------------------------- // saxpy5 method unrolled, with no vectors //---------------------------------------------------------------------- diff --git a/GraphBLAS/FactoryKernels/GB_AxB__plus_times_fp64.c b/GraphBLAS/FactoryKernels/GB_AxB__plus_times_fp64.c index 40d1d7d2ae..b772916144 100644 --- a/GraphBLAS/FactoryKernels/GB_AxB__plus_times_fp64.c +++ b/GraphBLAS/FactoryKernels/GB_AxB__plus_times_fp64.c @@ -7,6 +7,9 @@ //------------------------------------------------------------------------------ +#ifdef GBRISCV64 +#include +#endif #include "GB.h" #include "GB_control.h" #include "mxm/GB_AxB_saxpy.h" @@ -14,6 +17,14 @@ #include "assign/GB_bitmap_assign_methods.h" #include "FactoryKernels/GB_AxB__include2.h" +// riscv intrinsics + +#define VSETVL(x) __riscv_vsetvl_e64m8(x) +#define VLE(x,y) __riscv_vle64_v_f64m8(x, y) +#define VFMACC(x,y,z,w) __riscv_vfmacc_vf_f64m8(x, y, z, w) +#define VSE(x,y,z) __riscv_vse64_v_f64m8(x, y, z) +#define VECTORTYPE vfloat64m8_t + // semiring operators: #define GB_MULTADD(z,a,b,i,k,j) z += (a*b) #define GB_MULT(z,a,b,i,k,j) z = (a*b) @@ -43,6 +54,7 @@ // special case semirings: #define GB_SEMIRING_HAS_AVX_IMPLEMENTATION 1 +#define GB_SEMIRING_HAS_RVV_IMPLEMENTATION 1 // monoid properties: #define GB_Z_TYPE double @@ -282,6 +294,26 @@ GrB_Info GB (_Asaxpy4B__plus_times_fp64) #endif + //---------------------------------------------------------------------- + // saxpy5 method with RISC-V vectors + //---------------------------------------------------------------------- + #if GB_COMPILER_SUPPORTS_RVV1 + + GB_TARGET_RVV1 static inline void GB_AxB_saxpy5_unrolled_rvv + ( + GrB_Matrix C, + const GrB_Matrix A, + const GrB_Matrix B, + const int ntasks, + const int nthreads, + const int64_t *B_slice + ) + { + #include "mxm/template/GB_AxB_saxpy5_lv.c" + } + + #endif + //---------------------------------------------------------------------- // saxpy5 method unrolled, with no vectors //---------------------------------------------------------------------- diff --git a/GraphBLAS/GraphBLAS/rename/GB_rename.h b/GraphBLAS/GraphBLAS/rename/GB_rename.h index 2767635b09..3c8fe4fdf5 100644 --- a/GraphBLAS/GraphBLAS/rename/GB_rename.h +++ b/GraphBLAS/GraphBLAS/rename/GB_rename.h @@ -389,6 +389,7 @@ #define GB_Global_calloc_function_set GM_Global_calloc_function_set #define GB_Global_cpu_features_avx2 GM_Global_cpu_features_avx2 #define GB_Global_cpu_features_avx512f GM_Global_cpu_features_avx512f +#define GB_Global_cpu_features_rvv_1_0 GM_Global_cpu_features_rvv_1_0 #define GB_Global_cpu_features_query GM_Global_cpu_features_query #define GB_Global_flush_get GM_Global_flush_get #define GB_Global_flush_set GM_Global_flush_set diff --git a/GraphBLAS/Source/codegen/Generator/GB_AxB.c b/GraphBLAS/Source/codegen/Generator/GB_AxB.c index c3d8f1b0af..a038f3dc96 100644 --- a/GraphBLAS/Source/codegen/Generator/GB_AxB.c +++ b/GraphBLAS/Source/codegen/Generator/GB_AxB.c @@ -7,6 +7,9 @@ //------------------------------------------------------------------------------ +#ifdef GBRISCV64 +#include +#endif #include "GB.h" #include "GB_control.h" #include "mxm/GB_AxB_saxpy.h" @@ -310,6 +313,28 @@ m4_divert(if_semiring_has_avx) } #endif +m4_divert(if_semiring_has_rvv) + //---------------------------------------------------------------------- + // saxpy5 method with RISC-V vectors + //---------------------------------------------------------------------- + + #if GB_COMPILER_SUPPORTS_RVV1 + + GB_TARGET_RVV1 static inline void GB_AxB_saxpy5_unrolled_rvv + ( + GrB_Matrix C, + const GrB_Matrix A, + const GrB_Matrix B, + const int ntasks, + const int nthreads, + const int64_t *B_slice + ) + { + #include "mxm/template/GB_AxB_saxpy5_lv.c" + } + + #endif + m4_divert(if_saxpy5_enabled) //---------------------------------------------------------------------- diff --git a/GraphBLAS/Source/cpu/GB_cpu_features_impl.c b/GraphBLAS/Source/cpu/GB_cpu_features_impl.c index a8da662b12..1d6d39ab17 100644 --- a/GraphBLAS/Source/cpu/GB_cpu_features_impl.c +++ b/GraphBLAS/Source/cpu/GB_cpu_features_impl.c @@ -41,6 +41,7 @@ #include "src/impl_x86_freebsd.c" #include "src/impl_x86_linux_or_android.c" #include "src/impl_x86_windows.c" + #include "src/impl_riscv_linux.c" #if GBX86 #if (defined(__apple__) || defined(__APPLE__) || defined(__MACH__)) // needed for src/impl_x86_macos.c: diff --git a/GraphBLAS/Source/global/GB_Global.c b/GraphBLAS/Source/global/GB_Global.c index f0b53e9962..346dcbd796 100644 --- a/GraphBLAS/Source/global/GB_Global.c +++ b/GraphBLAS/Source/global/GB_Global.c @@ -131,6 +131,7 @@ typedef struct bool cpu_features_avx2 ; // x86_64 with AVX2 bool cpu_features_avx512f ; // x86_64 with AVX512f + bool cpu_features_rvv_1_0 ; // RISC-V with RVV1.0 //-------------------------------------------------------------------------- // CUDA (DRAFT: in progress): @@ -215,6 +216,7 @@ static GB_Global_struct GB_Global = // CPU features .cpu_features_avx2 = false, // x86_64 with AVX2 .cpu_features_avx512f = false, // x86_64 with AVX512f + .cpu_features_rvv_1_0 = false, // RISC-V with RVV1.0 // CUDA environment (DRAFT: in progress) .gpu_count = 0, // # of GPUs in the system @@ -306,16 +308,36 @@ void GB_Global_cpu_features_query (void) } #endif + } + #elif GBRISCV64 + { + //---------------------------------------------------------------------- + // xRISC-V architecture: see if RVV1.0 is supported + //---------------------------------------------------------------------- + + #if defined ( GBRVV ) + { + // the build system asserts whether or not RVV1.0 is available + GB_Global.cpu_features_rvv_1_0 = (bool) (GBRVV) ; + } + #else + { + // RVV1.0 not available + GB_Global.cpu_features_rvv_1_0 = false ; + } + #endif + } #else { //---------------------------------------------------------------------- - // not on the x86_64 architecture, so no AVX2 or AVX512F acceleration + // not on the x86_64 or RISC-V architecture, so no AVX2, AVX512F or RVV1.0 acceleration //---------------------------------------------------------------------- GB_Global.cpu_features_avx2 = false ; GB_Global.cpu_features_avx512f = false ; + GB_Global.cpu_features_rvv_1_0 = false ; } #endif @@ -331,6 +353,11 @@ bool GB_Global_cpu_features_avx512f (void) return (GB_Global.cpu_features_avx512f) ; } +bool GB_Global_cpu_features_rvv_1_0 (void) +{ + return (GB_Global.cpu_features_rvv_1_0) ; +} + //------------------------------------------------------------------------------ // hyper_switch //------------------------------------------------------------------------------ diff --git a/GraphBLAS/Source/global/GB_Global.h b/GraphBLAS/Source/global/GB_Global.h index 0f42b8767c..fb0d759495 100644 --- a/GraphBLAS/Source/global/GB_Global.h +++ b/GraphBLAS/Source/global/GB_Global.h @@ -17,6 +17,7 @@ void GB_Global_cpu_features_query (void) ; bool GB_Global_cpu_features_avx2 (void) ; bool GB_Global_cpu_features_avx512f (void) ; +bool GB_Global_cpu_features_rvv_1_0 (void) ; void GB_Global_mode_set (GrB_Mode mode) ; GrB_Mode GB_Global_mode_get (void) ; diff --git a/GraphBLAS/Source/include/GB_compiler.h b/GraphBLAS/Source/include/GB_compiler.h index ecccdc96a1..c4116c424e 100644 --- a/GraphBLAS/Source/include/GB_compiler.h +++ b/GraphBLAS/Source/include/GB_compiler.h @@ -245,6 +245,16 @@ #endif +#if !defined ( GBRISCV64 ) + + #if defined(__riscv) + #define GBRISCV64 1 + #else + #define GBRISCV64 0 + #endif + +#endif + //------------------------------------------------------------------------------ // AVX2 and AVX512F support for the x86_64 architecture //------------------------------------------------------------------------------ @@ -306,6 +316,31 @@ #define GB_TARGET_AVX2 #endif +//------------------------------------------------------------------------------ +// RVV1.0 support for the RISC-V architecture +//------------------------------------------------------------------------------ + +#if GBRISCV64 + #if GB_COMPILER_GCC + // TODO: add other compilers + #if __GNUC__ >= 13 + #define GB_COMPILER_SUPPORTS_RVV1 1 + #else + #define GB_COMPILER_SUPPORTS_RVV1 0 + #endif + #endif +#else + // non-RISC-V architecture + #define GB_COMPILER_SUPPORTS_RVV1 0 +#endif + +// prefix for function with target rvv1.0 +#if GB_COMPILER_SUPPORTS_RVV1 + #define GB_TARGET_RVV1 __attribute__ ((target ("arch=rv64gcv"))) +#else + #define GB_TARGET_RVV1 +#endif + //------------------------------------------------------------------------------ // disable Google's cpu_featgures on some compilers //------------------------------------------------------------------------------ diff --git a/GraphBLAS/Source/jit_kernels/template/GB_jit_kernel_AxB_saxpy5.c b/GraphBLAS/Source/jit_kernels/template/GB_jit_kernel_AxB_saxpy5.c index 4b3acc6653..d172d3ed7c 100644 --- a/GraphBLAS/Source/jit_kernels/template/GB_jit_kernel_AxB_saxpy5.c +++ b/GraphBLAS/Source/jit_kernels/template/GB_jit_kernel_AxB_saxpy5.c @@ -8,6 +8,9 @@ //------------------------------------------------------------------------------ #include "include/GB_AxB_saxpy3_template.h" +#ifdef GBRISCV64 +#include +#endif GB_JIT_GLOBAL GB_JIT_KERNEL_AXB_SAXPY5_PROTO (GB_jit_kernel) ; @@ -82,6 +85,27 @@ GB_JIT_GLOBAL GB_JIT_KERNEL_AXB_SAXPY5_PROTO (GB_jit_kernel) ; } #endif + + //---------------------------------------------------------------------- + // saxpy5 method with RISC-V vectors + //---------------------------------------------------------------------- + + #if GB_COMPILER_SUPPORTS_RVV1 + + GB_TARGET_RVV1 static inline void GB_AxB_saxpy5_unrolled_rvv + ( + GrB_Matrix C, + const GrB_Matrix A, + const GrB_Matrix B, + const int ntasks, + const int nthreads, + const int64_t *B_slice + ) + { + #include "template/GB_AxB_saxpy5_lv.c" + } + + #endif #endif @@ -171,6 +195,20 @@ GB_JIT_GLOBAL GB_JIT_KERNEL_AXB_SAXPY5_PROTO (GB_jit_kernel) } #endif + #if GB_SEMIRING_HAS_RVV_IMPLEMENTATION + { + #if GB_COMPILER_SUPPORTS_RVV1 + if (cpu_has_avx2) + { + // RISC-V64 with RVV1.0 + GB_AxB_saxpy5_unrolled_rvv (C, A, B, ntasks, nthreads, + B_slice) ; + return (GrB_SUCCESS) ; + } + #endif + } + #endif + // any architecture and any semiring GB_AxB_saxpy5_unrolled_vanilla (C, A, B, ntasks, nthreads, B_slice) ; diff --git a/GraphBLAS/Source/mxm/factory/GB_AxB_saxpy5_meta.c b/GraphBLAS/Source/mxm/factory/GB_AxB_saxpy5_meta.c index 9a48d43859..d0b4646efb 100644 --- a/GraphBLAS/Source/mxm/factory/GB_AxB_saxpy5_meta.c +++ b/GraphBLAS/Source/mxm/factory/GB_AxB_saxpy5_meta.c @@ -143,6 +143,17 @@ } #endif #endif + + #if GB_SEMIRING_HAS_RVV_IMPLEMENTATION + #if GB_COMPILER_SUPPORTS_RVV1 + if (GB_Global_cpu_features_rvv_1_0 ( )) + { + GB_AxB_saxpy5_unrolled_rvv (C, A, B, + ntasks, nthreads, B_slice) ; + return (GrB_SUCCESS) ; + } + #endif + #endif // any architecture and any built-in semiring GB_AxB_saxpy5_unrolled_vanilla (C, A, B, ntasks, nthreads, B_slice) ; diff --git a/GraphBLAS/Source/mxm/include/GB_mxm_shared_definitions.h b/GraphBLAS/Source/mxm/include/GB_mxm_shared_definitions.h index 5b530993c6..d709470418 100644 --- a/GraphBLAS/Source/mxm/include/GB_mxm_shared_definitions.h +++ b/GraphBLAS/Source/mxm/include/GB_mxm_shared_definitions.h @@ -71,6 +71,12 @@ #define GB_SEMIRING_HAS_AVX_IMPLEMENTATION 0 #endif +//1 if the semiring has a RVV1.0 implementation +#ifndef GB_SEMIRING_HAS_RVV_IMPLEMENTATION +#define GB_SEMIRING_HAS_RVV_IMPLEMENTATION 0 +#endif + + //------------------------------------------------------------------------------ // special multiply operators //------------------------------------------------------------------------------ diff --git a/GraphBLAS/Source/mxm/template/GB_AxB_saxpy5_lv.c b/GraphBLAS/Source/mxm/template/GB_AxB_saxpy5_lv.c new file mode 100644 index 0000000000..dde2f6e836 --- /dev/null +++ b/GraphBLAS/Source/mxm/template/GB_AxB_saxpy5_lv.c @@ -0,0 +1,53 @@ +{ + const int64_t m = C->vlen; + const int64_t *restrict Bp = B->p; + const int64_t *restrict Bh = B->h; + const int64_t *restrict Bi = B->i; + const GB_A_TYPE *restrict Ax = (GB_A_TYPE *)A->x; + const GB_B_TYPE *restrict Bx = (GB_B_TYPE *)B->x; + size_t vl = VSETVL(m); + GB_C_TYPE *restrict Cx = (GB_C_TYPE *)C->x; + +#pragma omp parallel for num_threads(nthreads) schedule(dynamic, 1) + for (int tid = 0; tid < ntasks; tid++) + { + const int64_t jB_start = B_slice[tid]; + const int64_t jB_end = B_slice[tid + 1]; + + for (int64_t jB = jB_start; jB < jB_end; jB++) + { + const int64_t j = GBH_B(Bh, jB); + GB_C_TYPE *restrict Cxj = Cx + (j * m); + const int64_t pB_start = Bp[jB]; + const int64_t pB_end = Bp[jB + 1]; + for (int64_t i = 0; i < m && (m - i) >= vl; i += vl) + { + VECTORTYPE vc = VLE(Cxj + i, vl); + for (int64_t pB = pB_start; pB < pB_end; pB++) + { + const int64_t k = Bi[pB]; + const GB_B_TYPE bkj = Bx[pB]; + VECTORTYPE va = VLE(Ax + i + k * m, vl); + vc = VFMACC(vc, bkj, va, vl); + } + + VSE(Cxj + i, vc, vl); + } + int64_t remaining = m % vl; + if (remaining > 0) + { + int64_t i = m - remaining; + VECTORTYPE vc = VLE(Cxj + i, remaining); + for (int64_t pB = pB_start; pB < pB_end; pB++) + { + const int64_t k = Bi[pB]; + const GB_B_TYPE bkj = Bx[pB]; + VECTORTYPE va = VLE(Ax + i + k * m, remaining); + vc = VFMACC(vc, bkj, va, remaining); + } + + VSE(Cxj + i, vc, remaining); + } + } + } +} diff --git a/GraphBLAS/cpu_features/CMakeLists.txt b/GraphBLAS/cpu_features/CMakeLists.txt index ac3c0a5498..942a1140f0 100644 --- a/GraphBLAS/cpu_features/CMakeLists.txt +++ b/GraphBLAS/cpu_features/CMakeLists.txt @@ -49,6 +49,7 @@ set(PROCESSOR_IS_ARM FALSE) set(PROCESSOR_IS_AARCH64 FALSE) set(PROCESSOR_IS_X86 FALSE) set(PROCESSOR_IS_POWER FALSE) +set(PROCESSOR_IS_RISCV FALSE) if(CMAKE_SYSTEM_PROCESSOR MATCHES "^mips") set(PROCESSOR_IS_MIPS TRUE) @@ -60,6 +61,8 @@ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64)|(AMD64|amd64)|(^i.86$)") set(PROCESSOR_IS_X86 TRUE) elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)") set(PROCESSOR_IS_POWER TRUE) +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "riscv") + set(PROCESSOR_IS_RISCV TRUE) endif() macro(add_cpu_features_headers_and_sources HDRS_LIST_NAME SRCS_LIST_NAME) @@ -78,6 +81,8 @@ macro(add_cpu_features_headers_and_sources HDRS_LIST_NAME SRCS_LIST_NAME) list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/internal/cpuid_x86.h) elseif(PROCESSOR_IS_POWER) list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_ppc.h) + elseif(PROCESSOR_IS_RISCV) + list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_riscv.h) else() message(FATAL_ERROR "Unsupported architectures ${CMAKE_SYSTEM_PROCESSOR}") endif() diff --git a/GraphBLAS/cpu_features/include/cpuinfo_riscv.h b/GraphBLAS/cpu_features/include/cpuinfo_riscv.h new file mode 100644 index 0000000000..1fa7aa5135 --- /dev/null +++ b/GraphBLAS/cpu_features/include/cpuinfo_riscv.h @@ -0,0 +1,72 @@ +// Copyright 2022 Google LLC +// +// Licensed 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. + +#ifndef CPU_FEATURES_INCLUDE_CPUINFO_RISCV_H_ +#define CPU_FEATURES_INCLUDE_CPUINFO_RISCV_H_ + +#include "cpu_features_cache_info.h" +#include "cpu_features_macros.h" + +#if !defined(CPU_FEATURES_ARCH_RISCV) +#error "Including cpuinfo_riscv.h from a non-riscv target." +#endif + +CPU_FEATURES_START_CPP_NAMESPACE + +typedef struct { + // Base + int RV32I : 1; // Base Integer Instruction Set, 32-bit + int RV64I : 1; // Base Integer Instruction Set, 64-bit + + // Extension + int M : 1; // Standard Extension for Integer Multiplication/Division + int A : 1; // Standard Extension for Atomic Instructions + int F : 1; // Standard Extension for Single-Precision Floating-Point + int D : 1; // Standard Extension for Double-Precision Floating-Point + int Q : 1; // Standard Extension for Quad-Precision Floating-Point + int C : 1; // Standard Extension for Compressed Instructions + int V : 1; // Standard Extension for Vector Instructions + int Zicsr : 1; // Control and Status Register (CSR) + int Zifencei : 1; // Instruction-Fetch Fence +} RiscvFeatures; + +typedef struct { + RiscvFeatures features; + char uarch[64]; // 0 terminated string + char vendor[64]; // 0 terminated string +} RiscvInfo; + +typedef enum { + RISCV_RV32I, + RISCV_RV64I, + RISCV_M, + RISCV_A, + RISCV_F, + RISCV_D, + RISCV_Q, + RISCV_C, + RISCV_V, + RISCV_Zicsr, + RISCV_Zifencei, + RISCV_LAST_, +} RiscvFeaturesEnum; + +RiscvInfo GetRiscvInfo(void); +int GetRiscvFeaturesEnumValue(const RiscvFeatures* features, + RiscvFeaturesEnum value); +const char* GetRiscvFeaturesEnumName(RiscvFeaturesEnum); + +CPU_FEATURES_END_CPP_NAMESPACE + +#endif // CPU_FEATURES_INCLUDE_CPUINFO_RISCV_H_ diff --git a/GraphBLAS/cpu_features/src/impl_riscv_linux.c b/GraphBLAS/cpu_features/src/impl_riscv_linux.c new file mode 100644 index 0000000000..8abec6eb9c --- /dev/null +++ b/GraphBLAS/cpu_features/src/impl_riscv_linux.c @@ -0,0 +1,111 @@ +// Copyright 2022 Google LLC +// +// Licensed 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 "cpu_features_macros.h" + +#ifdef CPU_FEATURES_ARCH_RISCV +#if defined(CPU_FEATURES_OS_LINUX) + +#include "cpuinfo_riscv.h" + +// According to +// https://elixir.bootlin.com/linux/latest/source/Documentation/devicetree/bindings/riscv/cpus.yaml +// isa string should match the following regex +// ^rv(?:64|32)imaf?d?q?c?b?v?k?h?(?:_[hsxz](?:[a-z])+)*$ +// +// This means we can test for features in this exact order except for Z +// extensions. + +//////////////////////////////////////////////////////////////////////////////// +// Definitions for introspection. +//////////////////////////////////////////////////////////////////////////////// +#define INTROSPECTION_TABLE \ + LINE(RISCV_RV32I, RV32I, "rv32i", RISCV_HWCAP_32, 0) \ + LINE(RISCV_RV64I, RV64I, "rv64i", RISCV_HWCAP_64, 0) \ + LINE(RISCV_M, M, "m", RISCV_HWCAP_M, 0) \ + LINE(RISCV_A, A, "a", RISCV_HWCAP_A, 0) \ + LINE(RISCV_F, F, "f", RISCV_HWCAP_F, 0) \ + LINE(RISCV_D, D, "d", RISCV_HWCAP_D, 0) \ + LINE(RISCV_Q, Q, "q", RISCV_HWCAP_Q, 0) \ + LINE(RISCV_C, C, "c", RISCV_HWCAP_C, 0) \ + LINE(RISCV_V, V, "v", RISCV_HWCAP_V, 0) \ + LINE(RISCV_Zicsr, Zicsr, "_zicsr", 0, 0) \ + LINE(RISCV_Zifencei, Zifencei, "_zifencei", 0, 0) +#define INTROSPECTION_PREFIX Riscv +#define INTROSPECTION_ENUM_PREFIX RISCV +#include "define_introspection_and_hwcaps.inl" + +//////////////////////////////////////////////////////////////////////////////// +// Implementation. +//////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "internal/filesystem.h" +#include "internal/stack_line_reader.h" + +static const RiscvInfo kEmptyRiscvInfo; + +static void HandleRiscVIsaLine(StringView line, RiscvFeatures* const features) { + for (size_t i = 0; i < RISCV_LAST_; ++i) { + StringView flag = str(kCpuInfoFlags[i]); + int index_of_flag = CpuFeatures_StringView_IndexOf(line, flag); + bool is_set = index_of_flag != -1; + kSetters[i](features, is_set); + if (is_set) + line = CpuFeatures_StringView_PopFront(line, index_of_flag + flag.size); + } +} + +static bool HandleRiscVLine(const LineResult result, RiscvInfo* const info) { + StringView line = result.line; + StringView key, value; + if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) { + if (CpuFeatures_StringView_IsEquals(key, str("isa"))) { + HandleRiscVIsaLine(value, &info->features); + } else if (CpuFeatures_StringView_IsEquals(key, str("uarch"))) { + int index = CpuFeatures_StringView_IndexOfChar(value, ','); + if (index == -1) return true; + StringView vendor = CpuFeatures_StringView_KeepFront(value, index); + StringView uarch = CpuFeatures_StringView_PopFront(value, index + 1); + CpuFeatures_StringView_CopyString(vendor, info->vendor, + sizeof(info->vendor)); + CpuFeatures_StringView_CopyString(uarch, info->uarch, + sizeof(info->uarch)); + } + } + return !result.eof; +} + +static void FillProcCpuInfoData(RiscvInfo* const info) { + const int fd = CpuFeatures_OpenFile("/proc/cpuinfo"); + if (fd >= 0) { + StackLineReader reader; + StackLineReader_Initialize(&reader, fd); + for (;;) { + if (!HandleRiscVLine(StackLineReader_NextLine(&reader), info)) break; + } + CpuFeatures_CloseFile(fd); + } +} + +RiscvInfo GetRiscvInfo(void) { + RiscvInfo info = kEmptyRiscvInfo; + FillProcCpuInfoData(&info); + return info; +} + +#endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID) +#endif // CPU_FEATURES_ARCH_RISCV diff --git a/GraphBLAS/cpu_features/src/utils/list_cpu_features.c b/GraphBLAS/cpu_features/src/utils/list_cpu_features.c index 4389f20249..c9d567269b 100644 --- a/GraphBLAS/cpu_features/src/utils/list_cpu_features.c +++ b/GraphBLAS/cpu_features/src/utils/list_cpu_features.c @@ -35,6 +35,8 @@ #include "cpuinfo_mips.h" #elif defined(CPU_FEATURES_ARCH_PPC) #include "cpuinfo_ppc.h" +#elif defined(CPU_FEATURES_ARCH_RISCV) +#include "cpuinfo_riscv.h" #endif // Design principles