From 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d Mon Sep 17 00:00:00 2001 From: Jef Date: Tue, 24 Sep 2024 14:54:57 +0200 Subject: Initial community commit --- .../openmpt-trunk/misc/mptCPU.cpp | 258 +++++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 Src/external_dependencies/openmpt-trunk/misc/mptCPU.cpp (limited to 'Src/external_dependencies/openmpt-trunk/misc/mptCPU.cpp') diff --git a/Src/external_dependencies/openmpt-trunk/misc/mptCPU.cpp b/Src/external_dependencies/openmpt-trunk/misc/mptCPU.cpp new file mode 100644 index 00000000..56b7bd63 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/misc/mptCPU.cpp @@ -0,0 +1,258 @@ +/* + * mptCPU.cpp + * ---------- + * Purpose: CPU feature detection. + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#include "stdafx.h" +#include "mptCPU.h" + +#include "../common/mptStringBuffer.h" + +#if defined(MPT_ENABLE_ARCH_INTRINSICS) +#if MPT_COMPILER_MSVC && (defined(MPT_ENABLE_ARCH_X86) || defined(MPT_ENABLE_ARCH_AMD64)) +#include +#endif // MPT_COMPILER_MSVC && (MPT_ENABLE_ARCH_X86 || MPT_ENABLE_ARCH_AMD64) +#endif // MPT_ENABLE_ARCH_INTRINSICS + + +OPENMPT_NAMESPACE_BEGIN + + +namespace CPU +{ + + +#if defined(MPT_ENABLE_ARCH_INTRINSICS) + + +uint32 EnabledFeatures = 0; + + +#if MPT_COMPILER_MSVC && (defined(MPT_ENABLE_ARCH_X86) || defined(MPT_ENABLE_ARCH_AMD64)) + + +typedef char cpuid_result_string[12]; + + +struct cpuid_result { + uint32 a; + uint32 b; + uint32 c; + uint32 d; + std::string as_string() const + { + cpuid_result_string result; + result[0+0] = (b >> 0) & 0xff; + result[0+1] = (b >> 8) & 0xff; + result[0+2] = (b >>16) & 0xff; + result[0+3] = (b >>24) & 0xff; + result[4+0] = (d >> 0) & 0xff; + result[4+1] = (d >> 8) & 0xff; + result[4+2] = (d >>16) & 0xff; + result[4+3] = (d >>24) & 0xff; + result[8+0] = (c >> 0) & 0xff; + result[8+1] = (c >> 8) & 0xff; + result[8+2] = (c >>16) & 0xff; + result[8+3] = (c >>24) & 0xff; + return std::string(result, result + 12); + } + std::string as_string4() const + { + std::string result; + result.push_back(static_cast((a >> 0) & 0xff)); + result.push_back(static_cast((a >> 8) & 0xff)); + result.push_back(static_cast((a >> 16) & 0xff)); + result.push_back(static_cast((a >> 24) & 0xff)); + result.push_back(static_cast((b >> 0) & 0xff)); + result.push_back(static_cast((b >> 8) & 0xff)); + result.push_back(static_cast((b >> 16) & 0xff)); + result.push_back(static_cast((b >> 24) & 0xff)); + result.push_back(static_cast((c >> 0) & 0xff)); + result.push_back(static_cast((c >> 8) & 0xff)); + result.push_back(static_cast((c >> 16) & 0xff)); + result.push_back(static_cast((c >> 24) & 0xff)); + result.push_back(static_cast((d >> 0) & 0xff)); + result.push_back(static_cast((d >> 8) & 0xff)); + result.push_back(static_cast((d >> 16) & 0xff)); + result.push_back(static_cast((d >> 24) & 0xff)); + return result; + } +}; + + +static cpuid_result cpuid(uint32 function) +{ + cpuid_result result; + int CPUInfo[4]; + __cpuid(CPUInfo, function); + result.a = CPUInfo[0]; + result.b = CPUInfo[1]; + result.c = CPUInfo[2]; + result.d = CPUInfo[3]; + return result; +} + + +static cpuid_result cpuidex(uint32 function_a, uint32 function_c) +{ + cpuid_result result; + int CPUInfo[4]; + __cpuidex(CPUInfo, function_a, function_c); + result.a = CPUInfo[0]; + result.b = CPUInfo[1]; + result.c = CPUInfo[2]; + result.d = CPUInfo[3]; + return result; +} + + +Info::Info() +{ + + cpuid_result VendorString = cpuid(0x00000000u); + mpt::String::WriteAutoBuf(VendorID) = VendorString.as_string(); + if(VendorString.a >= 0x00000001u) + { + cpuid_result StandardFeatureFlags = cpuid(0x00000001u); + CPUID = StandardFeatureFlags.a; + uint32 BaseStepping = (StandardFeatureFlags.a >> 0) & 0x0f; + uint32 BaseModel = (StandardFeatureFlags.a >> 4) & 0x0f; + uint32 BaseFamily = (StandardFeatureFlags.a >> 8) & 0x0f; + uint32 ExtModel = (StandardFeatureFlags.a >> 16) & 0x0f; + uint32 ExtFamily = (StandardFeatureFlags.a >> 20) & 0xff; + if(BaseFamily == 0xf) + { + Family = static_cast(ExtFamily + BaseFamily); + } else + { + Family = static_cast(BaseFamily); + } + if((BaseFamily == 0x6) || (BaseFamily == 0xf)) + { + Model = static_cast((ExtModel << 4) | (BaseModel << 0)); + } else + { + Model = static_cast(BaseModel); + } + Stepping = static_cast(BaseStepping); + if(StandardFeatureFlags.d & (1<<23)) AvailableFeatures |= feature::mmx; + if(StandardFeatureFlags.d & (1<<25)) AvailableFeatures |= feature::sse; + if(StandardFeatureFlags.d & (1<<26)) AvailableFeatures |= feature::sse2; + if(StandardFeatureFlags.c & (1<< 0)) AvailableFeatures |= feature::sse3; + if(StandardFeatureFlags.c & (1<< 9)) AvailableFeatures |= feature::ssse3; + if(StandardFeatureFlags.c & (1<<19)) AvailableFeatures |= feature::sse4_1; + if(StandardFeatureFlags.c & (1<<20)) AvailableFeatures |= feature::sse4_2; + if(StandardFeatureFlags.c & (1<<28)) AvailableFeatures |= feature::avx; + } + if(VendorString.a >= 0x00000007u) + { + cpuid_result ExtendedFeatures = cpuidex(0x00000007u, 0x00000000u); + if(ExtendedFeatures.b & (1<< 5)) AvailableFeatures |= feature::avx2; + } + + cpuid_result ExtendedVendorString = cpuid(0x80000000u); + if(ExtendedVendorString.a >= 0x80000001u) + { + cpuid_result ExtendedFeatureFlags = cpuid(0x80000001u); + if(ExtendedFeatureFlags.d & (1<<29)) AvailableFeatures |= feature::lm; + } + if(ExtendedVendorString.a >= 0x80000004u) + { + mpt::String::WriteAutoBuf(BrandID) = cpuid(0x80000002u).as_string4() + cpuid(0x80000003u).as_string4() + cpuid(0x80000004u).as_string4(); + } + +} + + +#elif MPT_COMPILER_MSVC && (defined(MPT_ENABLE_ARCH_X86) || defined(MPT_ENABLE_ARCH_AMD64)) + + +Info::Info() +{ + + if(IsProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE) != 0) AvailableFeatures |= feature::mmx; + if(IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE) != 0) AvailableFeatures |= feature::sse; + if(IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE) != 0) AvailableFeatures |= feature::sse2; + if(IsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE) != 0) AvailableFeatures |= feature::sse3; + +} + + +#else // !(MPT_COMPILER_MSVC && (MPT_ENABLE_ARCH_X86 || MPT_ENABLE_ARCH_AMD64)) + + +Info::Info() +{ + return; +} + + +#endif // MPT_COMPILER_MSVC && (MPT_ENABLE_ARCH_X86 || MPT_ENABLE_ARCH_AMD64) + + +const Info & Info::Get() +{ + static Info info; + return info; +} + + +struct InfoInitializer +{ + InfoInitializer() + { + Info::Get(); + } +}; + + +static InfoInitializer g_InfoInitializer; + + +void EnableAvailableFeatures() +{ + EnabledFeatures = Info::Get().AvailableFeatures; +} + + +#endif // MPT_ENABLE_ARCH_INTRINSICS + + +uint32 GetMinimumFeatures() +{ + uint32 flags = 0; + #ifdef MPT_ENABLE_ARCH_INTRINSICS + #if MPT_COMPILER_MSVC + #if defined(_M_X64) + flags |= feature::lm | feature::sse | feature::sse2; + #elif defined(_M_IX86) + #if defined(_M_IX86_FP) + #if (_M_IX86_FP >= 2) + flags |= feature::sse | feature::sse2; + #elif (_M_IX86_FP == 1) + flags |= feature::sse; + #endif + #endif + #endif + #if defined(__AVX__) + flags |= feature::avx; + #endif + #if defined(__AVX2__) + flags |= feature::avx2; + #endif + #endif + #endif // MPT_ENABLE_ARCH_INTRINSICS + return flags; +} + + + +} // namespace CPU + + +OPENMPT_NAMESPACE_END -- cgit