• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

saitoha / libsixel / 20094101604

10 Dec 2025 09:40AM UTC coverage: 41.187% (+0.01%) from 41.176%
20094101604

push

github

saitoha
ci: shorten ci job labels

10821 of 40782 branches covered (26.53%)

14857 of 36072 relevant lines covered (41.19%)

2721494.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

70.0
/src/cpu.c
1
/*
2
 * SPDX-License-Identifier: MIT
3
 *
4
 * Copyright (c) 2025 libsixel developers. See `AUTHORS`.
5
 */
6

7
#include "config.h"
8

9
/* STDC_HEADERS */
10
#include <stdlib.h>
11

12
#if HAVE_INTRIN_H && \
13
    (defined(_WIN32) || defined(__x86_64__) || defined(_M_X64) || \
14
     defined(__i386) || defined(_M_IX86))
15
/* avoid cpuid.h macro clashes on Windows toolchains */
16
# include <intrin.h>
17
#endif
18
#if HAVE_CPUID_H && !defined(_WIN32) && \
19
    (defined(__x86_64__) || defined(__i386))
20
# include <cpuid.h>
21
#endif
22
#if defined(HAVE_IMMINTRIN_H) && \
23
    (defined(__x86_64__) || defined(_M_X64) || defined(__i386) || \
24
     defined(_M_IX86))
25
# include <immintrin.h>
26
#endif
27

28
#include "cpu.h"
29
#include "compat_stub.h"
30

31
static int simd_cached = -1;
32

33
static enum sixel_simd_level
34
sixel_cpu_env_cap(void)
140✔
35
{
36
    char const *env;
140✔
37

38
    env = sixel_compat_getenv("SIXEL_SIMD_LEVEL");
140✔
39
    if (env == NULL || env[0] == '\0') {
140!
40
        return SIXEL_SIMD_LEVEL_NEON;
25✔
41
    }
42
    if (sixel_compat_strcasecmp(env, "auto") == 0) {
×
43
        return SIXEL_SIMD_LEVEL_NEON;
44
    }
45
    if (sixel_compat_strcasecmp(env, "none") == 0 ||
×
46
        sixel_compat_strcasecmp(env, "scalar") == 0) {
×
47
        return SIXEL_SIMD_LEVEL_SCALAR;
×
48
    }
49
    if (sixel_compat_strcasecmp(env, "sse2") == 0) {
×
50
        return SIXEL_SIMD_LEVEL_SSE2;
51
    }
52
    if (sixel_compat_strcasecmp(env, "avx") == 0) {
×
53
        return SIXEL_SIMD_LEVEL_AVX;
54
    }
55
    if (sixel_compat_strcasecmp(env, "avx2") == 0) {
×
56
        return SIXEL_SIMD_LEVEL_AVX2;
57
    }
58
    if (sixel_compat_strcasecmp(env, "avx512") == 0) {
×
59
        return SIXEL_SIMD_LEVEL_AVX512;
60
    }
61
    if (sixel_compat_strcasecmp(env, "neon") == 0) {
×
62
        return SIXEL_SIMD_LEVEL_NEON;
63
    }
64
    return SIXEL_SIMD_LEVEL_NEON;
65
}
25✔
66

