Common: Add CPU feature detection for ARM64

This commit is contained in:
SachinVin 2022-04-04 23:43:39 +05:30
parent f1c2f63aa1
commit 0af8406e44
3 changed files with 149 additions and 0 deletions

View File

@ -125,6 +125,12 @@ if(ARCHITECTURE_x86_64)
x64/xbyak_abi.h
x64/xbyak_util.h
)
elseif(ARCHITECTURE_ARM64)
target_sources(common
PRIVATE
aarch64/cpu_detect.cpp
aarch64/cpu_detect.h
)
endif()
create_target_directory_groups(common)

View File

@ -0,0 +1,112 @@
// Copyright 2013 Dolphin Emulator Project / 2022 Citra Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <cstring>
#include <fstream>
#include <string>
#ifdef __APPLE__
// clang-format off
#include <sys/types.h>
#include <sys/sysctl.h>
// clang-format on
#elif !defined(_WIN32)
#ifndef __FreeBSD__
#include <asm/hwcap.h>
#endif // __FreeBSD__
#include <sys/auxv.h>
#include <unistd.h>
#endif // __APPLE__
#include "common/aarch64/cpu_detect.h"
#include "common/file_util.h"
namespace Common {
#ifdef __APPLE__
static std::string GetCPUString() {
char buf[128];
size_t buf_len = sizeof(buf);
if (sysctlbyname("machdep.cpu.brand_string", &buf, &buf_len, NULL, 0) == -1) {
return "Unknown";
}
return buf;
}
#elif !defined(WIN32)
static std::string GetCPUString() {
constexpr char procfile[] = "/proc/cpuinfo";
constexpr char marker[] = "Hardware\t: ";
std::string cpu_string = "Unknown";
std::string line;
std::ifstream file;
OpenFStream(file, procfile, std::ios_base::in);
if (!file)
return cpu_string;
while (std::getline(file, line)) {
if (line.find(marker) != std::string::npos) {
cpu_string = line.substr(strlen(marker));
break;
}
}
return cpu_string;
}
#endif // __APPLE__
// Detects the various CPU features
static CPUCaps Detect() {
CPUCaps caps;
// Set some defaults here
caps.fma = true;
caps.afp = false;
#ifdef __APPLE__
// M-series CPUs have all of these
caps.fp = true;
caps.asimd = true;
caps.aes = true;
caps.crc32 = true;
caps.sha1 = true;
caps.sha2 = true;
caps.cpu_string = GetCPUString();
#elif defined(_WIN32)
// Windows does not provide any mechanism for querying the system registers on ARMv8, unlike
// Linux which traps the register reads and emulates them in the kernel. There are environment
// variables containing some of the CPU-specific values, which we could use for a lookup table
// in the future. For now, assume all features are present as all known devices which are
// Windows-on-ARM compatible also support these extensions.
caps.fp = true;
caps.asimd = true;
caps.aes = true;
caps.crc32 = true;
caps.sha1 = true;
caps.sha2 = true;
#else
caps.cpu_string = GetCPUString();
#ifdef __FreeBSD__
u_long hwcaps = 0;
elf_aux_info(AT_HWCAP, &hwcaps, sizeof(u_long));
#else
unsigned long hwcaps = getauxval(AT_HWCAP);
#endif // __FreeBSD__
caps.fp = hwcaps & HWCAP_FP;
caps.asimd = hwcaps & HWCAP_ASIMD;
caps.aes = hwcaps & HWCAP_AES;
caps.crc32 = hwcaps & HWCAP_CRC32;
caps.sha1 = hwcaps & HWCAP_SHA1;
caps.sha2 = hwcaps & HWCAP_SHA2;
#endif // __APPLE__
return caps;
}
const CPUCaps& GetCPUCaps() {
static CPUCaps caps = Detect();
return caps;
}
} // namespace Common

View File

@ -0,0 +1,31 @@
// Copyright 2013 Dolphin Emulator Project / 2021 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <string>
namespace Common {
/// Arm64 CPU capabilities that may be detected by this module
struct CPUCaps {
std::string cpu_string;
bool aes;
bool afp; // Alternate floating-point behavior
bool asimd;
bool crc32;
bool fma;
bool fp;
bool sha1;
bool sha2;
};
/**
* Gets the supported capabilities of the host CPU
* @return Reference to a CPUCaps struct with the detected host CPU capabilities
*/
const CPUCaps& GetCPUCaps();
} // namespace Common