00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <stdlib.h>
00024 #include <string.h>
00025 #include "libavutil/x86/asm.h"
00026 #include "libavutil/cpu.h"
00027
00028 #if HAVE_INLINE_ASM
00029
00030 #define cpuid(index, eax, ebx, ecx, edx) \
00031 __asm__ volatile ( \
00032 "mov %%"REG_b", %%"REG_S" \n\t" \
00033 "cpuid \n\t" \
00034 "xchg %%"REG_b", %%"REG_S \
00035 : "=a" (eax), "=S" (ebx), "=c" (ecx), "=d" (edx) \
00036 : "0" (index))
00037 #elif HAVE_CPUID
00038 #include <intrin.h>
00039
00040 #define cpuid(index, eax, ebx, ecx, edx) \
00041 do { \
00042 int info[4]; \
00043 __cpuid(info, index); \
00044 eax = info[0]; \
00045 ebx = info[1]; \
00046 ecx = info[2]; \
00047 edx = info[3]; \
00048 } while (0)
00049 #endif
00050
00051 #if HAVE_INLINE_ASM
00052 #define xgetbv(index, eax, edx) \
00053 __asm__ (".byte 0x0f, 0x01, 0xd0" : "=a"(eax), "=d"(edx) : "c" (index))
00054 #elif HAVE_XGETBV
00055 #include <immintrin.h>
00056
00057 #define xgetbv(index, eax, edx) \
00058 do { \
00059 uint64_t res = __xgetbv(index); \
00060 eax = res; \
00061 edx = res >> 32; \
00062 } while (0)
00063 #endif
00064
00065 #if HAVE_INLINE_ASM
00066
00067 #define get_eflags(x) \
00068 __asm__ volatile ("pushfl \n" \
00069 "pop %0 \n" \
00070 : "=r"(x))
00071
00072 #define set_eflags(x) \
00073 __asm__ volatile ("push %0 \n" \
00074 "popfl \n" \
00075 :: "r"(x))
00076
00077 #elif HAVE_RWEFLAGS
00078
00079 #include <intrin.h>
00080
00081 #define get_eflags(x) \
00082 x = __readeflags()
00083
00084 #define set_eflags(x) \
00085 __writeeflags(x)
00086
00087 #endif
00088
00089
00090 int ff_get_cpu_flags_x86(void)
00091 {
00092 int rval = 0;
00093 int eax, ebx, ecx, edx;
00094 int max_std_level, max_ext_level, std_caps = 0, ext_caps = 0;
00095 int family = 0, model = 0;
00096 union { int i[3]; char c[12]; } vendor;
00097
00098 #if ARCH_X86_32
00099 x86_reg a, c;
00100
00101
00102
00103 get_eflags(a);
00104 set_eflags(a ^ 0x200000);
00105 get_eflags(c);
00106
00107 if (a == c)
00108 return 0;
00109 #endif
00110
00111 cpuid(0, max_std_level, ebx, ecx, edx);
00112 vendor.i[0] = ebx;
00113 vendor.i[1] = edx;
00114 vendor.i[2] = ecx;
00115
00116 if (max_std_level >= 1) {
00117 cpuid(1, eax, ebx, ecx, std_caps);
00118 family = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff);
00119 model = ((eax >> 4) & 0xf) + ((eax >> 12) & 0xf0);
00120 if (std_caps & (1 << 15))
00121 rval |= AV_CPU_FLAG_CMOV;
00122 if (std_caps & (1 << 23))
00123 rval |= AV_CPU_FLAG_MMX;
00124 if (std_caps & (1 << 25))
00125 rval |= AV_CPU_FLAG_MMXEXT;
00126 #if HAVE_SSE
00127 if (std_caps & (1 << 25))
00128 rval |= AV_CPU_FLAG_SSE;
00129 if (std_caps & (1 << 26))
00130 rval |= AV_CPU_FLAG_SSE2;
00131 if (ecx & 1)
00132 rval |= AV_CPU_FLAG_SSE3;
00133 if (ecx & 0x00000200 )
00134 rval |= AV_CPU_FLAG_SSSE3;
00135 if (ecx & 0x00080000 )
00136 rval |= AV_CPU_FLAG_SSE4;
00137 if (ecx & 0x00100000 )
00138 rval |= AV_CPU_FLAG_SSE42;
00139 #if HAVE_AVX
00140
00141 if ((ecx & 0x18000000) == 0x18000000) {
00142
00143 xgetbv(0, eax, edx);
00144 if ((eax & 0x6) == 0x6)
00145 rval |= AV_CPU_FLAG_AVX;
00146 }
00147 #endif
00148 #endif
00149 }
00150
00151 cpuid(0x80000000, max_ext_level, ebx, ecx, edx);
00152
00153 if (max_ext_level >= 0x80000001) {
00154 cpuid(0x80000001, eax, ebx, ecx, ext_caps);
00155 if (ext_caps & (1U << 31))
00156 rval |= AV_CPU_FLAG_3DNOW;
00157 if (ext_caps & (1 << 30))
00158 rval |= AV_CPU_FLAG_3DNOWEXT;
00159 if (ext_caps & (1 << 23))
00160 rval |= AV_CPU_FLAG_MMX;
00161 if (ext_caps & (1 << 22))
00162 rval |= AV_CPU_FLAG_MMXEXT;
00163
00164
00165
00166
00167
00168
00169
00170
00171 if (!strncmp(vendor.c, "AuthenticAMD", 12) &&
00172 rval & AV_CPU_FLAG_SSE2 && !(ecx & 0x00000040)) {
00173 rval |= AV_CPU_FLAG_SSE2SLOW;
00174 }
00175
00176
00177
00178 if (rval & AV_CPU_FLAG_AVX) {
00179 if (ecx & 0x00000800)
00180 rval |= AV_CPU_FLAG_XOP;
00181 if (ecx & 0x00010000)
00182 rval |= AV_CPU_FLAG_FMA4;
00183 }
00184 }
00185
00186 if (!strncmp(vendor.c, "GenuineIntel", 12)) {
00187 if (family == 6 && (model == 9 || model == 13 || model == 14)) {
00188
00189
00190
00191
00192
00193
00194
00195 if (rval & AV_CPU_FLAG_SSE2)
00196 rval ^= AV_CPU_FLAG_SSE2SLOW | AV_CPU_FLAG_SSE2;
00197 if (rval & AV_CPU_FLAG_SSE3)
00198 rval ^= AV_CPU_FLAG_SSE3SLOW | AV_CPU_FLAG_SSE3;
00199 }
00200
00201
00202
00203
00204
00205 if (family == 6 && model == 28)
00206 rval |= AV_CPU_FLAG_ATOM;
00207 }
00208
00209 return rval;
00210 }