media/libtheora/lib/x86_vc/x86cpu.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial