123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- /*! \file CPUID.cpp
- Functions which probe the CPU to discover what SIMD functionality is present
- */
- /************************************************************************************************
- Copyright 2008 Gregory W Heckler
- This file is part of the GPS Software Defined Radio (GPS-SDR)
- The GPS-SDR is free software; you can redistribute it and/or modify it under the terms of the
- GNU General Public License as published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
- The GPS-SDR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
- even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- You should have received a copy of the GNU General Public License along with GPS-SDR; if not,
- write to the:
- Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- ************************************************************************************************/
- #include "includes.h"
- #include "defines.h"
- #include "simd.h"
- #include <cpuid.h>
- /* https://stackoverflow.com/questions/6121792/how-to-check-if-a-cpu-supports-the-sse3-instruction-set */
- void cpuid(int info[4], int InfoType){
- __cpuid_count(InfoType, 0, info[0], info[1], info[2], info[3]);
- }
- /* https://stackoverflow.com/questions/6121792/how-to-check-if-a-cpu-supports-the-sse3-instruction-set */
- bool CPU_CHECK_SIMD()
- {
- // Misc.
- bool HW_MMX;
- bool HW_x64;
- bool HW_ABM; // Advanced Bit Manipulation
- bool HW_RDRAND;
- bool HW_BMI1;
- bool HW_BMI2;
- bool HW_ADX;
- bool HW_PREFETCHWT1;
- // SIMD: 128-bit
- bool HW_SSE;
- bool HW_SSE2;
- bool HW_SSE3;
- bool HW_SSSE3;
- bool HW_SSE41;
- bool HW_SSE42;
- bool HW_SSE4a;
- bool HW_AES;
- bool HW_SHA;
- // SIMD: 256-bit
- bool HW_AVX;
- bool HW_XOP;
- bool HW_FMA3;
- bool HW_FMA4;
- bool HW_AVX2;
- // SIMD: 512-bit
- bool HW_AVX512F; // AVX512 Foundation
- bool HW_AVX512CD; // AVX512 Conflict Detection
- bool HW_AVX512PF; // AVX512 Prefetch
- bool HW_AVX512ER; // AVX512 Exponential + Reciprocal
- bool HW_AVX512VL; // AVX512 Vector Length Extensions
- bool HW_AVX512BW; // AVX512 Byte + Word
- bool HW_AVX512DQ; // AVX512 Doubleword + Quadword
- bool HW_AVX512IFMA; // AVX512 Integer 52-bit Fused Multiply-Add
- bool HW_AVX512VBMI; // AVX512 Vector Byte Manipulation Instructions
- int info[4];
- cpuid(info, 0);
- int nIds = info[0];
- cpuid(info, 0x80000000);
- unsigned nExIds = info[0];
- // Detect Features
- if (nIds >= 0x00000001){
- cpuid(info,0x00000001);
- HW_MMX = (info[3] & ((int)1 << 23)) != 0;
- HW_SSE = (info[3] & ((int)1 << 25)) != 0;
- HW_SSE2 = (info[3] & ((int)1 << 26)) != 0;
- HW_SSE3 = (info[2] & ((int)1 << 0)) != 0;
- HW_SSSE3 = (info[2] & ((int)1 << 9)) != 0;
- HW_SSE41 = (info[2] & ((int)1 << 19)) != 0;
- HW_SSE42 = (info[2] & ((int)1 << 20)) != 0;
- HW_AES = (info[2] & ((int)1 << 25)) != 0;
- HW_AVX = (info[2] & ((int)1 << 28)) != 0;
- HW_FMA3 = (info[2] & ((int)1 << 12)) != 0;
- HW_RDRAND = (info[2] & ((int)1 << 30)) != 0;
- }
- if (nIds >= 0x00000007){
- cpuid(info,0x00000007);
- HW_AVX2 = (info[1] & ((int)1 << 5)) != 0;
- HW_BMI1 = (info[1] & ((int)1 << 3)) != 0;
- HW_BMI2 = (info[1] & ((int)1 << 8)) != 0;
- HW_ADX = (info[1] & ((int)1 << 19)) != 0;
- HW_SHA = (info[1] & ((int)1 << 29)) != 0;
- HW_PREFETCHWT1 = (info[2] & ((int)1 << 0)) != 0;
- HW_AVX512F = (info[1] & ((int)1 << 16)) != 0;
- HW_AVX512CD = (info[1] & ((int)1 << 28)) != 0;
- HW_AVX512PF = (info[1] & ((int)1 << 26)) != 0;
- HW_AVX512ER = (info[1] & ((int)1 << 27)) != 0;
- HW_AVX512VL = (info[1] & ((int)1 << 31)) != 0;
- HW_AVX512BW = (info[1] & ((int)1 << 30)) != 0;
- HW_AVX512DQ = (info[1] & ((int)1 << 17)) != 0;
- HW_AVX512IFMA = (info[1] & ((int)1 << 21)) != 0;
- HW_AVX512VBMI = (info[2] & ((int)1 << 1)) != 0;
- }
- if (nExIds >= 0x80000001){
- cpuid(info,0x80000001);
- HW_x64 = (info[3] & ((int)1 << 29)) != 0;
- HW_ABM = (info[2] & ((int)1 << 5)) != 0;
- HW_SSE4a = (info[2] & ((int)1 << 6)) != 0;
- HW_FMA4 = (info[2] & ((int)1 << 16)) != 0;
- HW_XOP = (info[2] & ((int)1 << 11)) != 0;
- }
- }
- bool CPU_IS_SIMD_OPTION_ENABLED(enum CPU_SIMD_OPTIONS cpu_option)
- {
- bool HW_MMX = false;
- bool HW_SSE = false;
- bool HW_SSE2 = false;
- bool HW_SSE3 = false;
- bool HW_SSSE3 = false;
- bool HW_SSE41 = false;
- bool HW_SSE42 = false;
- int info[4];
- cpuid(info, 0);
- int nIds = info[0];
- // Detect Features
- if (nIds >= 0x00000001){
- cpuid(info,0x00000001);
- HW_MMX = (info[3] & ((int)1 << 23)) != 0;
- HW_SSE = (info[3] & ((int)1 << 25)) != 0;
- HW_SSE2 = (info[3] & ((int)1 << 26)) != 0;
- HW_SSE3 = (info[2] & ((int)1 << 0)) != 0;
- HW_SSSE3 = (info[2] & ((int)1 << 9)) != 0;
- HW_SSE41 = (info[2] & ((int)1 << 19)) != 0;
- HW_SSE42 = (info[2] & ((int)1 << 20)) != 0;
- }
- switch(cpu_option)
- {
- case CPU_MMX_EN:
- {
- return HW_MMX;
- break;
- }
- case CPU_SSE_EN:
- {
- return HW_SSE;
- break;
- }
- case CPU_SSE2_EN:
- {
- return HW_SSE2;
- break;
- }
- case CPU_SSE3_EN:
- {
- return HW_SSE3;
- break;
- }
- case CPU_SSSE3_EN:
- {
- return HW_SSSE3;
- break;
- }
- case CPU_SSE41_EN:
- {
- return HW_SSE41;
- break;
- }
- case CPU_SSE42_EN:
- {
- return HW_SSE42;
- break;
- }
- default:
- {
- return false;
- break;
- }
- }
- }
- // Default definitions of simd_xxx functions. In function Init_SIMD() they cen be changed if required.
- void (*simd_add)(int16 *A, int16 *B, int32 cnt) = &x86_add; //simd_add = &x86_add;
- void (*simd_sub)(int16 *A, int16 *B, int32 cnt) = &x86_sub; //simd_sub = &x86_sub;
- void (*simd_mul)(int16 *A, int16 *B, int32 cnt) = &x86_mul; //simd_mul = &x86_mul;
- int32 (*simd_dot)(int16 *A, int16 *B, int32 cnt) = &x86_dot; //simd_dot = &x86_dot;
- void (*simd_conj)(CPX *A, int32 cnt) = &x86_conj; //simd_conj = &x86_conj;
- void (*simd_cacc)(CPX *A, MIX *B, int32 cnt, int32 *iaccum, int32 *baccum) = &x86_cacc; //simd_cacc = &x86_cacc;
- void (*simd_cmul)(CPX *A, CPX *B, int32 cnt) = &x86_cmul; //simd_cmul = &x86_cmul;
- void (*simd_cmuls)(CPX *A, CPX *B, int32 cnt, int32 shift) = &x86_cmuls; //simd_cmuls = &x86_cmuls;
- void (*simd_cmulsc)(CPX *A, CPX *B, CPX *C, int32 cnt, int32 shift) = &x86_cmulsc; //simd_cmulsc = &x86_cmulsc;
- void (*simd_cmag)(CPX *A, int32 cnt) = &x86_cmag; //simd_cmag = &x86_cmag;
- void (*simd_prn_accum)(CPX *A, CPX *E, CPX *P, CPX *L, int32 cnt, CPX *accum) = &x86_prn_accum;
- void (*simd_prn_accum_new)(CPX *A, MIX *E, MIX *P, MIX *L, int32 cnt, CPX_ACCUM *accum) = &x86_prn_accum_new;
- void (*simd_max)(int32 *A, int32 *index, int32 *magt, int32 cnt) = &x86_max; //simd_max = &x86_max;
- void Init_SIMD()
- {
- if (CPU_IS_SIMD_OPTION_ENABLED(CPU_SSE3_EN))
- {
- void (*simd_add)(int16 *A, int16 *B, int32 cnt) = &sse_add; //simd_add = &sse_add;
- void (*simd_sub)(int16 *A, int16 *B, int32 cnt) = &sse_sub; //simd_sub = &sse_sub;
- void (*simd_mul)(int16 *A, int16 *B, int32 cnt) = &sse_mul; //simd_mul = &sse_mul;
- int32 (*simd_dot)(int16 *A, int16 *B, int32 cnt) = &sse_dot; //simd_dot = &sse_dot;
- void (*simd_conj)(CPX *A, int32 cnt) = &sse_conj; //simd_conj = &sse_conj;
- void (*simd_cacc)(CPX *A, MIX *B, int32 cnt, int32 *iaccum, int32 *baccum) = &sse_cacc; //simd_cacc = &sse_cacc;
- void (*simd_cmul)(CPX *A, CPX *B, int32 cnt) = &sse_cmul; //simd_cmul = &sse_cmul;
- void (*simd_cmuls)(CPX *A, CPX *B, int32 cnt, int32 shift) = &sse_cmuls; //simd_cmuls = &sse_cmuls;
- void (*simd_cmulsc)(CPX *A, CPX *B, CPX *C, int32 cnt, int32 shift) = &sse_cmulsc; //simd_cmulsc = &sse_cmulsc;
- }
- else
- {
- void (*simd_add)(int16 *A, int16 *B, int32 cnt) = &x86_add; //simd_add = &x86_add;
- void (*simd_sub)(int16 *A, int16 *B, int32 cnt) = &x86_sub; //simd_sub = &x86_sub;
- void (*simd_mul)(int16 *A, int16 *B, int32 cnt) = &x86_mul; //simd_mul = &x86_mul;
- int32 (*simd_dot)(int16 *A, int16 *B, int32 cnt) = &x86_dot; //simd_dot = &x86_dot;
- void (*simd_conj)(CPX *A, int32 cnt) = &x86_conj; //simd_conj = &x86_conj;
- void (*simd_cacc)(CPX *A, MIX *B, int32 cnt, int32 *iaccum, int32 *baccum) = &x86_cacc; //simd_cacc = &x86_cacc;
- void (*simd_cmul)(CPX *A, CPX *B, int32 cnt) = &x86_cmul; //simd_cmul = &x86_cmul;
- void (*simd_cmuls)(CPX *A, CPX *B, int32 cnt, int32 shift) = &x86_cmuls; //simd_cmuls = &x86_cmuls;
- void (*simd_cmulsc)(CPX *A, CPX *B, CPX *C, int32 cnt, int32 shift) = &x86_cmulsc; //simd_cmulsc = &x86_cmulsc;
- }
- void (*simd_cmag)(CPX *A, int32 cnt) = &x86_cmag; //simd_cmag = &x86_cmag;
- void (*simd_max)(int32 *A, int32 *index, int32 *magt, int32 cnt) = &x86_max; //simd_max = &x86_max;
- void (*simd_prn_accum_new)(CPX *A, MIX *E, MIX *P, MIX *L, int32 cnt, CPX_ACCUM *accum) = &x86_prn_accum_new;
- }
|