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