From 390ac799e791127e9d12fe266860e315129998bb Mon Sep 17 00:00:00 2001 From: Daniel Date: Sat, 25 Nov 2017 17:25:19 +0100 Subject: [PATCH] Added CPUID check --- RakeDiagSearch/RakeDiagSearch/Generator.cpp | 2 - RakeDiagSearch/RakeDiagSearch/main.cpp | 102 ++++++++++++++++++-- 2 files changed, 95 insertions(+), 9 deletions(-) diff --git a/RakeDiagSearch/RakeDiagSearch/Generator.cpp b/RakeDiagSearch/RakeDiagSearch/Generator.cpp index 07c572a..38dec5e 100644 --- a/RakeDiagSearch/RakeDiagSearch/Generator.cpp +++ b/RakeDiagSearch/RakeDiagSearch/Generator.cpp @@ -460,8 +460,6 @@ inline void Generator::StartImpl() int cellValue; // New value for the cell int oldCellValue; // Old value from the cell - int stop = 0; // Flag of finishing the computing - // Create constant copies of used fields to speedup calculations const int cellsInPath = this->cellsInPath; const int keyValue = this->keyValue; diff --git a/RakeDiagSearch/RakeDiagSearch/main.cpp b/RakeDiagSearch/RakeDiagSearch/main.cpp index 9d8338e..a06f48d 100644 --- a/RakeDiagSearch/RakeDiagSearch/main.cpp +++ b/RakeDiagSearch/RakeDiagSearch/main.cpp @@ -1,10 +1,13 @@ -# include -# include -# include -# include -# include "boinc_api.h" - -# include "MovePairSearch.h" +#include +#include +#include +#include +#include "boinc_api.h" +#include "MovePairSearch.h" +#if defined(__i386__) || defined (__x86_64__) +#include +#include +#endif using namespace std; @@ -126,3 +129,88 @@ int main(int argumentsCount, char* argumentsValues[]) // will be shown). return 0; } + +// Do not check x86 CPU features if SSE2 is not required. Very old CPUs may not support CPUID. +// Code below uses C stdio because C++ iostreams are not initialized yet and app would crash. +// This function is called before main() starts. +#if (defined(__i386__) || defined (__x86_64__)) && defined(__SSE2__) +__attribute__((constructor(101), target("no-sse"))) +void CheckCpuid() +{ + unsigned int a, b, c, d; + + if (!__get_cpuid(1, &a, &b, &c, &d)) + { + fprintf(stderr, "CPUID instruction is not supported by your CPU!\n"); + exit(1); + } + + if (0 == (d & bit_SSE2)) + { + fprintf(stderr, "SSE2 instructions are not supported by your CPU!\n"); + exit(1); + } + +#ifdef __AVX__ + if (0 == (c & bit_AVX)) + { + fprintf(stderr, "AVX instructions are not supported by your CPU!\n"); + exit(1); + } + + // AVX also needs OS support, check for it + if (0 == (c & bit_OSXSAVE)) + { + fprintf(stderr, "OSXSAVE instructions are not supported by your CPU!\n"); + exit(1); + } + + unsigned int eax, edx; + unsigned int ecx = 0; // _XCR_XFEATURE_ENABLED_MASK + __asm__ ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (ecx)); + if (0x6 != (eax & 0x6)) // XSTATE_SSE | XSTATE_YMM + { + fprintf(stderr, "AVX instructions are not supported by your OS!\n"); + exit(1); + } +#endif + +#ifdef __AVX2__ + if (!__get_cpuid(7, &a, &b, &c, &d)) { + fprintf(stderr, "Extended CPUID 0x7 instruction is not supported by your CPU!\n"); + exit(1); + } + + if (0 == (b & bit_AVX2)) + { + fprintf(stderr, "AVX2 instructions are not supported by your CPU!\n"); + exit(1); + } +#endif + +#ifdef __AVX512F__ + // During comppilation following AVX512 instruction sets are enabled: F, CD, VL, BW, DQ + // Code directly uses F and VL. Compiler may emit instruction from other ones, so check them all + + // We need data loaded during AVX and AVX2 checks, make sure we have it +#if !defined(__AVX__) || !defined(__AVX2__) +#error AVX or AVX2 is not enabled! +#endif + + const unsigned int avx512bits = bit_AVX512F | bit_AVX512DQ | bit_AVX512CD | bit_AVX512BW | bit_AVX512VL; + + if (avx512bits != (b & avx512bits)) + { + fprintf(stderr, "AVX512 instructions are not supported by your CPU!\n"); + exit(1); + } + + // AVX512 also needs OS support, check for it + if (0xe6 != (eax & 0xe6)) // XSTATE_SSE | XSTATE_YMM | XSTATE_OPMASK | XSTATE_ZMM | XSTATE_HI_ZMM + { + fprintf(stderr, "AVX512 instructions are not supported by your OS!\n"); + exit(1); + } +#endif +} +#endif