67
static enum sixel_simd_level
68
sixel_cpu_detect_native(void)
140✔
69
{
70
    enum sixel_simd_level level;
140✔
71

72
    level = SIXEL_SIMD_LEVEL_SCALAR;
140✔
73
#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || \
74
    defined(_M_IX86)
75
# if HAVE_BUILTIN_CPU_INIT && !defined(_MSC_VER)
76
    __builtin_cpu_init();
115✔
77
# endif
78
# if HAVE_BUILTIN_CPU_SUPPORTS && !defined(_MSC_VER)
79
    /*
80
     * clang-cl accepts __builtin_cpu_supports() but MSVC-style
81
     * toolchains do not ship the runtime helpers (e.g.
82
     * __cpu_indicator_init). Skip the builtin path there and use the
83
     * intrinsics-based detection instead.
84
     */
85
    if (__builtin_cpu_supports("avx512f")) {
115!
86
        level = SIXEL_SIMD_LEVEL_AVX512;
87
    } else if (__builtin_cpu_supports("avx2")) {
115!
88
        level = SIXEL_SIMD_LEVEL_AVX2;
89
    } else if (__builtin_cpu_supports("avx")) {
×
90
        level = SIXEL_SIMD_LEVEL_AVX;
91
    } else if (__builtin_cpu_supports("sse2")) {
×
92
        level = SIXEL_SIMD_LEVEL_SSE2;
93
    }
94
# elif defined(_MSC_VER) && HAVE_INTRIN_H
95
    int cpu_info[4];
96
    int osxsave;
97
    int avx_capable;
98

99
    __cpuid(cpu_info, 1);
100
    osxsave = (cpu_info[2] & (1 << 27));
101
    avx_capable = (cpu_info[2] & (1 << 28));
102
    if (osxsave && avx_capable) {
103
        unsigned long long xcr0;
104

105
        xcr0 = _xgetbv(0);
106
        if ((xcr0 & 0x6) == 0x6) {
107
            int extended[4];
108

109
            __cpuidex(extended, 7, 0);
110
            if ((extended[1] & (1 << 16)) != 0) {
111
                level = SIXEL_SIMD_LEVEL_AVX512;
112
            } else if ((extended[1] & (1 << 5)) != 0) {
113
                level = SIXEL_SIMD_LEVEL_AVX2;
114
            } else {
115
                level = SIXEL_SIMD_LEVEL_AVX;
116
            }
117
        }
118
    }
119
    if (level == SIXEL_SIMD_LEVEL_SCALAR && (cpu_info[3] & (1 << 26))) {
120
        level = SIXEL_SIMD_LEVEL_SSE2;
121
    }
122
# elif HAVE_CPUID_H
123
    unsigned int eax;
124
    unsigned int ebx;
125
    unsigned int ecx;
126
    unsigned int edx;
127

128
    if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) != 0) {
129
        if ((ecx & (1U << 28)) != 0) {
130
            if (__get_cpuid_max(0, NULL) >= 7 &&
131
                __get_cpuid_count(7, 0, &eax, &ebx, &ecx, &edx) != 0) {
132
                if ((ebx & (1U << 16)) != 0) {
133
                    level = SIXEL_SIMD_LEVEL_AVX512;
134
                } else if ((ebx & (1U << 5)) != 0) {
135
                    level = SIXEL_SIMD_LEVEL_AVX2;
136
                } else {
137
                    level = SIXEL_SIMD_LEVEL_AVX;
138
                }
139
            } else {
140
                level = SIXEL_SIMD_LEVEL_AVX;
141
            }
142
        } else if ((edx & (1U << 26)) != 0) {
143
            level = SIXEL_SIMD_LEVEL_SSE2;
144
        }
145
    }
146
# endif
147
#elif defined(__aarch64__) || defined(__ARM_NEON) || defined(__ARM_NEON__)
148
    level = SIXEL_SIMD_LEVEL_NEON;
25✔
149
#endif
150
    return level;
165✔
151
}
25✔
152

153
static enum sixel_simd_level
154
sixel_cpu_min(enum sixel_simd_level lhs, enum sixel_simd_level rhs)
140✔
155
{
156
    if (lhs < rhs) {
140!
157
        return lhs;
158
    }
159
    return rhs;
25✔
160
}
25✔
161

162
int
163
sixel_cpu_simd_level(void)
166✔
164
{
165
    enum sixel_simd_level env_cap;
166✔
166
    enum sixel_simd_level native;
166✔
167

168
    if (simd_cached >= 0) {
166!
169
        return simd_cached;
170
    }
171

172
    env_cap = sixel_cpu_env_cap();
140✔
173
    native = sixel_cpu_detect_native();
140✔
174
    simd_cached = (int)sixel_cpu_min(env_cap, native);
140✔
175
    return simd_cached;
140✔
176
}
25✔
177

178
void
179
sixel_cpu_reset_simd_cache(void)
×
180
{
181
    simd_cached = -1;
×
182
}
×
183

184
/* emacs Local Variables:      */
185
/* emacs mode: c               */
186
/* emacs tab-width: 4          */
187
/* emacs indent-tabs-mode: nil */
188
/* emacs c-basic-offset: 4     */
189
/* emacs End:                  */
190
/* vim: set expandtab ts=4 sts=4 sw=4 : */
191
/* EOF */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc