PageRenderTime 26ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/trunk/libs/libflac/flac-1.3.2/src/libFLAC/cpu.c

https://gitlab.com/thanhnhat041/padavan-ng
C | 293 lines | 210 code | 36 blank | 47 comment | 49 complexity | dc73ed9d2c8e5cf28d6e52cb169c8b00 MD5 | raw file
  1. /* libFLAC - Free Lossless Audio Codec library
  2. * Copyright (C) 2001-2009 Josh Coalson
  3. * Copyright (C) 2011-2016 Xiph.Org Foundation
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. *
  9. * - Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. *
  12. * - Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. *
  16. * - Neither the name of the Xiph.org Foundation nor the names of its
  17. * contributors may be used to endorse or promote products derived from
  18. * this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
  24. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  25. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  26. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  27. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  28. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  29. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  30. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. */
  32. #ifdef HAVE_CONFIG_H
  33. # include <config.h>
  34. #endif
  35. #include "private/cpu.h"
  36. #include "share/compat.h"
  37. #include <stdlib.h>
  38. #include <memory.h>
  39. #if defined(_MSC_VER)
  40. # include <intrin.h> /* for __cpuid() and _xgetbv() */
  41. #endif
  42. #if defined __GNUC__ && defined HAVE_CPUID_H
  43. # include <cpuid.h> /* for __get_cpuid() and __get_cpuid_max() */
  44. #endif
  45. #ifdef DEBUG
  46. #include <stdio.h>
  47. #define dfprintf fprintf
  48. #else
  49. /* This is bad practice, it should be a static void empty function */
  50. #define dfprintf(file, format, ...)
  51. #endif
  52. #if defined FLAC__CPU_IA32
  53. /* these are flags in EDX of CPUID AX=00000001 */
  54. static const unsigned FLAC__CPUINFO_IA32_CPUID_CMOV = 0x00008000;
  55. static const unsigned FLAC__CPUINFO_IA32_CPUID_MMX = 0x00800000;
  56. static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE = 0x02000000;
  57. static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE2 = 0x04000000;
  58. #endif
  59. #if FLAC__HAS_X86INTRIN || FLAC__AVX_SUPPORTED
  60. /* these are flags in ECX of CPUID AX=00000001 */
  61. static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE3 = 0x00000001;
  62. static const unsigned FLAC__CPUINFO_IA32_CPUID_SSSE3 = 0x00000200;
  63. static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE41 = 0x00080000;
  64. static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE42 = 0x00100000;
  65. /* these are flags in ECX of CPUID AX=00000001 */
  66. static const unsigned FLAC__CPUINFO_IA32_CPUID_OSXSAVE = 0x08000000;
  67. static const unsigned FLAC__CPUINFO_IA32_CPUID_AVX = 0x10000000;
  68. static const unsigned FLAC__CPUINFO_IA32_CPUID_FMA = 0x00001000;
  69. /* these are flags in EBX of CPUID AX=00000007 */
  70. static const unsigned FLAC__CPUINFO_IA32_CPUID_AVX2 = 0x00000020;
  71. #endif
  72. #if defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64
  73. static uint32_t
  74. cpu_xgetbv_x86(void)
  75. {
  76. #if (defined _MSC_VER || defined __INTEL_COMPILER) && FLAC__HAS_X86INTRIN && FLAC__AVX_SUPPORTED
  77. return (uint32_t)_xgetbv(0);
  78. #elif defined __GNUC__
  79. uint32_t lo, hi;
  80. asm volatile (".byte 0x0f, 0x01, 0xd0" : "=a"(lo), "=d"(hi) : "c" (0));
  81. return lo;
  82. #else
  83. return 0;
  84. #endif
  85. }
  86. #endif
  87. static void
  88. ia32_cpu_info (FLAC__CPUInfo *info)
  89. {
  90. #if !defined FLAC__CPU_IA32
  91. (void) info;
  92. #else
  93. FLAC__bool ia32_osxsave = false;
  94. FLAC__uint32 flags_eax, flags_ebx, flags_ecx, flags_edx;
  95. #if !defined FLAC__NO_ASM && (defined FLAC__HAS_NASM || FLAC__HAS_X86INTRIN)
  96. info->use_asm = true; /* we assume a minimum of 80386 with FLAC__CPU_IA32 */
  97. #if defined FLAC__HAS_NASM
  98. if(!FLAC__cpu_have_cpuid_asm_ia32())
  99. return;
  100. #endif
  101. /* http://www.sandpile.org/x86/cpuid.htm */
  102. if (FLAC__HAS_X86INTRIN) {
  103. FLAC__cpu_info_x86(0, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
  104. info->ia32.intel = (flags_ebx == 0x756E6547 && flags_edx == 0x49656E69 && flags_ecx == 0x6C65746E) ? true : false; /* GenuineIntel */
  105. FLAC__cpu_info_x86(1, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
  106. }
  107. else {
  108. FLAC__cpu_info_asm_ia32(&flags_edx, &flags_ecx);
  109. }
  110. info->ia32.cmov = (flags_edx & FLAC__CPUINFO_IA32_CPUID_CMOV ) ? true : false;
  111. info->ia32.mmx = (flags_edx & FLAC__CPUINFO_IA32_CPUID_MMX ) ? true : false;
  112. info->ia32.sse = (flags_edx & FLAC__CPUINFO_IA32_CPUID_SSE ) ? true : false;
  113. info->ia32.sse2 = (flags_edx & FLAC__CPUINFO_IA32_CPUID_SSE2 ) ? true : false;
  114. info->ia32.sse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE3 ) ? true : false;
  115. info->ia32.ssse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSSE3) ? true : false;
  116. info->ia32.sse41 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE41) ? true : false;
  117. info->ia32.sse42 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE42) ? true : false;
  118. if (FLAC__HAS_X86INTRIN && FLAC__AVX_SUPPORTED) {
  119. ia32_osxsave = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_OSXSAVE) ? true : false;
  120. info->ia32.avx = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_AVX ) ? true : false;
  121. info->ia32.fma = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_FMA ) ? true : false;
  122. FLAC__cpu_info_x86(7, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
  123. info->ia32.avx2 = (flags_ebx & FLAC__CPUINFO_IA32_CPUID_AVX2 ) ? true : false;
  124. }
  125. dfprintf(stderr, "CPU info (IA-32):\n");
  126. dfprintf(stderr, " CMOV ....... %c\n", info->ia32.cmov ? 'Y' : 'n');
  127. dfprintf(stderr, " MMX ........ %c\n", info->ia32.mmx ? 'Y' : 'n');
  128. dfprintf(stderr, " SSE ........ %c\n", info->ia32.sse ? 'Y' : 'n');
  129. dfprintf(stderr, " SSE2 ....... %c\n", info->ia32.sse2 ? 'Y' : 'n');
  130. dfprintf(stderr, " SSE3 ....... %c\n", info->ia32.sse3 ? 'Y' : 'n');
  131. dfprintf(stderr, " SSSE3 ...... %c\n", info->ia32.ssse3 ? 'Y' : 'n');
  132. dfprintf(stderr, " SSE41 ...... %c\n", info->ia32.sse41 ? 'Y' : 'n');
  133. dfprintf(stderr, " SSE42 ...... %c\n", info->ia32.sse42 ? 'Y' : 'n');
  134. if (FLAC__HAS_X86INTRIN && FLAC__AVX_SUPPORTED) {
  135. dfprintf(stderr, " AVX ........ %c\n", info->ia32.avx ? 'Y' : 'n');
  136. dfprintf(stderr, " FMA ........ %c\n", info->ia32.fma ? 'Y' : 'n');
  137. dfprintf(stderr, " AVX2 ....... %c\n", info->ia32.avx2 ? 'Y' : 'n');
  138. }
  139. /*
  140. * now have to check for OS support of AVX instructions
  141. */
  142. if (!FLAC__HAS_X86INTRIN || !info->ia32.avx || !ia32_osxsave || (cpu_xgetbv_x86() & 0x6) != 0x6) {
  143. /* no OS AVX support */
  144. info->ia32.avx = false;
  145. info->ia32.avx2 = false;
  146. info->ia32.fma = false;
  147. }
  148. if (FLAC__HAS_X86INTRIN && FLAC__AVX_SUPPORTED) {
  149. dfprintf(stderr, " AVX OS sup . %c\n", info->ia32.avx ? 'Y' : 'n');
  150. }
  151. #else
  152. info->use_asm = false;
  153. #endif
  154. #endif
  155. }
  156. static void
  157. x86_64_cpu_info (FLAC__CPUInfo *info)
  158. {
  159. #if !defined FLAC__NO_ASM && FLAC__HAS_X86INTRIN
  160. FLAC__bool x86_osxsave = false;
  161. FLAC__uint32 flags_eax, flags_ebx, flags_ecx, flags_edx;
  162. info->use_asm = true;
  163. /* http://www.sandpile.org/x86/cpuid.htm */
  164. FLAC__cpu_info_x86(0, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
  165. info->x86.intel = (flags_ebx == 0x756E6547 && flags_edx == 0x49656E69 && flags_ecx == 0x6C65746E) ? true : false; /* GenuineIntel */
  166. FLAC__cpu_info_x86(1, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
  167. info->x86.sse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE3 ) ? true : false;
  168. info->x86.ssse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSSE3) ? true : false;
  169. info->x86.sse41 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE41) ? true : false;
  170. info->x86.sse42 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE42) ? true : false;
  171. if (FLAC__AVX_SUPPORTED) {
  172. x86_osxsave = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_OSXSAVE) ? true : false;
  173. info->x86.avx = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_AVX ) ? true : false;
  174. info->x86.fma = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_FMA ) ? true : false;
  175. FLAC__cpu_info_x86(7, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
  176. info->x86.avx2 = (flags_ebx & FLAC__CPUINFO_IA32_CPUID_AVX2 ) ? true : false;
  177. }
  178. dfprintf(stderr, "CPU info (x86-64):\n");
  179. dfprintf(stderr, " SSE3 ....... %c\n", info->x86.sse3 ? 'Y' : 'n');
  180. dfprintf(stderr, " SSSE3 ...... %c\n", info->x86.ssse3 ? 'Y' : 'n');
  181. dfprintf(stderr, " SSE41 ...... %c\n", info->x86.sse41 ? 'Y' : 'n');
  182. dfprintf(stderr, " SSE42 ...... %c\n", info->x86.sse42 ? 'Y' : 'n');
  183. if (FLAC__AVX_SUPPORTED) {
  184. dfprintf(stderr, " AVX ........ %c\n", info->x86.avx ? 'Y' : 'n');
  185. dfprintf(stderr, " FMA ........ %c\n", info->x86.fma ? 'Y' : 'n');
  186. dfprintf(stderr, " AVX2 ....... %c\n", info->x86.avx2 ? 'Y' : 'n');
  187. }
  188. /*
  189. * now have to check for OS support of AVX instructions
  190. */
  191. if (!info->x86.avx || !x86_osxsave || (cpu_xgetbv_x86() & 0x6) != 0x6) {
  192. /* no OS AVX support */
  193. info->x86.avx = false;
  194. info->x86.avx2 = false;
  195. info->x86.fma = false;
  196. }
  197. if (FLAC__AVX_SUPPORTED) {
  198. dfprintf(stderr, " AVX OS sup . %c\n", info->x86.avx ? 'Y' : 'n');
  199. }
  200. #else
  201. /* Silence compiler warnings. */
  202. (void) info;
  203. #if defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64
  204. if (0) cpu_xgetbv_x86 ();
  205. #endif
  206. #endif
  207. }
  208. void FLAC__cpu_info (FLAC__CPUInfo *info)
  209. {
  210. memset(info, 0, sizeof(*info));
  211. #ifdef FLAC__CPU_IA32
  212. info->type = FLAC__CPUINFO_TYPE_IA32;
  213. #elif defined FLAC__CPU_X86_64
  214. info->type = FLAC__CPUINFO_TYPE_X86_64;
  215. #else
  216. info->type = FLAC__CPUINFO_TYPE_UNKNOWN;
  217. info->use_asm = false;
  218. #endif
  219. switch (info->type) {
  220. case FLAC__CPUINFO_TYPE_IA32:
  221. ia32_cpu_info (info);
  222. break;
  223. case FLAC__CPUINFO_TYPE_X86_64:
  224. x86_64_cpu_info (info);
  225. break;
  226. default:
  227. info->use_asm = false;
  228. break;
  229. }
  230. }
  231. #if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
  232. void FLAC__cpu_info_x86(FLAC__uint32 level, FLAC__uint32 *eax, FLAC__uint32 *ebx, FLAC__uint32 *ecx, FLAC__uint32 *edx)
  233. {
  234. #if defined _MSC_VER || defined __INTEL_COMPILER
  235. int cpuinfo[4];
  236. int ext = level & 0x80000000;
  237. __cpuid(cpuinfo, ext);
  238. if((unsigned)cpuinfo[0] >= level) {
  239. #if FLAC__AVX_SUPPORTED
  240. __cpuidex(cpuinfo, ext, 0); /* for AVX2 detection */
  241. #else
  242. __cpuid(cpuinfo, ext); /* some old compilers don't support __cpuidex */
  243. #endif
  244. *eax = cpuinfo[0]; *ebx = cpuinfo[1]; *ecx = cpuinfo[2]; *edx = cpuinfo[3];
  245. return;
  246. }
  247. #elif defined __GNUC__ && defined HAVE_CPUID_H
  248. FLAC__uint32 ext = level & 0x80000000;
  249. __cpuid(ext, *eax, *ebx, *ecx, *edx);
  250. if (*eax >= level) {
  251. __cpuid_count(level, 0, *eax, *ebx, *ecx, *edx);
  252. return;
  253. }
  254. #endif
  255. *eax = *ebx = *ecx = *edx = 0;
  256. }
  257. #endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */