/* * Copyright (c) 2010 The WebM project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef VPX_PORTS_X86_H #define VPX_PORTS_X86_H #include <stdlib.h> #include "config.h" typedef enum { VPX_CPU_UNKNOWN = -1, VPX_CPU_AMD, VPX_CPU_AMD_OLD, VPX_CPU_CENTAUR, VPX_CPU_CYRIX, VPX_CPU_INTEL, VPX_CPU_NEXGEN, VPX_CPU_NSC, VPX_CPU_RISE, VPX_CPU_SIS, VPX_CPU_TRANSMETA, VPX_CPU_TRANSMETA_OLD, VPX_CPU_UMC, VPX_CPU_VIA, VPX_CPU_LAST } vpx_cpu_t; #if defined(__GNUC__) && __GNUC__ #if ARCH_X86_64 #define cpuid(func,ax,bx,cx,dx)\ __asm__ __volatile__ (\ "cpuid \n\t" \ : "=a" (ax), "=b" (bx), "=c" (cx), "=d" (dx) \ : "a" (func)); #else #define cpuid(func,ax,bx,cx,dx)\ __asm__ __volatile__ (\ "mov %%ebx, %%edi \n\t" \ "cpuid \n\t" \ "xchg %%edi, %%ebx \n\t" \ : "=a" (ax), "=D" (bx), "=c" (cx), "=d" (dx) \ : "a" (func)); #endif #else #if ARCH_X86_64 void __cpuid(int CPUInfo[4], int info_type); #pragma intrinsic(__cpuid) #define cpuid(func,a,b,c,d) do{\ int regs[4];\ __cpuid(regs,func); a=regs[0]; b=regs[1]; c=regs[2]; d=regs[3];\ } while(0) #else #define cpuid(func,a,b,c,d)\ __asm mov eax, func\ __asm cpuid\ __asm mov a, eax\ __asm mov b, ebx\ __asm mov c, ecx\ __asm mov d, edx #endif #endif #define HAS_MMX 0x01 #define HAS_SSE 0x02 #define HAS_SSE2 0x04 #define HAS_SSE3 0x08 #define HAS_SSSE3 0x10 #define HAS_SSE4_1 0x20 #ifndef BIT #define BIT(n) (1<<n) #endif static int x86_simd_caps(void) { unsigned int flags = 0; unsigned int mask = ~0; unsigned int reg_eax, reg_ebx, reg_ecx, reg_edx; char *env; (void)reg_ebx; /* See if the CPU capabilities are being overridden by the environment */ env = getenv("VPX_SIMD_CAPS"); if (env && *env) return (int)strtol(env, NULL, 0); env = getenv("VPX_SIMD_CAPS_MASK"); if (env && *env) mask = strtol(env, NULL, 0); /* Ensure that the CPUID instruction supports extended features */ cpuid(0, reg_eax, reg_ebx, reg_ecx, reg_edx); if (reg_eax < 1) return 0; /* Get the standard feature flags */ cpuid(1, reg_eax, reg_ebx, reg_ecx, reg_edx); if (reg_edx & BIT(23)) flags |= HAS_MMX; if (reg_edx & BIT(25)) flags |= HAS_SSE; /* aka xmm */ if (reg_edx & BIT(26)) flags |= HAS_SSE2; /* aka wmt */ if (reg_ecx & BIT(0)) flags |= HAS_SSE3; if (reg_ecx & BIT(9)) flags |= HAS_SSSE3; if (reg_ecx & BIT(19)) flags |= HAS_SSE4_1; return flags & mask; } vpx_cpu_t vpx_x86_vendor(void); #if ARCH_X86_64 && defined(_MSC_VER) unsigned __int64 __rdtsc(void); #pragma intrinsic(__rdtsc) #endif static unsigned int x86_readtsc(void) { #if defined(__GNUC__) && __GNUC__ unsigned int tsc; __asm__ __volatile__("rdtsc\n\t":"=a"(tsc):); return tsc; #else #if ARCH_X86_64 return __rdtsc(); #else __asm rdtsc; #endif #endif } #if defined(__GNUC__) && __GNUC__ #define x86_pause_hint()\ __asm__ __volatile__ ("pause \n\t") #else #if ARCH_X86_64 /* No pause intrinsic for windows x64 */ #define x86_pause_hint() #else #define x86_pause_hint()\ __asm pause #endif #endif #if defined(__GNUC__) && __GNUC__ static void x87_set_control_word(unsigned short mode) { __asm__ __volatile__("fldcw %0" : : "m"(*&mode)); } static unsigned short x87_get_control_word(void) { unsigned short mode; __asm__ __volatile__("fstcw %0\n\t":"=m"(*&mode):); return mode; } #elif ARCH_X86_64 /* No fldcw intrinsics on Windows x64, punt to external asm */ extern void vpx_winx64_fldcw(unsigned short mode); extern unsigned short vpx_winx64_fstcw(void); #define x87_set_control_word vpx_winx64_fldcw #define x87_get_control_word vpx_winx64_fstcw #else static void x87_set_control_word(unsigned short mode) { __asm { fldcw mode } } static unsigned short x87_get_control_word(void) { unsigned short mode; __asm { fstcw mode } return mode; } #endif static unsigned short x87_set_double_precision(void) { unsigned short mode = x87_get_control_word(); x87_set_control_word((mode&~0x300) | 0x200); return mode; } extern void vpx_reset_mmx_state(void); #endif