The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

314 lines
10KB

  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 "include/private/cpu.h"
  36. #include "../compat.h"
  37. //#include <stdlib.h>
  38. //#include <string.h>
  39. #if defined _MSC_VER
  40. //#include <intrin.h> /* for __cpuid() and _xgetbv() */
  41. #elif defined __GNUC__ && defined HAVE_CPUID_H
  42. #include <cpuid.h> /* for __get_cpuid() and __get_cpuid_max() */
  43. #endif
  44. #ifndef NDEBUG
  45. //#include <stdio.h>
  46. #define dfprintf fprintf
  47. #else
  48. /* This is bad practice, it should be a static void empty function */
  49. #define dfprintf(file, format, ...)
  50. #endif
  51. #if defined FLAC__CPU_PPC
  52. #if defined(__linux__) || (defined(__FreeBSD__) && (__FreeBSD__ >= 12))
  53. #include <sys/auxv.h>
  54. #endif
  55. #endif
  56. #if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && (defined FLAC__HAS_NASM || FLAC__HAS_X86INTRIN) && !defined FLAC__NO_ASM
  57. /* these are flags in EDX of CPUID AX=00000001 */
  58. static const uint32_t FLAC__CPUINFO_X86_CPUID_CMOV = 0x00008000;
  59. static const uint32_t FLAC__CPUINFO_X86_CPUID_MMX = 0x00800000;
  60. static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE = 0x02000000;
  61. static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE2 = 0x04000000;
  62. /* these are flags in ECX of CPUID AX=00000001 */
  63. static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE3 = 0x00000001;
  64. static const uint32_t FLAC__CPUINFO_X86_CPUID_SSSE3 = 0x00000200;
  65. static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE41 = 0x00080000;
  66. static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE42 = 0x00100000;
  67. static const uint32_t FLAC__CPUINFO_X86_CPUID_OSXSAVE = 0x08000000;
  68. static const uint32_t FLAC__CPUINFO_X86_CPUID_AVX = 0x10000000;
  69. static const uint32_t FLAC__CPUINFO_X86_CPUID_FMA = 0x00001000;
  70. /* these are flags in EBX of CPUID AX=00000007 */
  71. static const uint32_t FLAC__CPUINFO_X86_CPUID_AVX2 = 0x00000020;
  72. #if FLAC__AVX_SUPPORTED
  73. static uint32_t
  74. cpu_xgetbv_x86(void)
  75. {
  76. #if (defined _MSC_VER || defined __INTEL_COMPILER) && 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 uint32_t
  88. cpu_have_cpuid(void)
  89. {
  90. #if defined FLAC__CPU_X86_64 || defined __i686__ || defined __SSE__ || (defined _M_IX86_FP && _M_IX86_FP > 0)
  91. /* target CPU does have CPUID instruction */
  92. return 1;
  93. #elif defined FLAC__HAS_NASM
  94. return FLAC__cpu_have_cpuid_asm_ia32();
  95. #elif defined __GNUC__ && defined HAVE_CPUID_H
  96. if (__get_cpuid_max(0, 0) != 0)
  97. return 1;
  98. else
  99. return 0;
  100. #elif defined _MSC_VER
  101. FLAC__uint32 flags1, flags2;
  102. __asm {
  103. pushfd
  104. pushfd
  105. pop eax
  106. mov flags1, eax
  107. xor eax, 0x200000
  108. push eax
  109. popfd
  110. pushfd
  111. pop eax
  112. mov flags2, eax
  113. popfd
  114. }
  115. if (((flags1^flags2) & 0x200000) != 0)
  116. return 1;
  117. else
  118. return 0;
  119. #else
  120. return 0;
  121. #endif
  122. }
  123. static void
  124. cpuinfo_x86(FLAC__uint32 level, FLAC__uint32 *eax, FLAC__uint32 *ebx, FLAC__uint32 *ecx, FLAC__uint32 *edx)
  125. {
  126. #if defined _MSC_VER
  127. int cpuinfo[4];
  128. int ext = level & 0x80000000;
  129. __cpuid(cpuinfo, ext);
  130. if ((uint32_t)cpuinfo[0] >= level) {
  131. #if FLAC__AVX_SUPPORTED
  132. __cpuidex(cpuinfo, level, 0); /* for AVX2 detection */
  133. #else
  134. __cpuid(cpuinfo, level); /* some old compilers don't support __cpuidex */
  135. #endif
  136. *eax = cpuinfo[0]; *ebx = cpuinfo[1]; *ecx = cpuinfo[2]; *edx = cpuinfo[3];
  137. return;
  138. }
  139. #elif defined __GNUC__ && defined HAVE_CPUID_H
  140. FLAC__uint32 ext = level & 0x80000000;
  141. __cpuid(ext, *eax, *ebx, *ecx, *edx);
  142. if (*eax >= level) {
  143. __cpuid_count(level, 0, *eax, *ebx, *ecx, *edx);
  144. return;
  145. }
  146. #elif defined FLAC__HAS_NASM && defined FLAC__CPU_IA32
  147. FLAC__cpu_info_asm_ia32(level, eax, ebx, ecx, edx);
  148. return;
  149. #endif
  150. ignoreUnused (level);
  151. *eax = *ebx = *ecx = *edx = 0;
  152. }
  153. #endif
  154. static void
  155. x86_cpu_info (FLAC__CPUInfo *info)
  156. {
  157. #if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && (defined FLAC__HAS_NASM || FLAC__HAS_X86INTRIN) && !defined FLAC__NO_ASM
  158. #if FLAC__AVX_SUPPORTED
  159. FLAC__bool x86_osxsave = false;
  160. #endif
  161. FLAC__bool os_avx = false;
  162. FLAC__uint32 flags_eax, flags_ebx, flags_ecx, flags_edx;
  163. info->use_asm = true; /* we assume a minimum of 80386 */
  164. if (!cpu_have_cpuid())
  165. return;
  166. cpuinfo_x86(0, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
  167. info->x86.intel = (flags_ebx == 0x756E6547 && flags_edx == 0x49656E69 && flags_ecx == 0x6C65746E) ? true : false; /* GenuineIntel */
  168. cpuinfo_x86(1, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
  169. info->x86.cmov = (flags_edx & FLAC__CPUINFO_X86_CPUID_CMOV ) ? true : false;
  170. info->x86.mmx = (flags_edx & FLAC__CPUINFO_X86_CPUID_MMX ) ? true : false;
  171. info->x86.sse = (flags_edx & FLAC__CPUINFO_X86_CPUID_SSE ) ? true : false;
  172. info->x86.sse2 = (flags_edx & FLAC__CPUINFO_X86_CPUID_SSE2 ) ? true : false;
  173. info->x86.sse3 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE3 ) ? true : false;
  174. info->x86.ssse3 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSSE3) ? true : false;
  175. info->x86.sse41 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE41) ? true : false;
  176. info->x86.sse42 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE42) ? true : false;
  177. #if FLAC__AVX_SUPPORTED
  178. x86_osxsave = (flags_ecx & FLAC__CPUINFO_X86_CPUID_OSXSAVE) ? true : false;
  179. info->x86.avx = (flags_ecx & FLAC__CPUINFO_X86_CPUID_AVX ) ? true : false;
  180. info->x86.fma = (flags_ecx & FLAC__CPUINFO_X86_CPUID_FMA ) ? true : false;
  181. cpuinfo_x86(7, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
  182. info->x86.avx2 = (flags_ebx & FLAC__CPUINFO_X86_CPUID_AVX2 ) ? true : false;
  183. #endif
  184. #if defined FLAC__CPU_IA32
  185. dfprintf(stderr, "CPU info (IA-32):\n", "");
  186. #else
  187. dfprintf(stderr, "CPU info (x86-64):\n", "");
  188. #endif
  189. dfprintf(stderr, " CMOV ....... %c\n", info->x86.cmov ? 'Y' : 'n');
  190. dfprintf(stderr, " MMX ........ %c\n", info->x86.mmx ? 'Y' : 'n');
  191. dfprintf(stderr, " SSE ........ %c\n", info->x86.sse ? 'Y' : 'n');
  192. dfprintf(stderr, " SSE2 ....... %c\n", info->x86.sse2 ? 'Y' : 'n');
  193. dfprintf(stderr, " SSE3 ....... %c\n", info->x86.sse3 ? 'Y' : 'n');
  194. dfprintf(stderr, " SSSE3 ...... %c\n", info->x86.ssse3 ? 'Y' : 'n');
  195. dfprintf(stderr, " SSE41 ...... %c\n", info->x86.sse41 ? 'Y' : 'n');
  196. dfprintf(stderr, " SSE42 ...... %c\n", info->x86.sse42 ? 'Y' : 'n');
  197. if (FLAC__AVX_SUPPORTED) {
  198. dfprintf(stderr, " AVX ........ %c\n", info->x86.avx ? 'Y' : 'n');
  199. dfprintf(stderr, " FMA ........ %c\n", info->x86.fma ? 'Y' : 'n');
  200. dfprintf(stderr, " AVX2 ....... %c\n", info->x86.avx2 ? 'Y' : 'n');
  201. }
  202. /*
  203. * now have to check for OS support of AVX instructions
  204. */
  205. #if FLAC__AVX_SUPPORTED
  206. if (info->x86.avx && x86_osxsave && (cpu_xgetbv_x86() & 0x6) == 0x6) {
  207. os_avx = true;
  208. }
  209. #endif
  210. if (os_avx) {
  211. dfprintf(stderr, " AVX OS sup . %c\n", info->x86.avx ? 'Y' : 'n');
  212. }
  213. if (!os_avx) {
  214. /* no OS AVX support */
  215. info->x86.avx = false;
  216. info->x86.avx2 = false;
  217. info->x86.fma = false;
  218. }
  219. #else
  220. info->use_asm = false;
  221. #endif
  222. }
  223. static void
  224. ppc_cpu_info (FLAC__CPUInfo *info)
  225. {
  226. #if defined FLAC__CPU_PPC
  227. #ifndef PPC_FEATURE2_ARCH_3_00
  228. #define PPC_FEATURE2_ARCH_3_00 0x00800000
  229. #endif
  230. #ifndef PPC_FEATURE2_ARCH_2_07
  231. #define PPC_FEATURE2_ARCH_2_07 0x80000000
  232. #endif
  233. #ifdef __linux__
  234. if (getauxval(AT_HWCAP2) & PPC_FEATURE2_ARCH_3_00) {
  235. info->ppc.arch_3_00 = true;
  236. } else if (getauxval(AT_HWCAP2) & PPC_FEATURE2_ARCH_2_07) {
  237. info->ppc.arch_2_07 = true;
  238. }
  239. #elif defined(__FreeBSD__) && (__FreeBSD__ >= 12)
  240. long hwcaps;
  241. /* elf_aux_info() appeared in FreeBSD 12.0 */
  242. elf_aux_info(AT_HWCAP2, &hwcaps, sizeof(hwcaps));
  243. if (hwcaps & PPC_FEATURE2_ARCH_3_00) {
  244. info->ppc.arch_3_00 = true;
  245. } else if (hwcaps & PPC_FEATURE2_ARCH_2_07) {
  246. info->ppc.arch_2_07 = true;
  247. }
  248. #elif defined(__APPLE__)
  249. /* no Mac OS X version supports CPU with Power AVI v2.07 or better */
  250. info->ppc.arch_2_07 = false;
  251. info->ppc.arch_3_00 = false;
  252. #else
  253. #error Unsupported platform! Please add support for reading ppc hwcaps.
  254. #endif
  255. #else
  256. info->ppc.arch_2_07 = false;
  257. info->ppc.arch_3_00 = false;
  258. #endif
  259. }
  260. void FLAC__cpu_info (FLAC__CPUInfo *info)
  261. {
  262. memset(info, 0, sizeof(*info));
  263. #ifdef FLAC__CPU_IA32
  264. info->type = FLAC__CPUINFO_TYPE_IA32;
  265. #elif defined FLAC__CPU_X86_64
  266. info->type = FLAC__CPUINFO_TYPE_X86_64;
  267. #elif defined FLAC__CPU_PPC
  268. info->type = FLAC__CPUINFO_TYPE_PPC;
  269. #else
  270. info->type = FLAC__CPUINFO_TYPE_UNKNOWN;
  271. #endif
  272. switch (info->type) {
  273. case FLAC__CPUINFO_TYPE_IA32: /* fallthrough */
  274. case FLAC__CPUINFO_TYPE_X86_64:
  275. x86_cpu_info (info);
  276. break;
  277. case FLAC__CPUINFO_TYPE_PPC:
  278. ppc_cpu_info (info);
  279. break;
  280. default:
  281. info->use_asm = false;
  282. break;
  283. }
  284. }