summaryrefslogtreecommitdiffstats
path: root/ml/dlib/dlib/simd/simd_check.h
blob: c4ca0c3b86f0521c8b580aac404b24657bfbdff8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SIMd_CHECK_Hh_
#define DLIB_SIMd_CHECK_Hh_

#include <array>
#include <iostream>

//#define DLIB_DO_NOT_USE_SIMD

// figure out which SIMD instructions we can use.
#ifndef DLIB_DO_NOT_USE_SIMD
    #if defined(_MSC_VER) 
        #ifdef __AVX__
            #ifndef DLIB_HAVE_SSE2
                #define DLIB_HAVE_SSE2
            #endif 
            #ifndef DLIB_HAVE_SSE3
                #define DLIB_HAVE_SSE3
            #endif
            #ifndef DLIB_HAVE_SSE41
                #define DLIB_HAVE_SSE41
            #endif
            #ifndef DLIB_HAVE_AVX
                #define DLIB_HAVE_AVX
            #endif
        #endif
        #if (defined( _M_X64) || defined(_M_IX86_FP) && _M_IX86_FP >= 2) && !defined(DLIB_HAVE_SSE2)
            #define DLIB_HAVE_SSE2
        #endif
    #else
        #ifdef __SSE2__
            #ifndef DLIB_HAVE_SSE2
                #define DLIB_HAVE_SSE2
            #endif 
        #endif
        #ifdef __SSSE3__
            #ifndef DLIB_HAVE_SSE3
                #define DLIB_HAVE_SSE3
            #endif
        #endif
        #ifdef __SSE4_1__
            #ifndef DLIB_HAVE_SSE41
                #define DLIB_HAVE_SSE41
            #endif
        #endif
        #ifdef __AVX__
            #ifndef DLIB_HAVE_AVX
                #define DLIB_HAVE_AVX
            #endif
        #endif
        #ifdef __AVX2__
            #ifndef DLIB_HAVE_AVX2
                #define DLIB_HAVE_AVX2
            #endif
        #endif
        #ifdef __ALTIVEC__
            #ifndef DLIB_HAVE_ALTIVEC
                #define DLIB_HAVE_ALTIVEC
            #endif
        #endif
        #ifdef __VSX__
            #ifndef DLIB_HAVE_VSX
                #define DLIB_HAVE_VSX
            #endif
        #endif
        #ifdef __VEC__ // __VEC__ = 10206
            #ifndef DLIB_HAVE_POWER_VEC	// vector and vec_ intrinsics
                #define DLIB_HAVE_POWER_VEC
            #endif
        #endif
        #ifdef __ARM_NEON
            #ifndef DLIB_HAVE_NEON
                #define DLIB_HAVE_NEON
            #endif
        #endif
    #endif
#endif

 
// ----------------------------------------------------------------------------------------


#ifdef DLIB_HAVE_ALTIVEC
#include <altivec.h>
#endif

#ifdef DLIB_HAVE_SSE2
    #include <xmmintrin.h>
    #include <emmintrin.h>
    #include <mmintrin.h>
#endif
#ifdef DLIB_HAVE_SSE3
    #include <pmmintrin.h> // SSE3
    #include <tmmintrin.h>
#endif
#ifdef DLIB_HAVE_SSE41
    #include <smmintrin.h> // SSE4
#endif
#ifdef DLIB_HAVE_AVX
    #include <immintrin.h> // AVX
#endif
#ifdef DLIB_HAVE_AVX2
    #include <immintrin.h> // AVX
//    #include <avx2intrin.h>
#endif
#ifdef DLIB_HAVE_NEON
    #include <arm_neon.h> // ARM NEON
#endif

// ----------------------------------------------------------------------------------------
// Define functions to check, at runtime, what instructions are available

#if defined(_MSC_VER) && (defined(_M_I86) || defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) )
    #include <intrin.h>

    inline std::array<unsigned int,4> cpuid(int function_id) 
    { 
        std::array<unsigned int,4> info;
        // Load EAX, EBX, ECX, EDX into info
        __cpuid((int*)info.data(), function_id);
        return info;
    }

#elif (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__i686__) || defined(__amd64__) || defined(__x86_64__))
    #include <cpuid.h>

    inline std::array<unsigned int,4> cpuid(int function_id) 
    { 
        std::array<unsigned int,4> info;
        // Load EAX, EBX, ECX, EDX into info
        __cpuid(function_id, info[0], info[1], info[2], info[3]);
        return info;
    }

#else

    inline std::array<unsigned int,4> cpuid(int) 
    {
        return std::array<unsigned int,4>{};
    }

#endif

    inline bool cpu_has_sse2_instructions()   { return 0!=(cpuid(1)[3]&(1<<26)); }
    inline bool cpu_has_sse3_instructions()   { return 0!=(cpuid(1)[2]&(1<<0));  }
    inline bool cpu_has_sse41_instructions()  { return 0!=(cpuid(1)[2]&(1<<19)); }
    inline bool cpu_has_sse42_instructions()  { return 0!=(cpuid(1)[2]&(1<<20)); }
    inline bool cpu_has_avx_instructions()    { return 0!=(cpuid(1)[2]&(1<<28)); }
    inline bool cpu_has_avx2_instructions()   { return 0!=(cpuid(7)[1]&(1<<5));  }
    inline bool cpu_has_avx512_instructions() { return 0!=(cpuid(7)[1]&(1<<16)); }

    inline void warn_about_unavailable_but_used_cpu_instructions()
    {
#if defined(DLIB_HAVE_AVX2)
        if (!cpu_has_avx2_instructions())
            std::cerr << "Dlib was compiled to use AVX2 instructions, but these aren't available on your machine." << std::endl;
#elif defined(DLIB_HAVE_AVX)
        if (!cpu_has_avx_instructions())
            std::cerr << "Dlib was compiled to use AVX instructions, but these aren't available on your machine." << std::endl;
#elif defined(DLIB_HAVE_SSE41)
        if (!cpu_has_sse41_instructions())
            std::cerr << "Dlib was compiled to use SSE41 instructions, but these aren't available on your machine." << std::endl;
#elif defined(DLIB_HAVE_SSE3)
        if (!cpu_has_sse3_instructions())
            std::cerr << "Dlib was compiled to use SSE3 instructions, but these aren't available on your machine." << std::endl;
#elif defined(DLIB_HAVE_SSE2)
        if (!cpu_has_sse2_instructions())
            std::cerr << "Dlib was compiled to use SSE2 instructions, but these aren't available on your machine." << std::endl;
#endif
    }

// ----------------------------------------------------------------------------------------

#endif // DLIB_SIMd_CHECK_Hh_