1 /*********************************************************************
2  * Copyright (C) 2005-2007 by Prakash Punnoor                        *
3  * prakash@punnoor.de                                                *
4  *                                                                   *
5  * This library is free software; you can redistribute it and/or     *
6  * modify it under the terms of the GNU Library General Public       *
7  * License as published by the Free Software Foundation;             *
8  * version 2 of the License                                          *
9  *                                                                   *
10  * This library is distributed in the hope that it will be useful,   *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of    *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU *
13  * Library General Public License for more details.                  *
14  *                                                                   *
15  * You should have received a copy of the GNU Library General Public *
16  * License along with this library; if not, write to the             *
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,      *
18  * Boston, MA  02110-1301, USA.                                      *
19  *********************************************************************/
20 #include <string.h>
21 #include <stdlib.h>
22 #include "x86_cpu_caps.h"
23 
24 /* caps1 */
25 #define MMX_BIT             23
26 #define SSE_BIT             25
27 #define SSE2_BIT            26
28 
29 /* caps2 */
30 #define SSE3_BIT             0
31 #define SSSE3_BIT            9
32 
33 /* caps3 */
34 #define AMD_3DNOW_BIT       31
35 #define AMD_3DNOWEXT_BIT    30
36 #define AMD_SSE_MMX_BIT     22
37 #define CYRIX_MMXEXT_BIT    24
38 
39 
40 #ifdef HAVE_CPU_CAPS_DETECTION
41 #include "asm_support.h"
42 
43 // derived from loki_cpuinfo.c, 1997-98 by H. Dietz and R. Fisher
44 // using infos from sandpile.org
cpu_caps_detect_x86(uint32_t * caps1,uint32_t * caps2,uint32_t * caps3)45 static void cpu_caps_detect_x86(uint32_t *caps1, uint32_t *caps2, uint32_t *caps3)
46 {
47     uint32_t c1, c2, c3;
48 
49 #if __GNUC__
50 #define param1      %0
51 #define param2      %1
52 #define param3      %2
53 
54     asm volatile (
55 #else
56 #define param1 c1
57 #define param2 c2
58 #define param3 c3
59 
60   __asm {
61 #endif
62         _mov(_b, _s)
63 
64         // standard CPUID
65         _mov(_(0x1), _eax)
66         _cpuid
67         _mov(_edx, param1) //caps1 - MMX, SSE, SSE2
68         _mov(_ecx, param2) //caps2 - SSE3
69 
70         // extended CPUID
71         _mov(_(0x80000001), _eax)
72         _cpuid
73         _mov(_edx, param3) //caps3 - 3DNOW!, 3DNOW!EXT, CYRIX-MMXEXT, AMD-MMX-SSE
74 
75         _mov(_s, _b)
76 #if __GNUC__
77         :"=m"(c1), "=m"(c2), "=m"(c3)   /* output */
78         :                               /* input */
79         :"%eax", "%ecx", "%edx", "%esi" /* clobbered registers */
80     );
81 #else
82  }
83 #endif
84 
85     *caps1 = c1;
86     *caps2 = c2;
87     *caps3 = c3;
88 }
89 #endif
90 
91 static struct x86cpu_caps_s x86cpu_caps_compile = { 0, 0, 0, 0, 0, 0, 0, 0, 0};
92 static struct x86cpu_caps_s x86cpu_caps_detect = { 1, 1, 1, 1, 1, 1, 1, 1, 1};
93 struct x86cpu_caps_s x86cpu_caps_use = { 0, 0, 0, 0, 0, 0, 0, 0, 0};
94 
cpu_caps_detect(void)95 void cpu_caps_detect(void)
96 {
97     /* compiled in SIMD routines */
98 #ifdef HAVE_MMX
99     x86cpu_caps_compile.mmx = 1;
100 #endif
101 #ifdef HAVE_SSE
102     x86cpu_caps_compile.sse = 1;
103 #endif
104 #ifdef HAVE_SSE2
105     x86cpu_caps_compile.sse2 = 1;
106 #endif
107 #ifdef HAVE_SSE3
108     x86cpu_caps_compile.sse3 = 1;
109 #endif
110 #ifdef HAVE_SSSE3
111     x86cpu_caps_compile.ssse3 = 1;
112 #endif
113 #ifdef HAVE_3DNOW
114     x86cpu_caps_compile.amd_3dnow = 1;
115 #endif
116 #ifdef HAVE_SSE_MMX
117     x86cpu_caps_compile.amd_sse_mmx = 1;
118 #endif
119 #ifdef HAVE_3DNOWEXT
120     x86cpu_caps_compile.amd_3dnowext = 1;
121 #endif
122     /* end compiled in SIMD routines */
123 
124     /* runtime detection */
125 #ifdef HAVE_CPU_CAPS_DETECTION
126     {
127         uint32_t caps1, caps2, caps3;
128 
129         cpu_caps_detect_x86(&caps1, &caps2, &caps3);
130 
131         x86cpu_caps_detect.mmx          = (caps1 >> MMX_BIT) & 1;
132         x86cpu_caps_detect.sse          = (caps1 >> SSE_BIT) & 1;
133         x86cpu_caps_detect.sse2         = (caps1 >> SSE2_BIT) & 1;
134 
135         x86cpu_caps_detect.sse3         = (caps2 >> SSE3_BIT) & 1;
136         x86cpu_caps_detect.ssse3         = (caps2 >> SSSE3_BIT) & 1;
137 
138         x86cpu_caps_detect.amd_3dnow    = (caps3 >> AMD_3DNOW_BIT) & 1;
139         x86cpu_caps_detect.amd_3dnowext = (caps3 >> AMD_3DNOWEXT_BIT) & 1;
140         x86cpu_caps_detect.amd_sse_mmx  = (caps3 >> AMD_SSE_MMX_BIT) & 1;
141         /* FIXME: For Cyrix MMXEXT detect Cyrix CPU first! */
142         /*
143         x86cpu_caps.cyrix_mmxext = (caps3 >> CYRIX_MMXEXT_BIT) & 1;
144         */
145     }
146 #endif /*HAVE_CPU_CAPS_DETECTION*/
147     /* end runtime detection */
148 
149     x86cpu_caps_use.mmx          = x86cpu_caps_detect.mmx          & x86cpu_caps_compile.mmx;
150     x86cpu_caps_use.sse          = x86cpu_caps_detect.sse          & x86cpu_caps_compile.sse;
151     x86cpu_caps_use.sse2         = x86cpu_caps_detect.sse2         & x86cpu_caps_compile.sse2;
152     x86cpu_caps_use.sse3         = x86cpu_caps_detect.sse3         & x86cpu_caps_compile.sse3;
153     x86cpu_caps_use.ssse3        = x86cpu_caps_detect.ssse3        & x86cpu_caps_compile.ssse3;
154     x86cpu_caps_use.amd_3dnow    = x86cpu_caps_detect.amd_3dnow    & x86cpu_caps_compile.amd_3dnow;
155     x86cpu_caps_use.amd_3dnowext = x86cpu_caps_detect.amd_3dnowext & x86cpu_caps_compile.amd_3dnowext;
156     x86cpu_caps_use.amd_sse_mmx  = x86cpu_caps_detect.amd_sse_mmx  & x86cpu_caps_compile.amd_sse_mmx;
157 }
158 
apply_simd_restrictions(AftenSimdInstructions * simd_instructions)159 void apply_simd_restrictions(AftenSimdInstructions *simd_instructions)
160 {
161     x86cpu_caps_use.mmx          &= simd_instructions->mmx;
162     x86cpu_caps_use.sse          &= simd_instructions->sse;
163     x86cpu_caps_use.sse2         &= simd_instructions->sse2;
164     x86cpu_caps_use.sse3         &= simd_instructions->sse3;
165     x86cpu_caps_use.ssse3        &= simd_instructions->ssse3;
166     x86cpu_caps_use.amd_3dnow    &= simd_instructions->amd_3dnow;
167     x86cpu_caps_use.amd_3dnowext &= simd_instructions->amd_3dnowext;
168     x86cpu_caps_use.amd_sse_mmx  &= simd_instructions->amd_sse_mmx;
169 }
170