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
17typedef 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
74void __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
103static int
104x86_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
150vpx_cpu_t vpx_x86_vendor(void);
151
152#if ARCH_X86_64 && defined(_MSC_VER)
153unsigned __int64 __rdtsc(void);
154#pragma intrinsic(__rdtsc)
155#endif
156static unsigned int
157x86_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__
193static void
194x87_set_control_word(unsigned short mode) {
195  __asm__ __volatile__("fldcw %0" : : "m"(*&mode));
196}
197static unsigned short
198x87_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)
204static void
205x87_set_control_word(unsigned short mode) {
206  asm volatile("fldcw %0" : : "m"(*&mode));
207}
208static unsigned short
209x87_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 */
216extern void           vpx_winx64_fldcw(unsigned short mode);
217extern 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
221static void
222x87_set_control_word(unsigned short mode) {
223  __asm { fldcw mode }
224}
225static unsigned short
226x87_get_control_word(void) {
227  unsigned short mode;
228  __asm { fstcw mode }
229  return mode;
230}
231#endif
232
233static unsigned short
234x87_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
241extern void vpx_reset_mmx_state(void);
242#endif
243
244