Coverage Report

Created: 2026-07-16 07:10

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
15.6k
{
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
15.6k
  __asm__ volatile (".byte 0x0f, 0x01, 0xd0" : "=a"(lo), "=d"(hi) : "c" (0));
81
15.6k
  return lo;
82
#else
83
  return 0;
84
#endif
85
15.6k
}
86
87
static uint32_t
88
cpu_have_cpuid(void)
89
15.6k
{
90
15.6k
#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
15.6k
  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
15.6k
}
121
122
static void
123
cpuinfo_x86(FLAC__uint32 level, FLAC__uint32 *eax, FLAC__uint32 *ebx, FLAC__uint32 *ecx, FLAC__uint32 *edx)
124
46.8k
{
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
46.8k
  __cpuid(ext, *eax, *ebx, *ecx, *edx);
141
46.8k
  if (*eax >= level) {
142
46.8k
    __cpuid_count(level, 0, *eax, *ebx, *ecx, *edx);
143
46.8k
    return;
144
46.8k
  }
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
15.6k
{
154
15.6k
#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN && !defined FLAC__NO_ASM
155
15.6k
  FLAC__bool x86_osxsave = false;
156
15.6k
  FLAC__bool os_avx = false;
157
15.6k
  FLAC__uint32 flags_eax, flags_ebx, flags_ecx, flags_edx;
158
159
15.6k
  info->use_asm = true; /* we assume a minimum of 80386 */
160
15.6k
  if (!cpu_have_cpuid())
161
0
    return;
162
163
15.6k
  cpuinfo_x86(0, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
164
15.6k
  info->x86.intel = (flags_ebx == 0x756E6547 && flags_edx == 0x49656E69 && flags_ecx == 0x6C65746E) ? true : false; /* GenuineIntel */
165
15.6k
  cpuinfo_x86(1, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
166
167
15.6k
  info->x86.cmov  = (flags_edx & FLAC__CPUINFO_X86_CPUID_CMOV ) ? true : false;
168
15.6k
  info->x86.mmx   = (flags_edx & FLAC__CPUINFO_X86_CPUID_MMX  ) ? true : false;
169
15.6k
  info->x86.sse   = (flags_edx & FLAC__CPUINFO_X86_CPUID_SSE  ) ? true : false;
170
15.6k
  info->x86.sse2  = (flags_edx & FLAC__CPUINFO_X86_CPUID_SSE2 ) ? true : false;
171
15.6k
  info->x86.sse3  = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE3 ) ? true : false;
172
15.6k
  info->x86.ssse3 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSSE3) ? true : false;
173
15.6k
  info->x86.sse41 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE41) ? true : false;
174
15.6k
  info->x86.sse42 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE42) ? true : false;
175
176
15.6k
  if (FLAC__AVX_SUPPORTED) {
177
15.6k
    x86_osxsave     = (flags_ecx & FLAC__CPUINFO_X86_CPUID_OSXSAVE) ? true : false;
178
15.6k
    info->x86.avx   = (flags_ecx & FLAC__CPUINFO_X86_CPUID_AVX    ) ? true : false;
179
15.6k
    info->x86.fma   = (flags_ecx & FLAC__CPUINFO_X86_CPUID_FMA    ) ? true : false;
180
15.6k
    cpuinfo_x86(7, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
181
15.6k
    info->x86.avx2  = (flags_ebx & FLAC__CPUINFO_X86_CPUID_AVX2   ) ? true : false;
182
15.6k
    info->x86.bmi2  = (flags_ebx & FLAC__CPUINFO_X86_CPUID_BMI2   ) ? true : false;
183
15.6k
  }
184
185
  /*
186
   * now have to check for OS support of AVX instructions
187
   */
188
15.6k
  if (FLAC__AVX_SUPPORTED && info->x86.avx && x86_osxsave && (cpu_xgetbv_x86() & 0x6) == 0x6) {
189
15.6k
    os_avx = true;
190
15.6k
  }
191
15.6k
  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
15.6k
}
201
202
void FLAC__cpu_info (FLAC__CPUInfo *info)
203
15.6k
{
204
15.6k
  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
15.6k
  switch (info->type) {
215
0
  case FLAC__CPUINFO_TYPE_IA32: /* fallthrough */
216
15.6k
  case FLAC__CPUINFO_TYPE_X86_64:
217
15.6k
    x86_cpu_info (info);
218
15.6k
    break;
219
0
  default:
220
    info->use_asm = false;
221
0
    break;
222
15.6k
  }
223
15.6k
}