Add riscv cpu info detection.

* Supports:

 * The standard single-letter Vector detection.

 * Vector fp16 detection.

Signed-off-by: Darren Hsieh <darren.hsieh@sifive.com>
Change-Id: Ia7ee1bd8ec1a990f1b2b1700805942e99c0aa87b
Reviewed-on: https://chromium-review.googlesource.com/c/libyuv/libyuv/+/4401738
Commit-Queue: Frank Barchard <fbarchard@chromium.org>
Reviewed-by: Frank Barchard <fbarchard@chromium.org>
This commit is contained in:
Darren Hsieh 2023-04-01 07:11:11 -07:00 committed by libyuv LUCI CQ
parent ec48e4328e
commit aa47d668d8
8 changed files with 125 additions and 0 deletions

View File

@ -40,6 +40,9 @@ By default the cpu is detected and the most advanced form of SIMD is used. But
LIBYUV_DISABLE_LSX
LIBYUV_DISABLE_LASX
## RISCV CPUs
LIBYUV_DISABLE_RVV
# Test Width/Height/Repeat
The unittests default to a small image (128x72) to run fast. This can be set by environment variable to test a specific resolutions.

View File

@ -55,6 +55,11 @@ static const int kCpuHasLOONGARCH = 0x2000000;
static const int kCpuHasLSX = 0x4000000;
static const int kCpuHasLASX = 0x8000000;
// These flags are only valid on RISCV processors.
static const int kCpuHasRISCV = 0x10000000;
static const int kCpuHasRVV = 0x20000000;
static const int kCpuHasRVVZVFH = 0x40000000;
// Optional init function. TestCpuFlag does an auto-init.
// Returns cpu_info flags.
LIBYUV_API
@ -78,6 +83,8 @@ LIBYUV_API
int ArmCpuCaps(const char* cpuinfo_name);
LIBYUV_API
int MipsCpuCaps(const char* cpuinfo_name);
LIBYUV_API
int RiscvCpuCaps(const char* cpuinfo_name);
// For testing, allow CPU flags to be disabled.
// ie MaskCpuFlags(~kCpuHasSSSE3) to disable SSSE3.

View File

@ -191,6 +191,63 @@ LIBYUV_API SAFEBUFFERS int MipsCpuCaps(const char* cpuinfo_name) {
return flag;
}
LIBYUV_API SAFEBUFFERS int RiscvCpuCaps(const char* cpuinfo_name) {
char cpuinfo_line[512];
int flag = 0x0;
FILE* f = fopen(cpuinfo_name, "r");
if (!f) {
// Assume nothing if /proc/cpuinfo is unavailable.
// This will occur for Chrome sandbox for Pepper or Render process.
return 0;
}
while (fgets(cpuinfo_line, sizeof(cpuinfo_line) - 1, f)) {
if (memcmp(cpuinfo_line, "isa", 3) == 0) {
// ISA string must begin with rv64{i,e,g} for a 64-bit processor.
char* isa = strstr(cpuinfo_line, "rv64");
if (isa) {
const int isa_len = strlen(isa);
// 5 ISA characters + 1 new-line character
if (isa_len < 6) {
fclose(f);
return 0;
}
// Skip {i,e,g} canonical checking.
// Skip rvxxx
isa += 5;
// Find the very first occurrence of 's', 'x' or 'z'.
// To detect multi-letter standard, non-standard, and
// supervisor-level extensions.
int otherExts_len = 0;
char* otherExts = strpbrk(isa, "zxs");
if (otherExts) {
otherExts_len = strlen(otherExts);
// Multi-letter extensions are seperated by a single underscore
// as described in RISC-V User-Level ISA V2.2.
char* ext = strtok(otherExts, "_");
while (ext) {
// Search for the ZVFH (Vector FP16) extension.
// The ZVFH implied the (Scalar FP16)ZFH extension.
if (!strcmp(ext, "zvfh") || !strcmp(ext, "zvfh\n")) {
flag |= kCpuHasRVVZVFH;
}
ext = strtok(NULL, "_");
}
}
const int std_isa_len = isa_len - otherExts_len - 5 - 1;
// Detect the v in the standard single-letter extensions.
// Skip optional Zve* and Zvl* extensions detection at otherExts.
if (memchr(isa, 'v', std_isa_len)) {
// The RVV implied the F extension.
flag |= kCpuHasRVV;
}
}
}
}
fclose(f);
return flag;
}
// TODO(fbarchard): Consider read_loongarch_ir().
#define LOONGARCH_CFG2 0x2
#define LOONGARCH_CFG2_LSX (1 << 6)
@ -277,6 +334,10 @@ static SAFEBUFFERS int GetCpuFlags(void) {
#endif
cpu_info |= kCpuHasARM;
#endif // __arm__
#if defined(__riscv) && defined(__linux__)
cpu_info = RiscvCpuCaps("/proc/cpuinfo");
cpu_info |= kCpuHasRISCV;
#endif // __riscv
cpu_info |= kCpuInitialized;
return cpu_info;
}

