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.

262 lines
8.9KB

  1. /* libFLAC - Free Lossless Audio Codec library
  2. * Copyright (C) 2001-2009 Josh Coalson
  3. * Copyright (C) 2011-2023 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(HAVE_SYS_AUXV_H)
  52. #include <sys/auxv.h>
  53. #endif
  54. #if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN && !defined FLAC__NO_ASM
  55. /* these are flags in EDX of CPUID AX=00000001 */
  56. static const uint32_t FLAC__CPUINFO_X86_CPUID_CMOV = 0x00008000;
  57. static const uint32_t FLAC__CPUINFO_X86_CPUID_MMX = 0x00800000;
  58. static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE = 0x02000000;
  59. static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE2 = 0x04000000;
  60. /* these are flags in ECX of CPUID AX=00000001 */
  61. static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE3 = 0x00000001;
  62. static const uint32_t FLAC__CPUINFO_X86_CPUID_SSSE3 = 0x00000200;
  63. static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE41 = 0x00080000;
  64. static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE42 = 0x00100000;
  65. static const uint32_t FLAC__CPUINFO_X86_CPUID_OSXSAVE = 0x08000000;
  66. static const uint32_t FLAC__CPUINFO_X86_CPUID_AVX = 0x10000000;
  67. static const uint32_t FLAC__CPUINFO_X86_CPUID_FMA = 0x00001000;
  68. /* these are flags in EBX of CPUID AX=00000007 */
  69. static const uint32_t FLAC__CPUINFO_X86_CPUID_AVX2 = 0x00000020;
  70. static const uint32_t FLAC__CPUINFO_X86_CPUID_BMI2 = 0x00000100;
  71. #if FLAC__AVX_SUPPORTED
  72. static uint32_t
  73. cpu_xgetbv_x86(void)
  74. {
  75. #if (defined _MSC_VER || defined __INTEL_COMPILER) && FLAC__AVX_SUPPORTED
  76. return (uint32_t)_xgetbv(0);
  77. #elif defined __GNUC__
  78. uint32_t lo, hi;
  79. __asm__ volatile (".byte 0x0f, 0x01, 0xd0" : "=a"(lo), "=d"(hi) : "c" (0));
  80. return lo;
  81. #else
  82. return 0;
  83. #endif
  84. }
  85. #endif
  86. static uint32_t
  87. cpu_have_cpuid(void)
  88. {
  89. #if defined FLAC__CPU_X86_64 || defined __i686__ || defined __SSE__ || (defined _M_IX86_FP && _M_IX86_FP > 0)
  90. /* target CPU does have CPUID instruction */
  91. return 1;
  92. #elif defined __GNUC__ && defined HAVE_CPUID_H
  93. if (__get_cpuid_max(0, 0) != 0)
  94. return 1;
  95. else
  96. return 0;
  97. #elif defined _MSC_VER
  98. FLAC__uint32 flags1, flags2;
  99. __asm {
  100. pushfd
  101. pushfd
  102. pop eax
  103. mov flags1, eax
  104. xor eax, 0x200000
  105. push eax
  106. popfd
  107. pushfd
  108. pop eax
  109. mov flags2, eax
  110. popfd
  111. }
  112. if (((flags1^flags2) & 0x200000) != 0)
  113. return 1;
  114. else
  115. return 0;
  116. #else
  117. return 0;
  118. #endif
  119. }
  120. static void
  121. cpuinfo_x86([[maybe_unused]] FLAC__uint32 level, FLAC__uint32 *eax, FLAC__uint32 *ebx, FLAC__uint32 *ecx, FLAC__uint32 *edx)
  122. {
  123. #if defined _MSC_VER
  124. int cpuinfo[4];
  125. int ext = level & 0x80000000;
  126. __cpuid(cpuinfo, ext);
  127. if ((uint32_t)cpuinfo[0] >= level) {
  128. #if FLAC__AVX_SUPPORTED
  129. __cpuidex(cpuinfo, level, 0); /* for AVX2 detection */
  130. #else
  131. __cpuid(cpuinfo, level); /* some old compilers don't support __cpuidex */
  132. #endif
  133. *eax = cpuinfo[0]; *ebx = cpuinfo[1]; *ecx = cpuinfo[2]; *edx = cpuinfo[3];
  134. return;
  135. }
  136. #elif defined __GNUC__ && defined HAVE_CPUID_H
  137. FLAC__uint32 ext = level & 0x80000000;
  138. __cpuid(ext, *eax, *ebx, *ecx, *edx);
  139. if (*eax >= level) {
  140. __cpuid_count(level, 0, *eax, *ebx, *ecx, *edx);
  141. return;
  142. }
  143. #endif
  144. *eax = *ebx = *ecx = *edx = 0;
  145. }
  146. #endif
  147. static void
  148. x86_cpu_info (FLAC__CPUInfo *info)
  149. {
  150. #if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN && !defined FLAC__NO_ASM
  151. #if FLAC__AVX_SUPPORTED
  152. FLAC__bool x86_osxsave = false;
  153. #endif
  154. FLAC__bool os_avx = false;
  155. FLAC__uint32 flags_eax, flags_ebx, flags_ecx, flags_edx;
  156. info->use_asm = true; /* we assume a minimum of 80386 */
  157. if (!cpu_have_cpuid())
  158. return;
  159. cpuinfo_x86(0, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
  160. info->x86.intel = (flags_ebx == 0x756E6547 && flags_edx == 0x49656E69 && flags_ecx == 0x6C65746E) ? true : false; /* GenuineIntel */
  161. cpuinfo_x86(1, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
  162. info->x86.cmov = (flags_edx & FLAC__CPUINFO_X86_CPUID_CMOV ) ? true : false;
  163. info->x86.mmx = (flags_edx & FLAC__CPUINFO_X86_CPUID_MMX ) ? true : false;
  164. info->x86.sse = (flags_edx & FLAC__CPUINFO_X86_CPUID_SSE ) ? true : false;
  165. info->x86.sse2 = (flags_edx & FLAC__CPUINFO_X86_CPUID_SSE2 ) ? true : false;
  166. info->x86.sse3 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE3 ) ? true : false;
  167. info->x86.ssse3 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSSE3) ? true : false;
  168. info->x86.sse41 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE41) ? true : false;
  169. info->x86.sse42 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE42) ? true : false;
  170. #if (FLAC__AVX_SUPPORTED)
  171. x86_osxsave = (flags_ecx & FLAC__CPUINFO_X86_CPUID_OSXSAVE) ? true : false;
  172. info->x86.avx = (flags_ecx & FLAC__CPUINFO_X86_CPUID_AVX ) ? true : false;
  173. info->x86.fma = (flags_ecx & FLAC__CPUINFO_X86_CPUID_FMA ) ? true : false;
  174. cpuinfo_x86(7, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
  175. info->x86.avx2 = (flags_ebx & FLAC__CPUINFO_X86_CPUID_AVX2 ) ? true : false;
  176. info->x86.bmi2 = (flags_ebx & FLAC__CPUINFO_X86_CPUID_BMI2 ) ? true : false;
  177. #endif
  178. #if defined FLAC__CPU_IA32
  179. dfprintf(stderr, "CPU info (IA-32):\n", "");
  180. #else
  181. dfprintf(stderr, "CPU info (x86-64):\n", "");
  182. #endif
  183. dfprintf(stderr, " CMOV ....... %c\n", info->x86.cmov ? 'Y' : 'n');
  184. dfprintf(stderr, " MMX ........ %c\n", info->x86.mmx ? 'Y' : 'n');
  185. dfprintf(stderr, " SSE ........ %c\n", info->x86.sse ? 'Y' : 'n');
  186. dfprintf(stderr, " SSE2 ....... %c\n", info->x86.sse2 ? 'Y' : 'n');
  187. dfprintf(stderr, " SSE3 ....... %c\n", info->x86.sse3 ? 'Y' : 'n');
  188. dfprintf(stderr, " SSSE3 ...... %c\n", info->x86.ssse3 ? 'Y' : 'n');
  189. dfprintf(stderr, " SSE41 ...... %c\n", info->x86.sse41 ? 'Y' : 'n');
  190. dfprintf(stderr, " SSE42 ...... %c\n", info->x86.sse42 ? 'Y' : 'n');
  191. if (FLAC__AVX_SUPPORTED) {
  192. dfprintf(stderr, " AVX ........ %c\n", info->x86.avx ? 'Y' : 'n');
  193. dfprintf(stderr, " FMA ........ %c\n", info->x86.fma ? 'Y' : 'n');
  194. dfprintf(stderr, " AVX2 ....... %c\n", info->x86.avx2 ? 'Y' : 'n');
  195. dfprintf(stderr, " BMI2 ....... %c\n", info->x86.bmi2 ? 'Y' : 'n');
  196. }
  197. /*
  198. * now have to check for OS support of AVX instructions
  199. */
  200. #if FLAC__AVX_SUPPORTED
  201. if (info->x86.avx && x86_osxsave && (cpu_xgetbv_x86() & 0x6) == 0x6) {
  202. os_avx = true;
  203. }
  204. #endif
  205. if (os_avx) {
  206. dfprintf(stderr, " AVX OS sup . %c\n", info->x86.avx ? 'Y' : 'n');
  207. }
  208. if (!os_avx) {
  209. /* no OS AVX support */
  210. info->x86.avx = false;
  211. info->x86.avx2 = false;
  212. info->x86.fma = false;
  213. }
  214. #else
  215. info->use_asm = false;
  216. #endif
  217. }
  218. void FLAC__cpu_info (FLAC__CPUInfo *info)
  219. {
  220. memset(info, 0, sizeof(*info));
  221. #ifdef FLAC__CPU_IA32
  222. info->type = FLAC__CPUINFO_TYPE_IA32;
  223. #elif defined FLAC__CPU_X86_64
  224. info->type = FLAC__CPUINFO_TYPE_X86_64;
  225. #else
  226. info->type = FLAC__CPUINFO_TYPE_UNKNOWN;
  227. #endif
  228. switch (info->type) {
  229. case FLAC__CPUINFO_TYPE_IA32: /* fallthrough */
  230. case FLAC__CPUINFO_TYPE_X86_64:
  231. x86_cpu_info (info);
  232. break;
  233. default:
  234. info->use_asm = false;
  235. break;
  236. }
  237. }