Skip to content

Commit

Permalink
Add limited support for RISC-V initialization (#190)
Browse files Browse the repository at this point in the history
* Adds header definitions for RISCV32 and RISCV64, and support in Bazel
  files for RISCV64. Adds ISA information for RISC-V and hwcap support.

* Adds support to construct the processor, core, cluster and package
  information reported by the system.

* Remaining support required for:
  - Inferring uarch of each processor (reports unknown for now).
  - Reading cache information (left empty for now).

Test: Build and ran cpu_info and isa_info on RISC-V QEMU instance and
RISC-V Android emulator. Confirmed that it properly reports the ISA
information as well as processor and cluster counts.
  • Loading branch information
prashanthswami authored Nov 14, 2023
1 parent d6860c4 commit 4e5be9e
Show file tree
Hide file tree
Showing 16 changed files with 1,196 additions and 25 deletions.
21 changes: 20 additions & 1 deletion BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ ARM_SRCS = [
"src/arm/uarch.c",
]

RISCV_SRCS = [
"src/riscv/uarch.c",
]

# Platform-specific sources and headers
LINUX_SRCS = [
"src/linux/cpulist.c",
Expand Down Expand Up @@ -81,6 +85,12 @@ LINUX_ARM32_SRCS = LINUX_ARM_SRCS + ["src/arm/linux/aarch32-isa.c"]

LINUX_ARM64_SRCS = LINUX_ARM_SRCS + ["src/arm/linux/aarch64-isa.c"]

LINUX_RISCV_SRCS = [
"src/riscv/linux/init.c",
"src/riscv/linux/riscv-isa.c",
"src/riscv/linux/riscv-hw.c",
]

ANDROID_ARM_SRCS = [
"src/arm/android/properties.c",
]
Expand Down Expand Up @@ -111,7 +121,8 @@ cc_library(
":linux_armeabi": COMMON_SRCS + ARM_SRCS + LINUX_SRCS + LINUX_ARM32_SRCS,
":linux_aarch64": COMMON_SRCS + ARM_SRCS + LINUX_SRCS + LINUX_ARM64_SRCS,
":linux_mips64": COMMON_SRCS + LINUX_SRCS,
":linux_riscv64": COMMON_SRCS + LINUX_SRCS,
":linux_riscv32": COMMON_SRCS + RISCV_SRCS + LINUX_SRCS + LINUX_RISCV_SRCS,
":linux_riscv64": COMMON_SRCS + RISCV_SRCS + LINUX_SRCS + LINUX_RISCV_SRCS,
":linux_s390x": COMMON_SRCS + LINUX_SRCS,
":macos_x86_64": COMMON_SRCS + X86_SRCS + MACH_SRCS + MACH_X86_SRCS,
":macos_x86_64_legacy": COMMON_SRCS + X86_SRCS + MACH_SRCS + MACH_X86_SRCS,
Expand All @@ -121,6 +132,7 @@ cc_library(
":android_arm64": COMMON_SRCS + ARM_SRCS + LINUX_SRCS + LINUX_ARM64_SRCS + ANDROID_ARM_SRCS,
":android_x86": COMMON_SRCS + X86_SRCS + LINUX_SRCS + LINUX_X86_SRCS,
":android_x86_64": COMMON_SRCS + X86_SRCS + LINUX_SRCS + LINUX_X86_SRCS,
":android_riscv64": COMMON_SRCS + RISCV_SRCS + LINUX_SRCS + LINUX_RISCV_SRCS,
":ios_x86_64": COMMON_SRCS + X86_SRCS + MACH_SRCS + MACH_X86_SRCS,
":ios_x86": COMMON_SRCS + X86_SRCS + MACH_SRCS + MACH_X86_SRCS,
":ios_armv7": COMMON_SRCS + MACH_SRCS + MACH_ARM_SRCS,
Expand Down Expand Up @@ -170,6 +182,8 @@ cc_library(
"src/arm/linux/cp.h",
"src/arm/api.h",
"src/arm/midr.h",
"src/riscv/api.h",
"src/riscv/linux/api.h",
],
)

Expand Down Expand Up @@ -231,6 +245,11 @@ config_setting(
values = {"cpu": "mips64"},
)

config_setting(
name = "linux_riscv32",
values = {"cpu": "riscv32"},
)

config_setting(
name = "linux_riscv64",
values = {"cpu": "riscv64"},
Expand Down
11 changes: 10 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ IF(NOT CMAKE_SYSTEM_PROCESSOR)
"cpuinfo will compile, but cpuinfo_initialize() will always fail.")
SET(CPUINFO_SUPPORTED_PLATFORM FALSE)
ENDIF()
ELSEIF(NOT CPUINFO_TARGET_PROCESSOR MATCHES "^(i[3-6]86|AMD64|x86(_64)?|armv[5-8].*|aarch64|arm64.*|ARM64.*)$")
ELSEIF(NOT CPUINFO_TARGET_PROCESSOR MATCHES "^(i[3-6]86|AMD64|x86(_64)?|armv[5-8].*|aarch64|arm64.*|ARM64.*|riscv(32|64))$")
MESSAGE(WARNING
"Target processor architecture \"${CPUINFO_TARGET_PROCESSOR}\" is not supported in cpuinfo. "
"cpuinfo will compile, but cpuinfo_initialize() will always fail.")
Expand Down Expand Up @@ -210,6 +210,15 @@ IF(CPUINFO_SUPPORTED_PLATFORM)
LIST(APPEND CPUINFO_SRCS
src/arm/android/properties.c)
ENDIF()
ELSEIF(CPUINFO_TARGET_PROCESSOR MATCHES "^(riscv(32|64))$")
LIST(APPEND CPUINFO_SRCS
src/riscv/uarch.c)
IF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
LIST(APPEND CPUINFO_SRCS
src/riscv/linux/init.c
src/riscv/linux/riscv-hw.c
src/riscv/linux/riscv-isa.c)
ENDIF()
ENDIF()

IF(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
Expand Down
6 changes: 6 additions & 0 deletions configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ def main(args):
sources += [
"arm/android/properties.c",
]
if build.target.is_riscv:
if build.target.is_linux:
sources += [
"riscv/linux/init.c",
"riscv/linux/riscv-isa.c",
]

if build.target.is_macos:
sources += ["mach/topology.c"]
Expand Down
121 changes: 121 additions & 0 deletions include/cpuinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@
#endif
#endif

#if defined(__riscv)
#if (__riscv_xlen == 32)
#define CPUINFO_ARCH_RISCV32 1
#elif (__riscv_xlen == 64)
#define CPUINFO_ARCH_RISCV64 1
#endif
#endif

/* Define other architecture-specific macros as 0 */

#ifndef CPUINFO_ARCH_X86
Expand Down Expand Up @@ -80,6 +88,14 @@
#define CPUINFO_ARCH_WASMSIMD 0
#endif

#ifndef CPUINFO_ARCH_RISCV32
#define CPUINFO_ARCH_RISCV32 0
#endif

#ifndef CPUINFO_ARCH_RISCV64
#define CPUINFO_ARCH_RISCV64 0
#endif

#if CPUINFO_ARCH_X86 && defined(_MSC_VER)
#define CPUINFO_ABI __cdecl
#elif CPUINFO_ARCH_X86 && defined(__GNUC__)
Expand Down Expand Up @@ -188,6 +204,8 @@ enum cpuinfo_vendor {
* Processors are variants of AMD cores.
*/
cpuinfo_vendor_hygon = 16,
/** SiFive, Inc. Vendor of RISC-V processor microarchitectures. */
cpuinfo_vendor_sifive = 17,

/* Active vendors of embedded CPUs */

Expand Down Expand Up @@ -1877,6 +1895,109 @@ static inline bool cpuinfo_has_arm_sve2(void) {
#endif
}

#if CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
/* This structure is not a part of stable API. Use cpuinfo_has_riscv_* functions instead. */
struct cpuinfo_riscv_isa {
/**
* Keep fields in line with the canonical order as defined by
* Section 27.11 Subset Naming Convention.
*/
/* RV32I/64I/128I Base ISA. */
bool i;
#if CPUINFO_ARCH_RISCV32
/* RV32E Base ISA. */
bool e;
#endif
/* Integer Multiply/Divide Extension. */
bool m;
/* Atomic Extension. */
bool a;
/* Single-Precision Floating-Point Extension. */
bool f;
/* Double-Precision Floating-Point Extension. */
bool d;
/* Compressed Extension. */
bool c;
/* Vector Extension. */
bool v;
};

extern struct cpuinfo_riscv_isa cpuinfo_isa;
#endif

static inline bool cpuinfo_has_riscv_i(void) {
#if CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
return cpuinfo_isa.i;
#else
return false;
#endif
}

static inline bool cpuinfo_has_riscv_e(void) {
#if CPUINFO_ARCH_RISCV32
return cpuinfo_isa.e;
#else
return false;
#endif
}

static inline bool cpuinfo_has_riscv_m(void) {
#if CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
return cpuinfo_isa.m;
#else
return false;
#endif
}

static inline bool cpuinfo_has_riscv_a(void) {
#if CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
return cpuinfo_isa.a;
#else
return false;
#endif
}

static inline bool cpuinfo_has_riscv_f(void) {
#if CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
return cpuinfo_isa.f;
#else
return false;
#endif
}

static inline bool cpuinfo_has_riscv_d(void) {
#if CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
return cpuinfo_isa.d;
#else
return false;
#endif
}

static inline bool cpuinfo_has_riscv_g(void) {
// The 'G' extension is simply shorthand for 'IMAFD'.
return cpuinfo_has_riscv_i()
&& cpuinfo_has_riscv_m()
&& cpuinfo_has_riscv_a()
&& cpuinfo_has_riscv_f()
&& cpuinfo_has_riscv_d();
}

static inline bool cpuinfo_has_riscv_c(void) {
#if CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
return cpuinfo_isa.c;
#else
return false;
#endif
}

static inline bool cpuinfo_has_riscv_v(void) {
#if CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
return cpuinfo_isa.v;
#else
return false;
#endif
}

const struct cpuinfo_processor* CPUINFO_ABI cpuinfo_get_processors(void);
const struct cpuinfo_core* CPUINFO_ABI cpuinfo_get_cores(void);
const struct cpuinfo_cluster* CPUINFO_ABI cpuinfo_get_clusters(void);
Expand Down
25 changes: 16 additions & 9 deletions src/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ uint32_t cpuinfo_packages_count = 0;
uint32_t cpuinfo_cache_count[cpuinfo_cache_level_max] = { 0 };
uint32_t cpuinfo_max_cache_size = 0;

#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 \
|| CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
struct cpuinfo_uarch_info* cpuinfo_uarchs = NULL;
uint32_t cpuinfo_uarchs_count = 0;
#else
Expand All @@ -41,7 +42,8 @@ uint32_t cpuinfo_max_cache_size = 0;
uint32_t cpuinfo_linux_cpu_max = 0;
const struct cpuinfo_processor** cpuinfo_linux_cpu_to_processor_map = NULL;
const struct cpuinfo_core** cpuinfo_linux_cpu_to_core_map = NULL;
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 \
|| CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
const uint32_t* cpuinfo_linux_cpu_to_uarch_index_map = NULL;
#endif
#endif
Expand Down Expand Up @@ -79,7 +81,8 @@ const struct cpuinfo_uarch_info* cpuinfo_get_uarchs() {
if (!cpuinfo_is_initialized) {
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "uarchs");
}
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 \
|| CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
return cpuinfo_uarchs;
#else
return &cpuinfo_global_uarch;
Expand Down Expand Up @@ -130,7 +133,8 @@ const struct cpuinfo_uarch_info* cpuinfo_get_uarch(uint32_t index) {
if (!cpuinfo_is_initialized) {
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "uarch");
}
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 \
|| CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
if CPUINFO_UNLIKELY(index >= cpuinfo_uarchs_count) {
return NULL;
}
Expand Down Expand Up @@ -175,7 +179,8 @@ uint32_t cpuinfo_get_uarchs_count(void) {
if (!cpuinfo_is_initialized) {
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "uarchs_count");
}
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 \
|| CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
return cpuinfo_uarchs_count;
#else
return 1;
Expand Down Expand Up @@ -351,7 +356,8 @@ uint32_t CPUINFO_ABI cpuinfo_get_current_uarch_index(void) {
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "current_uarch_index");
}
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 \
|| CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
#ifdef __linux__
if (cpuinfo_linux_cpu_to_uarch_index_map == NULL) {
/* Special case: avoid syscall on systems with only a single type of cores */
Expand All @@ -373,7 +379,7 @@ uint32_t CPUINFO_ABI cpuinfo_get_current_uarch_index(void) {
return 0;
#endif
#else
/* Only ARM/ARM64 processors may include cores of different types in the same package. */
/* Only ARM/ARM64/RISCV processors may include cores of different types in the same package. */
return 0;
#endif
}
Expand All @@ -382,7 +388,8 @@ uint32_t CPUINFO_ABI cpuinfo_get_current_uarch_index_with_default(uint32_t defau
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "current_uarch_index_with_default");
}
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 \
|| CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
#ifdef __linux__
if (cpuinfo_linux_cpu_to_uarch_index_map == NULL) {
/* Special case: avoid syscall on systems with only a single type of cores */
Expand All @@ -404,7 +411,7 @@ uint32_t CPUINFO_ABI cpuinfo_get_current_uarch_index_with_default(uint32_t defau
return default_uarch_index;
#endif
#else
/* Only ARM/ARM64 processors may include cores of different types in the same package. */
/* Only ARM/ARM64/RISCV processors may include cores of different types in the same package. */
return 0;
#endif
}
3 changes: 2 additions & 1 deletion src/cpuinfo/internal-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ extern CPUINFO_INTERNAL uint32_t cpuinfo_packages_count;
extern CPUINFO_INTERNAL uint32_t cpuinfo_cache_count[cpuinfo_cache_level_max];
extern CPUINFO_INTERNAL uint32_t cpuinfo_max_cache_size;

#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
extern CPUINFO_INTERNAL struct cpuinfo_uarch_info* cpuinfo_uarchs;
extern CPUINFO_INTERNAL uint32_t cpuinfo_uarchs_count;
#else
Expand All @@ -59,6 +59,7 @@ CPUINFO_PRIVATE void cpuinfo_x86_linux_init(void);
#endif
CPUINFO_PRIVATE void cpuinfo_arm_mach_init(void);
CPUINFO_PRIVATE void cpuinfo_arm_linux_init(void);
CPUINFO_PRIVATE void cpuinfo_riscv_linux_init(void);
CPUINFO_PRIVATE void cpuinfo_emscripten_init(void);

CPUINFO_PRIVATE uint32_t cpuinfo_compute_max_cache_size(const struct cpuinfo_processor* processor);
Expand Down
6 changes: 6 additions & 0 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ bool CPUINFO_ABI cpuinfo_initialize(void) {
#else
cpuinfo_log_error("operating system is not supported in cpuinfo");
#endif
#elif CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
#if defined(__linux__)
pthread_once(&init_guard, &cpuinfo_riscv_linux_init);
#else
cpuinfo_log_error("operating system is not supported in cpuinfo");
#endif
#elif CPUINFO_ARCH_ASMJS || CPUINFO_ARCH_WASM || CPUINFO_ARCH_WASMSIMD
#if defined(__EMSCRIPTEN_PTHREADS__)
pthread_once(&init_guard, &cpuinfo_emscripten_init);
Expand Down
Loading

0 comments on commit 4e5be9e

Please sign in to comment.