1 /********************************************************************
3 * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
8 * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
9 * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
11 ********************************************************************
13 CPU capability detection for x86 processors.
14 Originally written by Rudolf Marek.
17 last mod: $Id: cpu.c 16503 2009-08-22 18:14:02Z giles $
19 ********************************************************************/
23 #if !defined(OC_X86_ASM)
24 static ogg_uint32_t oc_cpu_flags_get(void){
28 # if !defined(_MSC_VER)
29 # if defined(__amd64__)||defined(__x86_64__)
30 /*On x86-64, gcc seems to be able to figure out how to save %rbx for us when
31 compiling with -fPIC.*/
32 # define cpuid(_op,_eax,_ebx,_ecx,_edx) \
33 __asm__ __volatile__( \
35 :[eax]"=a"(_eax),[ebx]"=b"(_ebx),[ecx]"=c"(_ecx),[edx]"=d"(_edx) \
40 /*On x86-32, not so much.*/
41 # define cpuid(_op,_eax,_ebx,_ecx,_edx) \
42 __asm__ __volatile__( \
43 "xchgl %%ebx,%[ebx]\n\t" \
45 "xchgl %%ebx,%[ebx]\n\t" \
46 :[eax]"=a"(_eax),[ebx]"=r"(_ebx),[ecx]"=c"(_ecx),[edx]"=d"(_edx) \
52 /*Why does MSVC need this complicated rigamarole?
53 At this point I honestly do not care.*/
55 /*Visual C cpuid helper function.
56 For VS2005 we could as well use the _cpuid builtin, but that wouldn't work
57 for VS2003 users, so we do it in inline assembler.*/
58 static void oc_cpuid_helper(ogg_uint32_t _cpu_info[4],ogg_uint32_t _op){
70 # define cpuid(_op,_eax,_ebx,_ecx,_edx) \
72 ogg_uint32_t cpu_info[4]; \
73 oc_cpuid_helper(cpu_info,_op); \
80 static void oc_detect_cpuid_helper(ogg_uint32_t *_eax,ogg_uint32_t *_ebx){
100 static ogg_uint32_t oc_parse_intel_flags(ogg_uint32_t _edx,ogg_uint32_t _ecx){
102 /*If there isn't even MMX, give up.*/
103 if(!(_edx&0x00800000))return 0;
104 flags=OC_CPU_X86_MMX;
105 if(_edx&0x02000000)flags|=OC_CPU_X86_MMXEXT|OC_CPU_X86_SSE;
106 if(_edx&0x04000000)flags|=OC_CPU_X86_SSE2;
107 if(_ecx&0x00000001)flags|=OC_CPU_X86_PNI;
108 if(_ecx&0x00000100)flags|=OC_CPU_X86_SSSE3;
109 if(_ecx&0x00080000)flags|=OC_CPU_X86_SSE4_1;
110 if(_ecx&0x00100000)flags|=OC_CPU_X86_SSE4_2;
114 static ogg_uint32_t oc_parse_amd_flags(ogg_uint32_t _edx,ogg_uint32_t _ecx){
116 /*If there isn't even MMX, give up.*/
117 if(!(_edx&0x00800000))return 0;
118 flags=OC_CPU_X86_MMX;
119 if(_edx&0x00400000)flags|=OC_CPU_X86_MMXEXT;
120 if(_edx&0x80000000)flags|=OC_CPU_X86_3DNOW;
121 if(_edx&0x40000000)flags|=OC_CPU_X86_3DNOWEXT;
122 if(_ecx&0x00000040)flags|=OC_CPU_X86_SSE4A;
123 if(_ecx&0x00000800)flags|=OC_CPU_X86_SSE5;
127 static ogg_uint32_t oc_cpu_flags_get(void){
133 # if !defined(__amd64__)&&!defined(__x86_64__)
134 /*Not all x86-32 chips support cpuid, so we have to check.*/
135 # if !defined(_MSC_VER)
136 __asm__ __volatile__(
141 "xorl $0x200000,%[a]\n\t"
147 :[a]"=r"(eax),[b]"=r"(ebx)
152 oc_detect_cpuid_helper(&eax,&ebx);
155 if(eax==ebx)return 0;
157 cpuid(0,eax,ebx,ecx,edx);
158 /* l e t n I e n i u n e G*/
159 if(ecx==0x6C65746E&&edx==0x49656E69&&ebx==0x756E6547||
160 /* 6 8 x M T e n i u n e G*/
161 ecx==0x3638784D&&edx==0x54656E69&&ebx==0x756E6547){
162 /*Intel, Transmeta (tested with Crusoe TM5800):*/
163 cpuid(1,eax,ebx,ecx,edx);
164 flags=oc_parse_intel_flags(edx,ecx);
166 /* D M A c i t n e h t u A*/
167 else if(ecx==0x444D4163&&edx==0x69746E65&&ebx==0x68747541||
168 /* C S N y b e d o e G*/
169 ecx==0x43534e20&&edx==0x79622065&&ebx==0x646f6547){
171 cpuid(0x80000000,eax,ebx,ecx,edx);
172 if(eax<0x80000001)flags=0;
174 cpuid(0x80000001,eax,ebx,ecx,edx);
175 flags=oc_parse_amd_flags(edx,ecx);
177 /*Also check for SSE.*/
178 cpuid(1,eax,ebx,ecx,edx);
179 flags|=oc_parse_intel_flags(edx,ecx);
181 /*Technically some VIA chips can be configured in the BIOS to return any
182 string here the user wants.
183 There is a special detection method that can be used to identify such
184 processors, but in my opinion, if the user really wants to change it, they
185 deserve what they get.*/
186 /* s l u a H r u a t n e C*/
187 else if(ecx==0x736C7561&&edx==0x48727561&&ebx==0x746E6543){
189 /*I only have documentation for the C7 (Esther) and Isaiah (forthcoming)
190 chips (thanks to the engineers from Centaur Technology who provided it).
191 These chips support Intel-like cpuid info.
192 The C3-2 (Nehemiah) cores appear to, as well.*/
193 cpuid(1,eax,ebx,ecx,edx);
194 flags=oc_parse_intel_flags(edx,ecx);
196 /*The (non-Nehemiah) C3 processors support AMD-like cpuid info.
197 We need to check this even if the Intel test succeeds to pick up 3DNow!
198 support on these processors.
199 Unlike actual AMD processors, we cannot _rely_ on this info, since
200 some cores (e.g., the 693 stepping of the Nehemiah) claim to support
201 this function, yet return edx=0, despite the Intel test indicating
203 Therefore the features detected here are strictly added to those
204 detected by the Intel test.*/
205 /*TODO: How about earlier chips?*/
206 cpuid(0x80000001,eax,ebx,ecx,edx);
207 /*Note: As of the C7, this function returns Intel-style extended feature
208 flags, not AMD-style.
209 Currently, this only defines bits 11, 20, and 29 (0x20100800), which
210 do not conflict with any of the AMD flags we inspect.
211 For the remaining bits, Intel tells us, "Do not count on their value",
212 but VIA assures us that they will all be zero (at least on the C7 and
214 In the (unlikely) event a future processor uses bits 18, 19, 30, or 31
215 (0xC0C00000) for something else, we will have to add code to detect
216 the model to decide when it is appropriate to inspect them.*/
217 flags|=oc_parse_amd_flags(edx,ecx);