Coverage Report

Created: 2026-01-09 06:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/flac/src/libFLAC/cpu.c
Line
Count
Source
1
/* libFLAC - Free Lossless Audio Codec library
2
 * Copyright (C) 2001-2009  Josh Coalson
3
 * Copyright (C) 2011-2025  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
33
#ifdef HAVE_CONFIG_H
34
#  include <config.h>
35
#endif
36
37
#include "private/cpu.h"
38
#include "share/compat.h"
39
#include <stdlib.h>
40
#include <string.h>
41
42
#if defined _MSC_VER
43
#include <intrin.h> /* for __cpuid() and _xgetbv() */
44
#elif defined __GNUC__ && defined HAVE_CPUID_H
45
#include <cpuid.h> /* for __get_cpuid() and __get_cpuid_max() */
46
#endif
47
48
#if defined(HAVE_SYS_AUXV_H)
49
#include <sys/auxv.h>
50
#endif
51
52
#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN && !defined FLAC__NO_ASM
53
54
/* these are flags in EDX of CPUID AX=00000001 */
55
static const uint32_t FLAC__CPUINFO_X86_CPUID_CMOV    = 0x00008000;
56
static const uint32_t FLAC__CPUINFO_X86_CPUID_MMX     = 0x00800000;
57
static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE     = 0x02000000;
58
static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE2    = 0x04000000;
59
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
69
/* these are flags in EBX of CPUID AX=00000007 */
70
static const uint32_t FLAC__CPUINFO_X86_CPUID_AVX2    = 0x00000020;
71
static const uint32_t FLAC__CPUINFO_X86_CPUID_BMI2    = 0x00000100;
72
73
static uint32_t
74
cpu_xgetbv_x86(void)
75
24.4k
{
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
24.4k
  __asm__ volatile (".byte 0x0f, 0x01, 0xd0" : "=a"(lo), "=d"(hi) : "c" (0));
81
24.4k
  return lo;
82
#else
83
  return 0;
84
#endif
85
24.4k
}
86
87
static uint32_t
88
cpu_have_cpuid(void)
89
24.4k
{
90
24.4k
#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
24.4k
  return 1;
93
#elif defined __GNUC__ && defined HAVE_CPUID_H
94
  if (__get_cpuid_max(0, 0) != 0)
95
    return 1;
96
  else
97
    return 0;
98
#elif defined _MSC_VER
99
  FLAC__uint32 flags1, flags2;
100
  __asm {
101
    pushfd
102
    pushfd
103
    pop   eax
104
    mov   flags1, eax
105
    xor   eax, 0x200000
106
    push  eax
107
    popfd
108
    pushfd
109
    pop   eax
110
    mov   flags2, eax
111
    popfd
112
  }
113
  if (((flags1^flags2) & 0x200000) != 0)
114
    return 1;
115
  else
116
    return 0;
117
#else
118
  return 0;
119
#endif
120
24.4k
}
121
122
static void
123
cpuinfo_x86(FLAC__uint32 level, FLAC__uint32 *eax, FLAC__uint32 *ebx, FLAC__uint32 *ecx, FLAC__uint32 *edx)
124
73.2k
{
125
#if defined _MSC_VER
126
  int cpuinfo[4];
127
  int ext = level & 0x80000000;
128
  __cpuid(cpuinfo, ext);
129
  if ((uint32_t)cpuinfo[0] >= level) {
130
#if FLAC__AVX_SUPPORTED
131
    __cpuidex(cpuinfo, level, 0); /* for AVX2 detection */
132
#else
133
    __cpuid(cpuinfo, level); /* some old compilers don't support __cpuidex */
134
#endif
135
    *eax = cpuinfo[0]; *ebx = cpuinfo[1]; *ecx = cpuinfo[2]; *edx = cpuinfo[3];
136
    return;
137
  }
138
#elif defined __GNUC__ && defined HAVE_CPUID_H
139
  FLAC__uint32 ext = level & 0x80000000;
140
73.2k
  __cpuid(ext, *eax, *ebx, *ecx, *edx);
141
73.2k
  if (*eax >= level) {
142
73.2k
    __cpuid_count(level, 0, *eax, *ebx, *ecx, *edx);
143
73.2k
    return;
144
73.2k
  }
145
0
#endif
146
0
  *eax = *ebx = *ecx = *edx = 0;
147
0
}
148
149
#endif
150
151
static void
152
x86_cpu_info (FLAC__CPUInfo *info)
153
24.4k
{
154
24.4k
#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN && !defined FLAC__NO_ASM
155
24.4k
  FLAC__bool x86_osxsave = false;
156
24.4k
  FLAC__bool os_avx = false;
157
24.4k
  FLAC__uint32 flags_eax, flags_ebx, flags_ecx, flags_edx;
158
159
24.4k
  info->use_asm = true; /* we assume a minimum of 80386 */
160
24.4k
  if (!cpu_have_cpuid())
161
0
    return;
162
163
24.4k
  cpuinfo_x86(0, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
164
24.4k
  info->x86.intel = (flags_ebx == 0x756E6547 && flags_edx == 0x49656E69 && flags_ecx == 0x6C65746E) ? true : false; /* GenuineIntel */
165
24.4k
  cpuinfo_x86(1, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
166
167
24.4k
  info->x86.cmov  = (flags_edx & FLAC__CPUINFO_X86_CPUID_CMOV ) ? true : false;
168
24.4k
  info->x86.mmx   = (flags_edx & FLAC__CPUINFO_X86_CPUID_MMX  ) ? true : false;
169
24.4k
  info->x86.sse   = (flags_edx & FLAC__CPUINFO_X86_CPUID_SSE  ) ? true : false;
170
24.4k
  info->x86.sse2  = (flags_edx & FLAC__CPUINFO_X86_CPUID_SSE2 ) ? true : false;
171
24.4k
  info->x86.sse3  = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE3 ) ? true : false;
172
24.4k
  info->x86.ssse3 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSSE3) ? true : false;
173
24.4k
  info->x86.sse41 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE41) ? true : false;
