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 #define HAS_AVX     0x40
     98 #define HAS_AVX2    0x80
     99 #ifndef BIT
    100 #define BIT(n) (1<<n)
    101 #endif
    102 
    103 static int
    104 x86_simd_caps(void) {
    105   unsigned int flags = 0;
    106   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   env = getenv("VPX_SIMD_CAPS");
    113 
    114   if (env && *env)
    115     return (int)strtol(env, NULL, 0);
    116 
    117   env = getenv("VPX_SIMD_CAPS_MASK");
    118 
    119   if (env && *env)
    120     mask = strtol(env, NULL, 0);
    121 
    122   /* Ensure that the CPUID instruction supports extended features */
    123   cpuid(0, reg_eax, reg_ebx, reg_ecx, reg_edx);
    124 
    125   if (reg_eax < 1)
    126     return 0;
    127 
    128   /* Get the standard feature flags */
    129   cpuid(1, reg_eax, reg_ebx, reg_ecx, reg_edx);
    130 
    131   if (reg_edx & BIT(23)) flags |= HAS_MMX;
    132 
    133   if (reg_edx & BIT(25)) flags |= HAS_SSE; /* aka xmm */
    134 
    135   if (reg_edx & BIT(26)) flags |= HAS_SSE2; /* aka wmt */
    136 
    137   if (reg_ecx & BIT(0)) flags |= HAS_SSE3;
    138 
    139   if (reg_ecx & BIT(9)) flags |= HAS_SSSE3;
    140 
    141   if (reg_ecx & BIT(19)) flags |= HAS_SSE4_1;
    142 
    143   if (reg_ecx & BIT(28)) flags |= HAS_AVX;
    144 
    145   if (reg_ebx & BIT(5)) flags |= HAS_AVX2;
    146 
    147   return flags & mask;
    148 }
    149 
    150 vpx_cpu_t vpx_x86_vendor(void);
    151 
    152 #if ARCH_X86_64 && defined(_MSC_VER)
    153 unsigned __int64 __rdtsc(void);
    154 #pragma intrinsic(__rdtsc)
    155 #endif
    156 static unsigned int
    157 x86_readtsc(void) {
    158 #if defined(__GNUC__) && __GNUC__
    159   unsigned int tsc;
    160   __asm__ __volatile__("rdtsc\n\t":"=a"(tsc):);
    161   return tsc;
    162 #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
    163   unsigned int tsc;
    164   asm volatile("rdtsc\n\t":"=a"(tsc):);
    165   return tsc;
    166 #else
    167 #if ARCH_X86_64
    168   return (unsigned int)__rdtsc();
    169 #else
    170   __asm  rdtsc;
    171 #endif
    172 #endif
    173 }
    174 
    175 
    176 #if defined(__GNUC__) && __GNUC__
    177 #define x86_pause_hint()\
    178   __asm__ __volatile__ ("pause \n\t")
    179 #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
    180 #define x86_pause_hint()\
    181   asm volatile ("pause \n\t")
    182 #else
    183 #if ARCH_X86_64
    184 #define x86_pause_hint()\
    185   _mm_pause();
    186 #else
    187 #define x86_pause_hint()\
    188   __asm pause
    189 #endif
    190 #endif
    191 
    192 #if defined(__GNUC__) && __GNUC__
    193 static void
    194 x87_set_control_word(unsigned short mode) {
    195   __asm__ __volatile__("fldcw %0" : : "m"(*&mode));
    196 }
    197 static unsigned short
    198 x87_get_control_word(void) {
    199   unsigned short mode;
    200   __asm__ __volatile__("fstcw %0\n\t":"=m"(*&mode):);
    201     return mode;
    202 }
    203 #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
    204 static void
    205 x87_set_control_word(unsigned short mode) {
    206   asm volatile("fldcw %0" : : "m"(*&mode));
    207 }
    208 static unsigned short
    209 x87_get_control_word(void) {
    210   unsigned short mode;
    211   asm volatile("fstcw %0\n\t":"=m"(*&mode):);
    212   return mode;
    213 }
    214 #elif ARCH_X86_64
    215 /* No fldcw intrinsics on Windows x64, punt to external asm */
    216 extern void           vpx_winx64_fldcw(unsigned short mode);
    217 extern unsigned short vpx_winx64_fstcw(void);
    218 #define x87_set_control_word vpx_winx64_fldcw
    219 #define x87_get_control_word vpx_winx64_fstcw
    220 #else
    221 static void
    222 x87_set_control_word(unsigned short mode) {
    223   __asm { fldcw mode }
    224 }
    225 static unsigned short
    226 x87_get_control_word(void) {
    227   unsigned short mode;
    228   __asm { fstcw mode }
    229   return mode;
    230 }
    231 #endif
    232 
    233 static unsigned short
    234 x87_set_double_precision(void) {
    235   unsigned short mode = x87_get_control_word();
    236   x87_set_control_word((mode&~0x300) | 0x200);
    237   return mode;
    238 }
    239 
    240 
    241 extern void vpx_reset_mmx_state(void);
    242 #endif
    243 
    244