1 : /*
2 : * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
3 : *
4 : * Use of this source code is governed by a BSD-style license
5 : * that can be found in the LICENSE file in the root of the source
6 : * tree. An additional intellectual property rights grant can be found
7 : * in the file PATENTS. All contributing project authors may
8 : * be found in the AUTHORS file in the root of the source tree.
9 : */
10 :
11 :
12 : #ifndef VPX_PORTS_X86_H
13 : #define VPX_PORTS_X86_H
14 : #include <stdlib.h>
15 : #include "config.h"
16 :
17 : typedef enum
18 : {
19 : VPX_CPU_UNKNOWN = -1,
20 : VPX_CPU_AMD,
21 : VPX_CPU_AMD_OLD,
22 : VPX_CPU_CENTAUR,
23 : VPX_CPU_CYRIX,
24 : VPX_CPU_INTEL,
25 : VPX_CPU_NEXGEN,
26 : VPX_CPU_NSC,
27 : VPX_CPU_RISE,
28 : VPX_CPU_SIS,
29 : VPX_CPU_TRANSMETA,
30 : VPX_CPU_TRANSMETA_OLD,
31 : VPX_CPU_UMC,
32 : VPX_CPU_VIA,
33 :
34 : VPX_CPU_LAST
35 : } vpx_cpu_t;
36 :
37 : #if defined(__GNUC__) && __GNUC__
38 : #if ARCH_X86_64
39 : #define cpuid(func,ax,bx,cx,dx)\
40 : __asm__ __volatile__ (\
41 : "cpuid \n\t" \
42 : : "=a" (ax), "=b" (bx), "=c" (cx), "=d" (dx) \
43 : : "a" (func));
44 : #else
45 : #define cpuid(func,ax,bx,cx,dx)\
46 : __asm__ __volatile__ (\
47 : "mov %%ebx, %%edi \n\t" \
48 : "cpuid \n\t" \
49 : "xchg %%edi, %%ebx \n\t" \
50 : : "=a" (ax), "=D" (bx), "=c" (cx), "=d" (dx) \
51 : : "a" (func));
52 : #endif
53 : #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
54 : #if ARCH_X86_64
55 : #define cpuid(func,ax,bx,cx,dx)\
56 : asm volatile (\
57 : "xchg %rsi, %rbx \n\t" \
58 : "cpuid \n\t" \
59 : "movl %ebx, %edi \n\t" \
60 : "xchg %rsi, %rbx \n\t" \
61 : : "=a" (ax), "=D" (bx), "=c" (cx), "=d" (dx) \
62 : : "a" (func));
63 : #else
64 : #define cpuid(func,ax,bx,cx,dx)\
65 : asm volatile (\
66 : "pushl %ebx \n\t" \
67 : "cpuid \n\t" \
68 : "movl %ebx, %edi \n\t" \
69 : "popl %ebx \n\t" \
70 : : "=a" (ax), "=D" (bx), "=c" (cx), "=d" (dx) \
71 : : "a" (func));
72 : #endif
73 : #else
74 : #if ARCH_X86_64
75 : void __cpuid(int CPUInfo[4], int info_type);
76 : #pragma intrinsic(__cpuid)
77 : #define cpuid(func,a,b,c,d) do{\
78 : int regs[4];\
79 : __cpuid(regs,func); a=regs[0]; b=regs[1]; c=regs[2]; d=regs[3];\
80 : } while(0)
81 : #else
82 : #define cpuid(func,a,b,c,d)\
83 : __asm mov eax, func\
84 : __asm cpuid\
85 : __asm mov a, eax\
86 : __asm mov b, ebx\
87 : __asm mov c, ecx\
88 : __asm mov d, edx
89 : #endif
90 : #endif
91 :
92 : #define HAS_MMX 0x01
93 : #define HAS_SSE 0x02
94 : #define HAS_SSE2 0x04
95 : #define HAS_SSE3 0x08
96 : #define HAS_SSSE3 0x10
97 : #define HAS_SSE4_1 0x20
98 : #ifndef BIT
99 : #define BIT(n) (1<<n)
100 : #endif
101 :
102 : static int
103 0 : x86_simd_caps(void)
104 : {
105 0 : unsigned int flags = 0;
106 0 : unsigned int mask = ~0;
107 : unsigned int reg_eax, reg_ebx, reg_ecx, reg_edx;
108 : char *env;
109 : (void)reg_ebx;
110 :
111 : /* See if the CPU capabilities are being overridden by the environment */
112 0 : env = getenv("VPX_SIMD_CAPS");
113 :
114 0 : if (env && *env)
115 0 : return (int)strtol(env, NULL, 0);
116 :
117 0 : env = getenv("VPX_SIMD_CAPS_MASK");
118 :
119 0 : if (env && *env)
120 0 : mask = strtol(env, NULL, 0);
121 :
122 : /* Ensure that the CPUID instruction supports extended features */
123 0 : cpuid(0, reg_eax, reg_ebx, reg_ecx, reg_edx);
124 :
125 0 : if (reg_eax < 1)
126 0 : return 0;
127 :
128 : /* Get the standard feature flags */
129 0 : cpuid(1, reg_eax, reg_ebx, reg_ecx, reg_edx);
130 :
131 0 : if (reg_edx & BIT(23)) flags |= HAS_MMX;
132 :
133 0 : if (reg_edx & BIT(25)) flags |= HAS_SSE; /* aka xmm */
134 :
135 0 : if (reg_edx & BIT(26)) flags |= HAS_SSE2; /* aka wmt */
136 :
137 0 : if (reg_ecx & BIT(0)) flags |= HAS_SSE3;
138 :
139 0 : if (reg_ecx & BIT(9)) flags |= HAS_SSSE3;
140 :
141 0 : if (reg_ecx & BIT(19)) flags |= HAS_SSE4_1;
142 :
143 0 : return flags & mask;
144 : }
145 :
146 : vpx_cpu_t vpx_x86_vendor(void);
147 :
148 : #if ARCH_X86_64 && defined(_MSC_VER)
149 : unsigned __int64 __rdtsc(void);
150 : #pragma intrinsic(__rdtsc)
151 : #endif
152 : static unsigned int
153 0 : x86_readtsc(void)
154 : {
155 : #if defined(__GNUC__) && __GNUC__
156 : unsigned int tsc;
157 0 : __asm__ __volatile__("rdtsc\n\t":"=a"(tsc):);
158 0 : return tsc;
159 : #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
160 : unsigned int tsc;
161 : asm volatile("rdtsc\n\t":"=a"(tsc):);
162 : return tsc;
163 : #else
164 : #if ARCH_X86_64
165 : return __rdtsc();
166 : #else
167 : __asm rdtsc;
168 : #endif
169 : #endif
170 : }
171 :
172 :
173 : #if defined(__GNUC__) && __GNUC__
174 : #define x86_pause_hint()\
175 : __asm__ __volatile__ ("pause \n\t")
176 : #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
177 : #define x86_pause_hint()\
178 : asm volatile ("pause \n\t")
179 : #else
180 : #if ARCH_X86_64
181 : #define x86_pause_hint()\
182 : _mm_pause();
183 : #else
184 : #define x86_pause_hint()\
185 : __asm pause
186 : #endif
187 : #endif
188 :
189 : #if defined(__GNUC__) && __GNUC__
190 : static void
191 0 : x87_set_control_word(unsigned short mode)
192 : {
193 0 : __asm__ __volatile__("fldcw %0" : : "m"(*&mode));
194 0 : }
195 : static unsigned short
196 0 : x87_get_control_word(void)
197 : {
198 : unsigned short mode;
199 0 : __asm__ __volatile__("fstcw %0\n\t":"=m"(*&mode):);
200 0 : return mode;
201 : }
202 : #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
203 : static void
204 : x87_set_control_word(unsigned short mode)
205 : {
206 : asm volatile("fldcw %0" : : "m"(*&mode));
207 : }
208 : static unsigned short
209 : x87_get_control_word(void)
210 : {
211 : unsigned short mode;
212 : asm volatile("fstcw %0\n\t":"=m"(*&mode):);
213 : return mode;
214 : }
215 : #elif ARCH_X86_64
216 : /* No fldcw intrinsics on Windows x64, punt to external asm */
217 : extern void vpx_winx64_fldcw(unsigned short mode);
218 : extern unsigned short vpx_winx64_fstcw(void);
219 : #define x87_set_control_word vpx_winx64_fldcw
220 : #define x87_get_control_word vpx_winx64_fstcw
221 : #else
222 : static void
223 : x87_set_control_word(unsigned short mode)
224 : {
225 : __asm { fldcw mode }
226 : }
227 : static unsigned short
228 : x87_get_control_word(void)
229 : {
230 : unsigned short mode;
231 : __asm { fstcw mode }
232 : return mode;
233 : }
234 : #endif
235 :
236 : static unsigned short
237 0 : x87_set_double_precision(void)
238 : {
239 0 : unsigned short mode = x87_get_control_word();
240 0 : x87_set_control_word((mode&~0x300) | 0x200);
241 0 : return mode;
242 : }
243 :
244 :
245 : extern void vpx_reset_mmx_state(void);
246 : #endif
247 :
|