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