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