Coverage Report

Created: 2024-09-06 07:53

/src/theora/lib/x86/x86cpu.c
Line
Count
Source (jump to first uncovered line)
1
/********************************************************************
2
 *                                                                  *
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.       *
7
 *                                                                  *
8
 * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009                *
9
 * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
10
 *                                                                  *
11
 ********************************************************************
12
13
 CPU capability detection for x86 processors.
14
  Originally written by Rudolf Marek.
15
16
 function:
17
  last mod: $Id$
18
19
 ********************************************************************/
20
21
#include "x86cpu.h"
22
23
#if !defined(OC_X86_ASM)
24
ogg_uint32_t oc_cpu_flags_get(void){
25
  return 0;
26
}
27
#else
28
# if defined(__amd64__)||defined(__x86_64__)
29
/*On x86-64, gcc seems to be able to figure out how to save %rbx for us when
30
   compiling with -fPIC.*/
31
#  define cpuid(_op,_eax,_ebx,_ecx,_edx) \
32
6.89k
  __asm__ __volatile__( \
33
6.89k
   "cpuid\n\t" \
34
6.89k
   :[eax]"=a"(_eax),[ebx]"=b"(_ebx),[ecx]"=c"(_ecx),[edx]"=d"(_edx) \
35
6.89k
   :"a"(_op) \
36
6.89k
   :"cc" \
37
6.89k
  )
38
# else
39
/*On x86-32, not so much.*/
40
#  define cpuid(_op,_eax,_ebx,_ecx,_edx) \
41
  __asm__ __volatile__( \
42
   "xchgl %%ebx,%[ebx]\n\t" \
43
   "cpuid\n\t" \
44
   "xchgl %%ebx,%[ebx]\n\t" \
45
   :[eax]"=a"(_eax),[ebx]"=r"(_ebx),[ecx]"=c"(_ecx),[edx]"=d"(_edx) \
46
   :"a"(_op) \
47
   :"cc" \
48
  )
