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 "config.h"
     16 
     17 #if defined(__GNUC__) && __GNUC__
     18 #if ARCH_X86_64
     19 #define cpuid(func,ax,bx,cx,dx)\
     20     __asm__ __volatile__ (\
     21                           "cpuid           \n\t" \
     22                           : "=a" (ax), "=b" (bx), "=c" (cx), "=d" (dx) \
     23                           : "a"  (func));
     24 #else
     25 #define cpuid(func,ax,bx,cx,dx)\
     26     __asm__ __volatile__ (\
     27                           "pushl %%ebx     \n\t" \
     28                           "cpuid           \n\t" \
     29                           "movl  %%ebx, %1 \n\t" \
     30                           "popl  %%ebx     \n\t" \
     31                           : "=a" (ax), "=r" (bx), "=c" (cx), "=d" (dx) \
     32                           : "a"  (func));
     33 #endif
     34 #else
     35 #if ARCH_X86_64
     36 void __cpuid(int CPUInfo[4], int info_type);
     37 #pragma intrinsic(__cpuid)
     38 #define cpuid(func,a,b,c,d) do{\
     39         int regs[4];\
     40         __cpuid(regs,func); a=regs[0];  b=regs[1];  c=regs[2];  d=regs[3];\
     41     } while(0)
     42 #else
     43 #define cpuid(func,a,b,c,d)\
     44     __asm mov eax, func\
     45     __asm cpuid\
     46     __asm mov a, eax\
     47     __asm mov b, ebx\
     48     __asm mov c, ecx\
     49     __asm mov d, edx
     50 #endif
     51 #endif
     52 
     53 #define HAS_MMX   0x01
     54 #define HAS_SSE   0x02
     55 #define HAS_SSE2  0x04
     56 #define HAS_SSE3  0x08
     57 #define HAS_SSSE3 0x10
     58 #ifndef BIT
     59 #define BIT(n) (1<<n)
     60 #endif
     61 
     62 static int
     63 x86_simd_caps(void)
     64 {
     65     unsigned int flags = 0;
     66     unsigned int mask = ~0;
     67     unsigned int reg_eax, reg_ebx, reg_ecx, reg_edx;
     68     char *env;
     69     (void)reg_ebx;
     70 
     71     /* See if the CPU capabilities are being overridden by the environment */
     72     env = getenv("VPX_SIMD_CAPS");
     73 
     74     if (env && *env)
     75         return (int)strtol(env, NULL, 0);
     76 
     77     env = getenv("VPX_SIMD_CAPS_MASK");
     78 
     79     if (env && *env)
     80         mask = strtol(env, NULL, 0);
     81 
     82     /* Ensure that the CPUID instruction supports extended features */
     83     cpuid(0, reg_eax, reg_ebx, reg_ecx, reg_edx);
     84 
     85     if (reg_eax < 1)
     86         return 0;
     87 
     88     /* Get the standard feature flags */
     89     cpuid(1, reg_eax, reg_ebx, reg_ecx, reg_edx);
     90 
     91     if (reg_edx & BIT(23)) flags |= HAS_MMX;
     92 
     93     if (reg_edx & BIT(25)) flags |= HAS_SSE; /* aka xmm */
     94 
     95     if (reg_edx & BIT(26)) flags |= HAS_SSE2; /* aka wmt */
     96 
     97     if (reg_ecx & BIT(0))  flags |= HAS_SSE3;
     98 
     99     if (reg_ecx & BIT(9))  flags |= HAS_SSSE3;
    100 
    101     return flags & mask;
    102 }
    103 
    104 
    105 #if ARCH_X86_64 && defined(_MSC_VER)
    106 unsigned __int64 __rdtsc(void);
    107 #pragma intrinsic(__rdtsc)
    108 #endif
    109 static unsigned int
    110 x86_readtsc(void)
    111 {
    112 #if defined(__GNUC__) && __GNUC__
    113     unsigned int tsc;
    114     __asm__ __volatile__("rdtsc\n\t":"=a"(tsc):);
    115     return tsc;
    116 #else
    117 #if ARCH_X86_64
    118     return __rdtsc();
    119 #else
    120     __asm  rdtsc;
    121 #endif
    122 #endif
    123 }
    124 
    125 
    126 #if defined(__GNUC__) && __GNUC__
    127 #define x86_pause_hint()\
    128     __asm__ __volatile__ ("pause \n\t")
    129 #else
    130 #if ARCH_X86_64
    131 /* No pause intrinsic for windows x64 */
    132 #define x86_pause_hint()
    133 #else
    134 #define x86_pause_hint()\
    135     __asm pause
    136 #endif
    137 #endif
    138 
    139 #if defined(__GNUC__) && __GNUC__
    140 static void
    141 x87_set_control_word(unsigned short mode)
    142 {
    143     __asm__ __volatile__("fldcw %0" : : "m"(*&mode));
    144 }
    145 static unsigned short
    146 x87_get_control_word(void)
    147 {
    148     unsigned short mode;
    149     __asm__ __volatile__("fstcw %0\n\t":"=m"(*&mode):);
    150     return mode;
    151 }
    152 #elif ARCH_X86_64
    153 /* No fldcw intrinsics on Windows x64, punt to external asm */
    154 extern void           vpx_winx64_fldcw(unsigned short mode);
    155 extern unsigned short vpx_winx64_fstcw(void);
    156 #define x87_set_control_word vpx_winx64_fldcw
    157 #define x87_get_control_word vpx_winx64_fstcw
    158 #else
    159 static void
    160 x87_set_control_word(unsigned short mode)
    161 {
    162     __asm { fldcw mode }
    163 }
    164 static unsigned short
    165 x87_get_control_word(void)
    166 {
    167     unsigned short mode;
    168     __asm { fstcw mode }
    169     return mode;
    170 }
    171 #endif
    172 
    173 static unsigned short
    174 x87_set_double_precision(void)
    175 {
    176     unsigned short mode = x87_get_control_word();
    177     x87_set_control_word((mode&~0x300) | 0x200);
    178     return mode;
    179 }
    180 
    181 
    182 extern void vpx_reset_mmx_state(void);
    183 #endif
    184 
    185