174
24.4k
  info->x86.sse42 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE42) ? true : false;
175
176
24.4k
  if (FLAC__AVX_SUPPORTED) {
177
24.4k
    x86_osxsave     = (flags_ecx & FLAC__CPUINFO_X86_CPUID_OSXSAVE) ? true : false;
178
24.4k
    info->x86.avx   = (flags_ecx & FLAC__CPUINFO_X86_CPUID_AVX    ) ? true : false;
179
24.4k
    info->x86.fma   = (flags_ecx & FLAC__CPUINFO_X86_CPUID_FMA    ) ? true : false;
180
24.4k
    cpuinfo_x86(7, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
181
24.4k
    info->x86.avx2  = (flags_ebx & FLAC__CPUINFO_X86_CPUID_AVX2   ) ? true : false;
182
24.4k
    info->x86.bmi2  = (flags_ebx & FLAC__CPUINFO_X86_CPUID_BMI2   ) ? true : false;
183
24.4k
  }
184
185
  /*
186
   * now have to check for OS support of AVX instructions
187
   */
188
24.4k
  if (FLAC__AVX_SUPPORTED && info->x86.avx && x86_osxsave && (cpu_xgetbv_x86() & 0x6) == 0x6) {
189
24.4k
    os_avx = true;
190
24.4k
  }
191
24.4k
  if (!os_avx) {
192
    /* no OS AVX support */
193
0
    info->x86.avx     = false;
194
0
    info->x86.avx2    = false;
195
0
    info->x86.fma     = false;
196
0
  }
197
#else
198
  info->use_asm = false;
199
#endif
200
24.4k
}
201
202
void FLAC__cpu_info (FLAC__CPUInfo *info)
203
24.4k
{
204
24.4k
  memset(info, 0, sizeof(*info));
205
206
#ifdef FLAC__CPU_IA32
207
  info->type = FLAC__CPUINFO_TYPE_IA32;
208
#elif defined FLAC__CPU_X86_64
209
  info->type = FLAC__CPUINFO_TYPE_X86_64;
210
#else
211
  info->type = FLAC__CPUINFO_TYPE_UNKNOWN;
212
#endif
213
214
24.4k
  switch (info->type) {
215
0
  case FLAC__CPUINFO_TYPE_IA32: /* fallthrough */
216
24.4k
  case FLAC__CPUINFO_TYPE_X86_64:
217
24.4k
    x86_cpu_info (info);
218
24.4k
    break;
219
0
  default:
220
    info->use_asm = false;
221
0
    break;
222
24.4k
  }
223
24.4k
}