49
# endif
50
51
3.44k
static ogg_uint32_t oc_parse_intel_flags(ogg_uint32_t _edx,ogg_uint32_t _ecx){
52
3.44k
  ogg_uint32_t flags;
53
  /*If there isn't even MMX, give up.*/
54
3.44k
  if(!(_edx&0x00800000))return 0;
55
3.44k
  flags=OC_CPU_X86_MMX;
56
3.44k
  if(_edx&0x02000000)flags|=OC_CPU_X86_MMXEXT|OC_CPU_X86_SSE;
57
3.44k
  if(_edx&0x04000000)flags|=OC_CPU_X86_SSE2;
58
3.44k
  if(_ecx&0x00000001)flags|=OC_CPU_X86_PNI;
59
3.44k
  if(_ecx&0x00000100)flags|=OC_CPU_X86_SSSE3;
60
3.44k
  if(_ecx&0x00080000)flags|=OC_CPU_X86_SSE4_1;
61
3.44k
  if(_ecx&0x00100000)flags|=OC_CPU_X86_SSE4_2;
62
3.44k
  return flags;
63
3.44k
}
64
65
0
static ogg_uint32_t oc_parse_amd_flags(ogg_uint32_t _edx,ogg_uint32_t _ecx){
66
0
  ogg_uint32_t flags;
67
  /*If there isn't even MMX, give up.*/
68
0
  if(!(_edx&0x00800000))return 0;
69
0
  flags=OC_CPU_X86_MMX;
70
0
  if(_edx&0x00400000)flags|=OC_CPU_X86_MMXEXT;
71
0
  if(_edx&0x80000000)flags|=OC_CPU_X86_3DNOW;
72
0
  if(_edx&0x40000000)flags|=OC_CPU_X86_3DNOWEXT;
73
0
  if(_ecx&0x00000040)flags|=OC_CPU_X86_SSE4A;
74
0
  if(_ecx&0x00000800)flags|=OC_CPU_X86_SSE5;
75
0
  return flags;
76
0
}
77
78
3.44k
ogg_uint32_t oc_cpu_flags_get(void){
79
3.44k
  ogg_uint32_t flags;
80
3.44k
  ogg_uint32_t eax;
81
3.44k
  ogg_uint32_t ebx;
82
3.44k
  ogg_uint32_t ecx;
83
3.44k
  ogg_uint32_t edx;
84
# if !defined(__amd64__)&&!defined(__x86_64__)
85
  /*Not all x86-32 chips support cpuid, so we have to check.*/
86
  __asm__ __volatile__(
87
   "pushfl\n\t"
88
   "pushfl\n\t"
89
   "popl %[a]\n\t"
90
   "movl %[a],%[b]\n\t"
91
   "xorl $0x200000,%[a]\n\t"
92
   "pushl %[a]\n\t"
93
   "popfl\n\t"
94
   "pushfl\n\t"
95
   "popl %[a]\n\t"
96
   "popfl\n\t"
97
   :[a]"=r"(eax),[b]"=r"(ebx)
98
   :
99
   :"cc"
100
  );
101
  /*No cpuid.*/
102
  if(eax==ebx)return 0;
103
# endif
104
3.44k
  cpuid(0,eax,ebx,ecx,edx);
105
  /*         l e t n          I e n i          u n e G*/
106
3.44k
  if(ecx==0x6C65746E&&edx==0x49656E69&&ebx==0x756E6547||
107
   /*      6 8 x M          T e n i          u n e G*/
108
3.44k
   ecx==0x3638784D&&edx==0x54656E69&&ebx==0x756E6547){
109
3.44k
    int family;
110
3.44k
    int model;
111
    /*Intel, Transmeta (tested with Crusoe TM5800):*/
112
3.44k
    cpuid(1,eax,ebx,ecx,edx);
113
3.44k
    flags=oc_parse_intel_flags(edx,ecx);
114
3.44k
    family=(eax>>8)&0xF;
115
3.44k
    model=(eax>>4)&0xF;
116
    /*The SSE unit on the Pentium M and Core Duo is much slower than the MMX
117
       unit, so don't use it.*/
118
3.44k
    if(family==6&&(model==9||model==13||model==14)){
119
0
      flags&=~(OC_CPU_X86_SSE2|OC_CPU_X86_PNI);
120
0
    }
121
3.44k
  }
122
  /*              D M A c          i t n e          h t u A*/
123
0
  else if(ecx==0x444D4163&&edx==0x69746E65&&ebx==0x68747541||
124
   /*      C S N            y b   e          d o e G*/
125
0
   ecx==0x43534e20&&edx==0x79622065&&ebx==0x646f6547){
126
    /*AMD, Geode:*/
127
0
    cpuid(0x80000000,eax,ebx,ecx,edx);
128
0
    if(eax<0x80000001)flags=0;
129
0
    else{
130
0
      cpuid(0x80000001,eax,ebx,ecx,edx);
131
0
      flags=oc_parse_amd_flags(edx,ecx);
132
0
    }
133
    /*Also check for SSE.*/
134
0
    cpuid(1,eax,ebx,ecx,edx);
135
0
    flags|=oc_parse_intel_flags(edx,ecx);
136
0
  }
137
  /*Technically some VIA chips can be configured in the BIOS to return any
138
     string here the user wants.
139
    There is a special detection method that can be used to identify such
140
     processors, but in my opinion, if the user really wants to change it, they
141
     deserve what they get.*/
142
  /*              s l u a          H r u a          t n e C*/
143
0
  else if(ecx==0x736C7561&&edx==0x48727561&&ebx==0x746E6543){
144
    /*VIA:*/
145
    /*I only have documentation for the C7 (Esther) and Isaiah (forthcoming)
146
       chips (thanks to the engineers from Centaur Technology who provided it).
147
      These chips support Intel-like cpuid info.
148
      The C3-2 (Nehemiah) cores appear to, as well.*/
149
0
    cpuid(1,eax,ebx,ecx,edx);
150
0
    flags=oc_parse_intel_flags(edx,ecx);
151
0
    if(eax>=0x80000001){
152
      /*The (non-Nehemiah) C3 processors support AMD-like cpuid info.
153
        We need to check this even if the Intel test succeeds to pick up 3DNow!
154
         support on these processors.
155
        Unlike actual AMD processors, we cannot _rely_ on this info, since
156
         some cores (e.g., the 693 stepping of the Nehemiah) claim to support
157
         this function, yet return edx=0, despite the Intel test indicating
158
         MMX support.
159
        Therefore the features detected here are strictly added to those
160
         detected by the Intel test.*/
161
      /*TODO: How about earlier chips?*/
162
0
      cpuid(0x80000001,eax,ebx,ecx,edx);
163
      /*Note: As of the C7, this function returns Intel-style extended feature
164
         flags, not AMD-style.
165
        Currently, this only defines bits 11, 20, and 29 (0x20100800), which
166
         do not conflict with any of the AMD flags we inspect.
167
        For the remaining bits, Intel tells us, "Do not count on their value",
168
         but VIA assures us that they will all be zero (at least on the C7 and
169
         Isaiah chips).
170
        In the (unlikely) event a future processor uses bits 18, 19, 30, or 31
171
         (0xC0C00000) for something else, we will have to add code to detect
172
         the model to decide when it is appropriate to inspect them.*/
173
0
      flags|=oc_parse_amd_flags(edx,ecx);
174
0
    }
175
0
  }
176
0
  else{
177
    /*Implement me.*/
178
0
    flags=0;
179
0
  }
180
3.44k
  return flags;
181
3.44k
}
182
#endif