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