View File

@ -26,6 +26,14 @@ TEST_F(LibYUVBaseTest, TestCpuHas) {
printf("Has ARM %d\n", has_arm);
int has_neon = TestCpuFlag(kCpuHasNEON);
printf("Has NEON %d\n", has_neon);
#endif
#if defined(__riscv) && defined(__linux__)
int has_riscv = TestCpuFlag(kCpuHasRISCV);
printf("Has RISCV %d\n", has_riscv);
int has_rvv = TestCpuFlag(kCpuHasRVV);
printf("Has RVV %d\n", has_rvv);
int has_rvvzvfh = TestCpuFlag(kCpuHasRVVZVFH);
printf("Has RVVZVFH %d\n", has_rvvzvfh);
#endif
int has_x86 = TestCpuFlag(kCpuHasX86);
int has_sse2 = TestCpuFlag(kCpuHasSSE2);
@ -164,6 +172,9 @@ TEST_F(LibYUVBaseTest, TestCompilerMacros) {
#ifdef _WIN32
printf("_WIN32 %d\n", _WIN32);
#endif
#ifdef __riscv
printf("__riscv %d\n", __riscv);
#endif
#ifdef GG_LONGLONG
printf("GG_LONGLONG %d\n", GG_LONGLONG);
#endif
@ -264,6 +275,32 @@ TEST_F(LibYUVBaseTest, TestLinuxMipsMsa) {
}
}
TEST_F(LibYUVBaseTest, TestLinuxRVV) {
if (FileExists("../../unit_test/testdata/riscv64.txt")) {
printf("Note: testing to load \"../../unit_test/testdata/riscv64.txt\"\n");
EXPECT_EQ(0, RiscvCpuCaps("../../unit_test/testdata/riscv64.txt"));
EXPECT_EQ(kCpuHasRVV,
RiscvCpuCaps("../../unit_test/testdata/riscv64_rvv.txt"));
EXPECT_EQ(kCpuHasRVV | kCpuHasRVVZVFH,
RiscvCpuCaps("../../unit_test/testdata/riscv64_rvv_zvfh.txt"));
} else {
printf(
"WARNING: unable to load "
"\"../../unit_test/testdata/riscv64.txt\"\n");
}
#if defined(__linux__) && defined(__riscv)
if (FileExists("/proc/cpuinfo")) {
if (!(kCpuHasRVV & RiscvCpuCaps("/proc/cpuinfo"))) {
// This can happen on RVV emulator but /proc/cpuinfo is from host.
printf("WARNING: RVV build enabled but CPU does not have RVV\n");
}
} else {
printf("WARNING: unable to load \"/proc/cpuinfo\"\n");
}
#endif
}
// TODO(fbarchard): Fix clangcl test of cpuflags.
#ifdef _MSC_VER
TEST_F(LibYUVBaseTest, DISABLED_TestSetCpuFlags) {

4
unit_test/testdata/riscv64.txt vendored Normal file
View File

@ -0,0 +1,4 @@
processor : 0
hart : 1
isa : rv64imac
mmu : sv48

4
unit_test/testdata/riscv64_rvv.txt vendored Normal file
View File

@ -0,0 +1,4 @@
processor : 0
hart : 1
isa : rv64imafdcv
mmu : sv48

View File

@ -0,0 +1,4 @@
processor : 0
hart : 1
isa : rv64imafdcv_zfh_zvfh
mmu : sv48

View File

@ -88,6 +88,11 @@ int TestCpuEnv(int cpu_info) {
cpu_info &= ~libyuv::kCpuHasLASX;
}
#endif
#if defined(__riscv) && defined(__linux__)
if (TestEnv("LIBYUV_DISABLE_RVV")) {
cpu_info &= ~libyuv::kCpuHasRVV;
}
#endif
#if !defined(__pnacl__) && !defined(__CLR_VER) && \
(defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || \
defined(_M_IX86))