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