xref: /aosp_15_r20/external/libdav1d/tests/checkasm/checkasm.c (revision c09093415860a1c2373dacd84c4fde00c507cdfd)
1*c0909341SAndroid Build Coastguard Worker /*
2*c0909341SAndroid Build Coastguard Worker  * Copyright © 2018, VideoLAN and dav1d authors
3*c0909341SAndroid Build Coastguard Worker  * Copyright © 2018, Two Orioles, LLC
4*c0909341SAndroid Build Coastguard Worker  * All rights reserved.
5*c0909341SAndroid Build Coastguard Worker  *
6*c0909341SAndroid Build Coastguard Worker  * Redistribution and use in source and binary forms, with or without
7*c0909341SAndroid Build Coastguard Worker  * modification, are permitted provided that the following conditions are met:
8*c0909341SAndroid Build Coastguard Worker  *
9*c0909341SAndroid Build Coastguard Worker  * 1. Redistributions of source code must retain the above copyright notice, this
10*c0909341SAndroid Build Coastguard Worker  *    list of conditions and the following disclaimer.
11*c0909341SAndroid Build Coastguard Worker  *
12*c0909341SAndroid Build Coastguard Worker  * 2. Redistributions in binary form must reproduce the above copyright notice,
13*c0909341SAndroid Build Coastguard Worker  *    this list of conditions and the following disclaimer in the documentation
14*c0909341SAndroid Build Coastguard Worker  *    and/or other materials provided with the distribution.
15*c0909341SAndroid Build Coastguard Worker  *
16*c0909341SAndroid Build Coastguard Worker  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17*c0909341SAndroid Build Coastguard Worker  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18*c0909341SAndroid Build Coastguard Worker  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19*c0909341SAndroid Build Coastguard Worker  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20*c0909341SAndroid Build Coastguard Worker  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21*c0909341SAndroid Build Coastguard Worker  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22*c0909341SAndroid Build Coastguard Worker  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23*c0909341SAndroid Build Coastguard Worker  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24*c0909341SAndroid Build Coastguard Worker  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25*c0909341SAndroid Build Coastguard Worker  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*c0909341SAndroid Build Coastguard Worker  */
27*c0909341SAndroid Build Coastguard Worker #include "tests/checkasm/checkasm.h"
28*c0909341SAndroid Build Coastguard Worker 
29*c0909341SAndroid Build Coastguard Worker #include <errno.h>
30*c0909341SAndroid Build Coastguard Worker #include <math.h>
31*c0909341SAndroid Build Coastguard Worker #include <signal.h>
32*c0909341SAndroid Build Coastguard Worker #include <stdarg.h>
33*c0909341SAndroid Build Coastguard Worker #include <stdio.h>
34*c0909341SAndroid Build Coastguard Worker #include <string.h>
35*c0909341SAndroid Build Coastguard Worker 
36*c0909341SAndroid Build Coastguard Worker #include "src/cpu.h"
37*c0909341SAndroid Build Coastguard Worker 
38*c0909341SAndroid Build Coastguard Worker #ifdef _WIN32
39*c0909341SAndroid Build Coastguard Worker #ifndef SIGBUS
40*c0909341SAndroid Build Coastguard Worker /* non-standard, use the same value as mingw-w64 */
41*c0909341SAndroid Build Coastguard Worker #define SIGBUS 10
42*c0909341SAndroid Build Coastguard Worker #endif
43*c0909341SAndroid Build Coastguard Worker #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
44*c0909341SAndroid Build Coastguard Worker #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x04
45*c0909341SAndroid Build Coastguard Worker #endif
46*c0909341SAndroid Build Coastguard Worker #else
47*c0909341SAndroid Build Coastguard Worker #include <time.h>
48*c0909341SAndroid Build Coastguard Worker #if HAVE_UNISTD_H
49*c0909341SAndroid Build Coastguard Worker #include <unistd.h>
50*c0909341SAndroid Build Coastguard Worker #endif
51*c0909341SAndroid Build Coastguard Worker #if HAVE_PTHREAD_SETAFFINITY_NP
52*c0909341SAndroid Build Coastguard Worker #include <pthread.h>
53*c0909341SAndroid Build Coastguard Worker #if HAVE_PTHREAD_NP_H
54*c0909341SAndroid Build Coastguard Worker #include <pthread_np.h>
55*c0909341SAndroid Build Coastguard Worker #endif
56*c0909341SAndroid Build Coastguard Worker #endif
57*c0909341SAndroid Build Coastguard Worker #ifdef __APPLE__
58*c0909341SAndroid Build Coastguard Worker #include <mach/mach_time.h>
59*c0909341SAndroid Build Coastguard Worker #endif
60*c0909341SAndroid Build Coastguard Worker #endif
61*c0909341SAndroid Build Coastguard Worker #if CONFIG_MACOS_KPERF
62*c0909341SAndroid Build Coastguard Worker #include <dlfcn.h>
63*c0909341SAndroid Build Coastguard Worker #endif
64*c0909341SAndroid Build Coastguard Worker 
65*c0909341SAndroid Build Coastguard Worker #define COLOR_RED    31
66*c0909341SAndroid Build Coastguard Worker #define COLOR_GREEN  32
67*c0909341SAndroid Build Coastguard Worker #define COLOR_YELLOW 33
68*c0909341SAndroid Build Coastguard Worker 
69*c0909341SAndroid Build Coastguard Worker /* List of tests to invoke */
70*c0909341SAndroid Build Coastguard Worker static const struct {
71*c0909341SAndroid Build Coastguard Worker     const char *name;
72*c0909341SAndroid Build Coastguard Worker     void (*func)(void);
73*c0909341SAndroid Build Coastguard Worker } tests[] = {
74*c0909341SAndroid Build Coastguard Worker     { "msac", checkasm_check_msac },
75*c0909341SAndroid Build Coastguard Worker     { "pal", checkasm_check_pal },
76*c0909341SAndroid Build Coastguard Worker     { "refmvs", checkasm_check_refmvs },
77*c0909341SAndroid Build Coastguard Worker #if CONFIG_8BPC
78*c0909341SAndroid Build Coastguard Worker     { "cdef_8bpc", checkasm_check_cdef_8bpc },
79*c0909341SAndroid Build Coastguard Worker     { "filmgrain_8bpc", checkasm_check_filmgrain_8bpc },
80*c0909341SAndroid Build Coastguard Worker     { "ipred_8bpc", checkasm_check_ipred_8bpc },
81*c0909341SAndroid Build Coastguard Worker     { "itx_8bpc", checkasm_check_itx_8bpc },
82*c0909341SAndroid Build Coastguard Worker     { "loopfilter_8bpc", checkasm_check_loopfilter_8bpc },
83*c0909341SAndroid Build Coastguard Worker     { "looprestoration_8bpc", checkasm_check_looprestoration_8bpc },
84*c0909341SAndroid Build Coastguard Worker     { "mc_8bpc", checkasm_check_mc_8bpc },
85*c0909341SAndroid Build Coastguard Worker #endif
86*c0909341SAndroid Build Coastguard Worker #if CONFIG_16BPC
87*c0909341SAndroid Build Coastguard Worker     { "cdef_16bpc", checkasm_check_cdef_16bpc },
88*c0909341SAndroid Build Coastguard Worker     { "filmgrain_16bpc", checkasm_check_filmgrain_16bpc },
89*c0909341SAndroid Build Coastguard Worker     { "ipred_16bpc", checkasm_check_ipred_16bpc },
90*c0909341SAndroid Build Coastguard Worker     { "itx_16bpc", checkasm_check_itx_16bpc },
91*c0909341SAndroid Build Coastguard Worker     { "loopfilter_16bpc", checkasm_check_loopfilter_16bpc },
92*c0909341SAndroid Build Coastguard Worker     { "looprestoration_16bpc", checkasm_check_looprestoration_16bpc },
93*c0909341SAndroid Build Coastguard Worker     { "mc_16bpc", checkasm_check_mc_16bpc },
94*c0909341SAndroid Build Coastguard Worker #endif
95*c0909341SAndroid Build Coastguard Worker     { 0 }
96*c0909341SAndroid Build Coastguard Worker };
97*c0909341SAndroid Build Coastguard Worker 
98*c0909341SAndroid Build Coastguard Worker /* List of cpu flags to check */
99*c0909341SAndroid Build Coastguard Worker static const struct {
100*c0909341SAndroid Build Coastguard Worker     const char *name;
101*c0909341SAndroid Build Coastguard Worker     const char *suffix;
102*c0909341SAndroid Build Coastguard Worker     unsigned flag;
103*c0909341SAndroid Build Coastguard Worker } cpus[] = {
104*c0909341SAndroid Build Coastguard Worker #if ARCH_X86
105*c0909341SAndroid Build Coastguard Worker     { "SSE2",               "sse2",      DAV1D_X86_CPU_FLAG_SSE2 },
106*c0909341SAndroid Build Coastguard Worker     { "SSSE3",              "ssse3",     DAV1D_X86_CPU_FLAG_SSSE3 },
107*c0909341SAndroid Build Coastguard Worker     { "SSE4.1",             "sse4",      DAV1D_X86_CPU_FLAG_SSE41 },
108*c0909341SAndroid Build Coastguard Worker     { "AVX2",               "avx2",      DAV1D_X86_CPU_FLAG_AVX2 },
109*c0909341SAndroid Build Coastguard Worker     { "AVX-512 (Ice Lake)", "avx512icl", DAV1D_X86_CPU_FLAG_AVX512ICL },
110*c0909341SAndroid Build Coastguard Worker #elif ARCH_AARCH64 || ARCH_ARM
111*c0909341SAndroid Build Coastguard Worker     { "NEON",               "neon",      DAV1D_ARM_CPU_FLAG_NEON },
112*c0909341SAndroid Build Coastguard Worker     { "DOTPROD",            "dotprod",   DAV1D_ARM_CPU_FLAG_DOTPROD },
113*c0909341SAndroid Build Coastguard Worker     { "I8MM",               "i8mm",      DAV1D_ARM_CPU_FLAG_I8MM },
114*c0909341SAndroid Build Coastguard Worker #if ARCH_AARCH64
115*c0909341SAndroid Build Coastguard Worker     { "SVE",                "sve",       DAV1D_ARM_CPU_FLAG_SVE },
116*c0909341SAndroid Build Coastguard Worker     { "SVE2",               "sve2",      DAV1D_ARM_CPU_FLAG_SVE2 },
117*c0909341SAndroid Build Coastguard Worker #endif /* ARCH_AARCH64 */
118*c0909341SAndroid Build Coastguard Worker #elif ARCH_LOONGARCH
119*c0909341SAndroid Build Coastguard Worker     { "LSX",                "lsx",       DAV1D_LOONGARCH_CPU_FLAG_LSX },
120*c0909341SAndroid Build Coastguard Worker     { "LASX",               "lasx",      DAV1D_LOONGARCH_CPU_FLAG_LASX },
121*c0909341SAndroid Build Coastguard Worker #elif ARCH_PPC64LE
122*c0909341SAndroid Build Coastguard Worker     { "VSX",                "vsx",       DAV1D_PPC_CPU_FLAG_VSX },
123*c0909341SAndroid Build Coastguard Worker     { "PWR9",               "pwr9",      DAV1D_PPC_CPU_FLAG_PWR9 },
124*c0909341SAndroid Build Coastguard Worker #elif ARCH_RISCV
125*c0909341SAndroid Build Coastguard Worker     { "RVV",                "rvv",       DAV1D_RISCV_CPU_FLAG_V },
126*c0909341SAndroid Build Coastguard Worker #endif
127*c0909341SAndroid Build Coastguard Worker     { 0 }
128*c0909341SAndroid Build Coastguard Worker };
129*c0909341SAndroid Build Coastguard Worker 
130*c0909341SAndroid Build Coastguard Worker #if ARCH_AARCH64 && HAVE_SVE
131*c0909341SAndroid Build Coastguard Worker int checkasm_sve_length(void);
132*c0909341SAndroid Build Coastguard Worker #endif
133*c0909341SAndroid Build Coastguard Worker 
134*c0909341SAndroid Build Coastguard Worker typedef struct CheckasmFuncVersion {
135*c0909341SAndroid Build Coastguard Worker     struct CheckasmFuncVersion *next;
136*c0909341SAndroid Build Coastguard Worker     void *func;
137*c0909341SAndroid Build Coastguard Worker     int ok;
138*c0909341SAndroid Build Coastguard Worker     unsigned cpu;
139*c0909341SAndroid Build Coastguard Worker     int iterations;
140*c0909341SAndroid Build Coastguard Worker     uint64_t cycles;
141*c0909341SAndroid Build Coastguard Worker } CheckasmFuncVersion;
142*c0909341SAndroid Build Coastguard Worker 
143*c0909341SAndroid Build Coastguard Worker /* Binary search tree node */
144*c0909341SAndroid Build Coastguard Worker typedef struct CheckasmFunc {
145*c0909341SAndroid Build Coastguard Worker     struct CheckasmFunc *child[2];
146*c0909341SAndroid Build Coastguard Worker     CheckasmFuncVersion versions;
147*c0909341SAndroid Build Coastguard Worker     uint8_t color; /* 0 = red, 1 = black */
148*c0909341SAndroid Build Coastguard Worker     char name[];
149*c0909341SAndroid Build Coastguard Worker } CheckasmFunc;
150*c0909341SAndroid Build Coastguard Worker 
151*c0909341SAndroid Build Coastguard Worker typedef enum {
152*c0909341SAndroid Build Coastguard Worker     RUN_NORMAL = 0,
153*c0909341SAndroid Build Coastguard Worker     RUN_BENCHMARK,
154*c0909341SAndroid Build Coastguard Worker     RUN_CPUFLAG_LISTING,
155*c0909341SAndroid Build Coastguard Worker     RUN_FUNCTION_LISTING,
156*c0909341SAndroid Build Coastguard Worker } CheckasmRunMode;
157*c0909341SAndroid Build Coastguard Worker 
158*c0909341SAndroid Build Coastguard Worker /* Internal state */
159*c0909341SAndroid Build Coastguard Worker static struct {
160*c0909341SAndroid Build Coastguard Worker     CheckasmFunc *funcs;
161*c0909341SAndroid Build Coastguard Worker     CheckasmFunc *current_func;
162*c0909341SAndroid Build Coastguard Worker     CheckasmFuncVersion *current_func_ver;
163*c0909341SAndroid Build Coastguard Worker     const char *current_test_name;
164*c0909341SAndroid Build Coastguard Worker     int num_checked;
165*c0909341SAndroid Build Coastguard Worker     int num_failed;
166*c0909341SAndroid Build Coastguard Worker     double nop_time;
167*c0909341SAndroid Build Coastguard Worker     unsigned cpu_flag;
168*c0909341SAndroid Build Coastguard Worker     const char *cpu_flag_name;
169*c0909341SAndroid Build Coastguard Worker     const char *test_pattern;
170*c0909341SAndroid Build Coastguard Worker     const char *function_pattern;
171*c0909341SAndroid Build Coastguard Worker     unsigned seed;
172*c0909341SAndroid Build Coastguard Worker     CheckasmRunMode run_mode;
173*c0909341SAndroid Build Coastguard Worker     int verbose;
174*c0909341SAndroid Build Coastguard Worker     volatile sig_atomic_t sig; // SIG_ATOMIC_MAX = signal handling enabled
175*c0909341SAndroid Build Coastguard Worker     int suffix_length;
176*c0909341SAndroid Build Coastguard Worker     int max_function_name_length;
177*c0909341SAndroid Build Coastguard Worker #if ARCH_X86_64
178*c0909341SAndroid Build Coastguard Worker     void (*simd_warmup)(void);
179*c0909341SAndroid Build Coastguard Worker #endif
180*c0909341SAndroid Build Coastguard Worker } state;
181*c0909341SAndroid Build Coastguard Worker 
182*c0909341SAndroid Build Coastguard Worker /* float compare support code */
183*c0909341SAndroid Build Coastguard Worker typedef union {
184*c0909341SAndroid Build Coastguard Worker     float f;
185*c0909341SAndroid Build Coastguard Worker     uint32_t i;
186*c0909341SAndroid Build Coastguard Worker } intfloat;
187*c0909341SAndroid Build Coastguard Worker 
188*c0909341SAndroid Build Coastguard Worker static uint32_t xs_state[4];
189*c0909341SAndroid Build Coastguard Worker 
xor128_srand(unsigned seed)190*c0909341SAndroid Build Coastguard Worker static void xor128_srand(unsigned seed) {
191*c0909341SAndroid Build Coastguard Worker     xs_state[0] = seed;
192*c0909341SAndroid Build Coastguard Worker     xs_state[1] = ( seed & 0xffff0000) | (~seed & 0x0000ffff);
193*c0909341SAndroid Build Coastguard Worker     xs_state[2] = (~seed & 0xffff0000) | ( seed & 0x0000ffff);
194*c0909341SAndroid Build Coastguard Worker     xs_state[3] = ~seed;
195*c0909341SAndroid Build Coastguard Worker }
196*c0909341SAndroid Build Coastguard Worker 
197*c0909341SAndroid Build Coastguard Worker // xor128 from Marsaglia, George (July 2003). "Xorshift RNGs".
198*c0909341SAndroid Build Coastguard Worker //             Journal of Statistical Software. 8 (14).
199*c0909341SAndroid Build Coastguard Worker //             doi:10.18637/jss.v008.i14.
xor128_rand(void)200*c0909341SAndroid Build Coastguard Worker int xor128_rand(void) {
201*c0909341SAndroid Build Coastguard Worker     const uint32_t x = xs_state[0];
202*c0909341SAndroid Build Coastguard Worker     const uint32_t t = x ^ (x << 11);
203*c0909341SAndroid Build Coastguard Worker 
204*c0909341SAndroid Build Coastguard Worker     xs_state[0] = xs_state[1];
205*c0909341SAndroid Build Coastguard Worker     xs_state[1] = xs_state[2];
206*c0909341SAndroid Build Coastguard Worker     xs_state[2] = xs_state[3];
207*c0909341SAndroid Build Coastguard Worker     uint32_t w = xs_state[3];
208*c0909341SAndroid Build Coastguard Worker 
209*c0909341SAndroid Build Coastguard Worker     w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
210*c0909341SAndroid Build Coastguard Worker     xs_state[3] = w;
211*c0909341SAndroid Build Coastguard Worker 
212*c0909341SAndroid Build Coastguard Worker     return w >> 1;
213*c0909341SAndroid Build Coastguard Worker }
214*c0909341SAndroid Build Coastguard Worker 
215*c0909341SAndroid Build Coastguard Worker #if CONFIG_MACOS_KPERF
216*c0909341SAndroid Build Coastguard Worker 
217*c0909341SAndroid Build Coastguard Worker static int (*kpc_get_thread_counters)(int, unsigned int, void *);
218*c0909341SAndroid Build Coastguard Worker 
219*c0909341SAndroid Build Coastguard Worker #define CFGWORD_EL0A64EN_MASK (0x20000)
220*c0909341SAndroid Build Coastguard Worker 
221*c0909341SAndroid Build Coastguard Worker #define CPMU_CORE_CYCLE 0x02
222*c0909341SAndroid Build Coastguard Worker 
223*c0909341SAndroid Build Coastguard Worker #define KPC_CLASS_FIXED_MASK        (1 << 0)
224*c0909341SAndroid Build Coastguard Worker #define KPC_CLASS_CONFIGURABLE_MASK (1 << 1)
225*c0909341SAndroid Build Coastguard Worker 
226*c0909341SAndroid Build Coastguard Worker #define COUNTERS_COUNT 10
227*c0909341SAndroid Build Coastguard Worker #define CONFIG_COUNT 8
228*c0909341SAndroid Build Coastguard Worker #define KPC_MASK (KPC_CLASS_CONFIGURABLE_MASK | KPC_CLASS_FIXED_MASK)
229*c0909341SAndroid Build Coastguard Worker 
kperf_init(void)230*c0909341SAndroid Build Coastguard Worker static int kperf_init(void) {
231*c0909341SAndroid Build Coastguard Worker     uint64_t config[COUNTERS_COUNT] = { 0 };
232*c0909341SAndroid Build Coastguard Worker 
233*c0909341SAndroid Build Coastguard Worker     void *kperf = dlopen("/System/Library/PrivateFrameworks/kperf.framework/kperf", RTLD_LAZY);
234*c0909341SAndroid Build Coastguard Worker     if (!kperf) {
235*c0909341SAndroid Build Coastguard Worker         fprintf(stderr, "checkasm: Unable to load kperf: %s\n", dlerror());
236*c0909341SAndroid Build Coastguard Worker         return 1;
237*c0909341SAndroid Build Coastguard Worker     }
238*c0909341SAndroid Build Coastguard Worker 
239*c0909341SAndroid Build Coastguard Worker     int (*kpc_force_all_ctrs_set)(int) = dlsym(kperf, "kpc_force_all_ctrs_set");
240*c0909341SAndroid Build Coastguard Worker     int (*kpc_set_counting)(uint32_t) = dlsym(kperf, "kpc_set_counting");
241*c0909341SAndroid Build Coastguard Worker     int (*kpc_set_thread_counting)(uint32_t) = dlsym(kperf, "kpc_set_thread_counting");
242*c0909341SAndroid Build Coastguard Worker     int (*kpc_set_config)(uint32_t, void *) = dlsym(kperf, "kpc_set_config");
243*c0909341SAndroid Build Coastguard Worker     uint32_t (*kpc_get_counter_count)(uint32_t) = dlsym(kperf, "kpc_get_counter_count");
244*c0909341SAndroid Build Coastguard Worker     uint32_t (*kpc_get_config_count)(uint32_t) = dlsym(kperf, "kpc_get_config_count");
245*c0909341SAndroid Build Coastguard Worker     kpc_get_thread_counters = dlsym(kperf, "kpc_get_thread_counters");
246*c0909341SAndroid Build Coastguard Worker 
247*c0909341SAndroid Build Coastguard Worker     if (!kpc_get_thread_counters) {
248*c0909341SAndroid Build Coastguard Worker         fprintf(stderr, "checkasm: Unable to load kpc_get_thread_counters\n");
249*c0909341SAndroid Build Coastguard Worker         return 1;
250*c0909341SAndroid Build Coastguard Worker     }
251*c0909341SAndroid Build Coastguard Worker 
252*c0909341SAndroid Build Coastguard Worker     if (!kpc_get_counter_count || kpc_get_counter_count(KPC_MASK) != COUNTERS_COUNT) {
253*c0909341SAndroid Build Coastguard Worker         fprintf(stderr, "checkasm: Unxpected kpc_get_counter_count\n");
254*c0909341SAndroid Build Coastguard Worker         return 1;
255*c0909341SAndroid Build Coastguard Worker     }
256*c0909341SAndroid Build Coastguard Worker     if (!kpc_get_config_count || kpc_get_config_count(KPC_MASK) != CONFIG_COUNT) {
257*c0909341SAndroid Build Coastguard Worker         fprintf(stderr, "checkasm: Unxpected kpc_get_config_count\n");
258*c0909341SAndroid Build Coastguard Worker         return 1;
259*c0909341SAndroid Build Coastguard Worker     }
260*c0909341SAndroid Build Coastguard Worker 
261*c0909341SAndroid Build Coastguard Worker     config[0] = CPMU_CORE_CYCLE | CFGWORD_EL0A64EN_MASK;
262*c0909341SAndroid Build Coastguard Worker 
263*c0909341SAndroid Build Coastguard Worker     if (!kpc_set_config || kpc_set_config(KPC_MASK, config)) {
264*c0909341SAndroid Build Coastguard Worker         fprintf(stderr, "checkasm: The kperf API needs to be run as root\n");
265*c0909341SAndroid Build Coastguard Worker         return 1;
266*c0909341SAndroid Build Coastguard Worker     }
267*c0909341SAndroid Build Coastguard Worker     if (!kpc_force_all_ctrs_set || kpc_force_all_ctrs_set(1)) {
268*c0909341SAndroid Build Coastguard Worker         fprintf(stderr, "checkasm: kpc_force_all_ctrs_set failed\n");
269*c0909341SAndroid Build Coastguard Worker         return 1;
270*c0909341SAndroid Build Coastguard Worker     }
271*c0909341SAndroid Build Coastguard Worker     if (!kpc_set_counting || kpc_set_counting(KPC_MASK)) {
272*c0909341SAndroid Build Coastguard Worker         fprintf(stderr, "checkasm: kpc_set_counting failed\n");
273*c0909341SAndroid Build Coastguard Worker         return 1;
274*c0909341SAndroid Build Coastguard Worker     }
275*c0909341SAndroid Build Coastguard Worker     if (!kpc_set_counting || kpc_set_thread_counting(KPC_MASK)) {
276*c0909341SAndroid Build Coastguard Worker         fprintf(stderr, "checkasm: kpc_set_thread_counting failed\n");
277*c0909341SAndroid Build Coastguard Worker         return 1;
278*c0909341SAndroid Build Coastguard Worker     }
279*c0909341SAndroid Build Coastguard Worker     return 0;
280*c0909341SAndroid Build Coastguard Worker }
281*c0909341SAndroid Build Coastguard Worker 
checkasm_kperf_cycles(void)282*c0909341SAndroid Build Coastguard Worker uint64_t checkasm_kperf_cycles(void) {
283*c0909341SAndroid Build Coastguard Worker     uint64_t counters[COUNTERS_COUNT];
284*c0909341SAndroid Build Coastguard Worker     if (kpc_get_thread_counters(0, COUNTERS_COUNT, counters))
285*c0909341SAndroid Build Coastguard Worker         return -1;
286*c0909341SAndroid Build Coastguard Worker 
287*c0909341SAndroid Build Coastguard Worker     return counters[0];
288*c0909341SAndroid Build Coastguard Worker }
289*c0909341SAndroid Build Coastguard Worker #endif
290*c0909341SAndroid Build Coastguard Worker 
is_negative(const intfloat u)291*c0909341SAndroid Build Coastguard Worker static int is_negative(const intfloat u) {
292*c0909341SAndroid Build Coastguard Worker     return u.i >> 31;
293*c0909341SAndroid Build Coastguard Worker }
294*c0909341SAndroid Build Coastguard Worker 
float_near_ulp(const float a,const float b,const unsigned max_ulp)295*c0909341SAndroid Build Coastguard Worker int float_near_ulp(const float a, const float b, const unsigned max_ulp) {
296*c0909341SAndroid Build Coastguard Worker     intfloat x, y;
297*c0909341SAndroid Build Coastguard Worker 
298*c0909341SAndroid Build Coastguard Worker     x.f = a;
299*c0909341SAndroid Build Coastguard Worker     y.f = b;
300*c0909341SAndroid Build Coastguard Worker 
301*c0909341SAndroid Build Coastguard Worker     if (is_negative(x) != is_negative(y)) {
302*c0909341SAndroid Build Coastguard Worker         // handle -0.0 == +0.0
303*c0909341SAndroid Build Coastguard Worker         return a == b;
304*c0909341SAndroid Build Coastguard Worker     }
305*c0909341SAndroid Build Coastguard Worker 
306*c0909341SAndroid Build Coastguard Worker     if (llabs((int64_t)x.i - y.i) <= max_ulp)
307*c0909341SAndroid Build Coastguard Worker         return 1;
308*c0909341SAndroid Build Coastguard Worker 
309*c0909341SAndroid Build Coastguard Worker     return 0;
310*c0909341SAndroid Build Coastguard Worker }
311*c0909341SAndroid Build Coastguard Worker 
float_near_ulp_array(const float * const a,const float * const b,const unsigned max_ulp,const int len)312*c0909341SAndroid Build Coastguard Worker int float_near_ulp_array(const float *const a, const float *const b,
313*c0909341SAndroid Build Coastguard Worker                          const unsigned max_ulp, const int len)
314*c0909341SAndroid Build Coastguard Worker {
315*c0909341SAndroid Build Coastguard Worker     for (int i = 0; i < len; i++)
316*c0909341SAndroid Build Coastguard Worker         if (!float_near_ulp(a[i], b[i], max_ulp))
317*c0909341SAndroid Build Coastguard Worker             return 0;
318*c0909341SAndroid Build Coastguard Worker 
319*c0909341SAndroid Build Coastguard Worker     return 1;
320*c0909341SAndroid Build Coastguard Worker }
321*c0909341SAndroid Build Coastguard Worker 
float_near_abs_eps(const float a,const float b,const float eps)322*c0909341SAndroid Build Coastguard Worker int float_near_abs_eps(const float a, const float b, const float eps) {
323*c0909341SAndroid Build Coastguard Worker     return fabsf(a - b) < eps;
324*c0909341SAndroid Build Coastguard Worker }
325*c0909341SAndroid Build Coastguard Worker 
float_near_abs_eps_array(const float * const a,const float * const b,const float eps,const int len)326*c0909341SAndroid Build Coastguard Worker int float_near_abs_eps_array(const float *const a, const float *const b,
327*c0909341SAndroid Build Coastguard Worker                              const float eps, const int len)
328*c0909341SAndroid Build Coastguard Worker {
329*c0909341SAndroid Build Coastguard Worker     for (int i = 0; i < len; i++)
330*c0909341SAndroid Build Coastguard Worker         if (!float_near_abs_eps(a[i], b[i], eps))
331*c0909341SAndroid Build Coastguard Worker             return 0;
332*c0909341SAndroid Build Coastguard Worker 
333*c0909341SAndroid Build Coastguard Worker     return 1;
334*c0909341SAndroid Build Coastguard Worker }
335*c0909341SAndroid Build Coastguard Worker 
float_near_abs_eps_ulp(const float a,const float b,const float eps,const unsigned max_ulp)336*c0909341SAndroid Build Coastguard Worker int float_near_abs_eps_ulp(const float a, const float b, const float eps,
337*c0909341SAndroid Build Coastguard Worker                            const unsigned max_ulp)
338*c0909341SAndroid Build Coastguard Worker {
339*c0909341SAndroid Build Coastguard Worker     return float_near_ulp(a, b, max_ulp) || float_near_abs_eps(a, b, eps);
340*c0909341SAndroid Build Coastguard Worker }
341*c0909341SAndroid Build Coastguard Worker 
float_near_abs_eps_array_ulp(const float * const a,const float * const b,const float eps,const unsigned max_ulp,const int len)342*c0909341SAndroid Build Coastguard Worker int float_near_abs_eps_array_ulp(const float *const a, const float *const b,
343*c0909341SAndroid Build Coastguard Worker                                  const float eps, const unsigned max_ulp,
344*c0909341SAndroid Build Coastguard Worker                                  const int len)
345*c0909341SAndroid Build Coastguard Worker {
346*c0909341SAndroid Build Coastguard Worker     for (int i = 0; i < len; i++)
347*c0909341SAndroid Build Coastguard Worker         if (!float_near_abs_eps_ulp(a[i], b[i], eps, max_ulp))
348*c0909341SAndroid Build Coastguard Worker             return 0;
349*c0909341SAndroid Build Coastguard Worker 
350*c0909341SAndroid Build Coastguard Worker     return 1;
351*c0909341SAndroid Build Coastguard Worker }
352*c0909341SAndroid Build Coastguard Worker 
353*c0909341SAndroid Build Coastguard Worker /* Print colored text to stderr if the terminal supports it */
354*c0909341SAndroid Build Coastguard Worker static int use_printf_color;
color_fprintf(FILE * const f,const int color,const char * const fmt,...)355*c0909341SAndroid Build Coastguard Worker static void color_fprintf(FILE *const f, const int color, const char *const fmt, ...) {
356*c0909341SAndroid Build Coastguard Worker     va_list arg;
357*c0909341SAndroid Build Coastguard Worker 
358*c0909341SAndroid Build Coastguard Worker     if (use_printf_color)
359*c0909341SAndroid Build Coastguard Worker         fprintf(f, "\x1b[0;%dm", color);
360*c0909341SAndroid Build Coastguard Worker 
361*c0909341SAndroid Build Coastguard Worker     va_start(arg, fmt);
362*c0909341SAndroid Build Coastguard Worker     vfprintf(f, fmt, arg);
363*c0909341SAndroid Build Coastguard Worker     va_end(arg);
364*c0909341SAndroid Build Coastguard Worker 
365*c0909341SAndroid Build Coastguard Worker     if (use_printf_color)
366*c0909341SAndroid Build Coastguard Worker         fprintf(f, "\x1b[0m");
367*c0909341SAndroid Build Coastguard Worker }
368*c0909341SAndroid Build Coastguard Worker 
369*c0909341SAndroid Build Coastguard Worker /* Deallocate a tree */
destroy_func_tree(CheckasmFunc * const f)370*c0909341SAndroid Build Coastguard Worker static void destroy_func_tree(CheckasmFunc *const f) {
371*c0909341SAndroid Build Coastguard Worker     if (f) {
372*c0909341SAndroid Build Coastguard Worker         CheckasmFuncVersion *v = f->versions.next;
373*c0909341SAndroid Build Coastguard Worker         while (v) {
374*c0909341SAndroid Build Coastguard Worker             CheckasmFuncVersion *next = v->next;
375*c0909341SAndroid Build Coastguard Worker             free(v);
376*c0909341SAndroid Build Coastguard Worker             v = next;
377*c0909341SAndroid Build Coastguard Worker         }
378*c0909341SAndroid Build Coastguard Worker 
379*c0909341SAndroid Build Coastguard Worker         destroy_func_tree(f->child[0]);
380*c0909341SAndroid Build Coastguard Worker         destroy_func_tree(f->child[1]);
381*c0909341SAndroid Build Coastguard Worker         free(f);
382*c0909341SAndroid Build Coastguard Worker     }
383*c0909341SAndroid Build Coastguard Worker }
384*c0909341SAndroid Build Coastguard Worker 
385*c0909341SAndroid Build Coastguard Worker /* Allocate a zero-initialized block, clean up and exit on failure */
checkasm_malloc(const size_t size)386*c0909341SAndroid Build Coastguard Worker static void *checkasm_malloc(const size_t size) {
387*c0909341SAndroid Build Coastguard Worker     void *const ptr = calloc(1, size);
388*c0909341SAndroid Build Coastguard Worker     if (!ptr) {
389*c0909341SAndroid Build Coastguard Worker         fprintf(stderr, "checkasm: malloc failed\n");
390*c0909341SAndroid Build Coastguard Worker         destroy_func_tree(state.funcs);
391*c0909341SAndroid Build Coastguard Worker         exit(1);
392*c0909341SAndroid Build Coastguard Worker     }
393*c0909341SAndroid Build Coastguard Worker     return ptr;
394*c0909341SAndroid Build Coastguard Worker }
395*c0909341SAndroid Build Coastguard Worker 
396*c0909341SAndroid Build Coastguard Worker /* Get the suffix of the specified cpu flag */
cpu_suffix(const unsigned cpu)397*c0909341SAndroid Build Coastguard Worker static const char *cpu_suffix(const unsigned cpu) {
398*c0909341SAndroid Build Coastguard Worker     for (int i = (int)(sizeof(cpus) / sizeof(*cpus)) - 2; i >= 0; i--)
399*c0909341SAndroid Build Coastguard Worker         if (cpu & cpus[i].flag)
400*c0909341SAndroid Build Coastguard Worker             return cpus[i].suffix;
401*c0909341SAndroid Build Coastguard Worker 
402*c0909341SAndroid Build Coastguard Worker     return "c";
403*c0909341SAndroid Build Coastguard Worker }
404*c0909341SAndroid Build Coastguard Worker 
405*c0909341SAndroid Build Coastguard Worker #ifdef readtime
cmp_nop(const void * a,const void * b)406*c0909341SAndroid Build Coastguard Worker static int cmp_nop(const void *a, const void *b) {
407*c0909341SAndroid Build Coastguard Worker     return *(const uint16_t*)a - *(const uint16_t*)b;
408*c0909341SAndroid Build Coastguard Worker }
409*c0909341SAndroid Build Coastguard Worker 
410*c0909341SAndroid Build Coastguard Worker /* Measure the overhead of the timing code (in decicycles) */
measure_nop_time(void)411*c0909341SAndroid Build Coastguard Worker static double measure_nop_time(void) {
412*c0909341SAndroid Build Coastguard Worker     uint16_t nops[10000];
413*c0909341SAndroid Build Coastguard Worker     int nop_sum = 0;
414*c0909341SAndroid Build Coastguard Worker 
415*c0909341SAndroid Build Coastguard Worker     for (int i = 0; i < 10000; i++) {
416*c0909341SAndroid Build Coastguard Worker         uint64_t t = readtime();
417*c0909341SAndroid Build Coastguard Worker         nops[i] = (uint16_t) (readtime() - t);
418*c0909341SAndroid Build Coastguard Worker     }
419*c0909341SAndroid Build Coastguard Worker 
420*c0909341SAndroid Build Coastguard Worker     qsort(nops, 10000, sizeof(uint16_t), cmp_nop);
421*c0909341SAndroid Build Coastguard Worker     for (int i = 2500; i < 7500; i++)
422*c0909341SAndroid Build Coastguard Worker         nop_sum += nops[i];
423*c0909341SAndroid Build Coastguard Worker 
424*c0909341SAndroid Build Coastguard Worker     return nop_sum / 5000.0;
425*c0909341SAndroid Build Coastguard Worker }
426*c0909341SAndroid Build Coastguard Worker 
avg_cycles_per_call(const CheckasmFuncVersion * const v)427*c0909341SAndroid Build Coastguard Worker static double avg_cycles_per_call(const CheckasmFuncVersion *const v) {
428*c0909341SAndroid Build Coastguard Worker     if (v->iterations) {
429*c0909341SAndroid Build Coastguard Worker         const double cycles = (double)v->cycles / v->iterations - state.nop_time;
430*c0909341SAndroid Build Coastguard Worker         if (cycles > 0.0)
431*c0909341SAndroid Build Coastguard Worker             return cycles / 4.0; /* 4 calls per iteration */
432*c0909341SAndroid Build Coastguard Worker     }
433*c0909341SAndroid Build Coastguard Worker     return 0.0;
434*c0909341SAndroid Build Coastguard Worker }
435*c0909341SAndroid Build Coastguard Worker 
436*c0909341SAndroid Build Coastguard Worker /* Print benchmark results */
print_benchs(const CheckasmFunc * const f)437*c0909341SAndroid Build Coastguard Worker static void print_benchs(const CheckasmFunc *const f) {
438*c0909341SAndroid Build Coastguard Worker     if (f) {
439*c0909341SAndroid Build Coastguard Worker         print_benchs(f->child[0]);
440*c0909341SAndroid Build Coastguard Worker 
441*c0909341SAndroid Build Coastguard Worker         /* Only print functions with at least one assembly version */
442*c0909341SAndroid Build Coastguard Worker         const CheckasmFuncVersion *v = &f->versions;
443*c0909341SAndroid Build Coastguard Worker         if (v->iterations) {
444*c0909341SAndroid Build Coastguard Worker             const double baseline = avg_cycles_per_call(v);
445*c0909341SAndroid Build Coastguard Worker             do {
446*c0909341SAndroid Build Coastguard Worker                 const int pad_length = 10 + state.max_function_name_length -
447*c0909341SAndroid Build Coastguard Worker                     printf("%s_%s:", f->name, cpu_suffix(v->cpu));
448*c0909341SAndroid Build Coastguard Worker                 const double cycles = avg_cycles_per_call(v);
449*c0909341SAndroid Build Coastguard Worker                 const double ratio = cycles ? baseline / cycles : 0.0;
450*c0909341SAndroid Build Coastguard Worker                 printf("%*.1f (%5.2fx)\n", imax(pad_length, 0), cycles, ratio);
451*c0909341SAndroid Build Coastguard Worker             } while ((v = v->next));
452*c0909341SAndroid Build Coastguard Worker         }
453*c0909341SAndroid Build Coastguard Worker 
454*c0909341SAndroid Build Coastguard Worker         print_benchs(f->child[1]);
455*c0909341SAndroid Build Coastguard Worker     }
456*c0909341SAndroid Build Coastguard Worker }
457*c0909341SAndroid Build Coastguard Worker #endif
458*c0909341SAndroid Build Coastguard Worker 
print_functions(const CheckasmFunc * const f)459*c0909341SAndroid Build Coastguard Worker static void print_functions(const CheckasmFunc *const f) {
460*c0909341SAndroid Build Coastguard Worker     if (f) {
461*c0909341SAndroid Build Coastguard Worker         print_functions(f->child[0]);
462*c0909341SAndroid Build Coastguard Worker         const CheckasmFuncVersion *v = &f->versions;
463*c0909341SAndroid Build Coastguard Worker         printf("%s (%s", f->name, cpu_suffix(v->cpu));
464*c0909341SAndroid Build Coastguard Worker         while ((v = v->next))
465*c0909341SAndroid Build Coastguard Worker             printf(", %s", cpu_suffix(v->cpu));
466*c0909341SAndroid Build Coastguard Worker         printf(")\n");
467*c0909341SAndroid Build Coastguard Worker         print_functions(f->child[1]);
468*c0909341SAndroid Build Coastguard Worker     }
469*c0909341SAndroid Build Coastguard Worker }
470*c0909341SAndroid Build Coastguard Worker 
471*c0909341SAndroid Build Coastguard Worker #define is_digit(x) ((x) >= '0' && (x) <= '9')
472*c0909341SAndroid Build Coastguard Worker 
473*c0909341SAndroid Build Coastguard Worker /* ASCIIbetical sort except preserving natural order for numbers */
cmp_func_names(const char * a,const char * b)474*c0909341SAndroid Build Coastguard Worker static int cmp_func_names(const char *a, const char *b) {
475*c0909341SAndroid Build Coastguard Worker     const char *const start = a;
476*c0909341SAndroid Build Coastguard Worker     int ascii_diff, digit_diff;
477*c0909341SAndroid Build Coastguard Worker 
478*c0909341SAndroid Build Coastguard Worker     for (; !(ascii_diff = *(const unsigned char*)a -
479*c0909341SAndroid Build Coastguard Worker                           *(const unsigned char*)b) && *a; a++, b++);
480*c0909341SAndroid Build Coastguard Worker     for (; is_digit(*a) && is_digit(*b); a++, b++);
481*c0909341SAndroid Build Coastguard Worker 
482*c0909341SAndroid Build Coastguard Worker     if (a > start && is_digit(a[-1]) &&
483*c0909341SAndroid Build Coastguard Worker         (digit_diff = is_digit(*a) - is_digit(*b)))
484*c0909341SAndroid Build Coastguard Worker     {
485*c0909341SAndroid Build Coastguard Worker         return digit_diff;
486*c0909341SAndroid Build Coastguard Worker     }
487*c0909341SAndroid Build Coastguard Worker 
488*c0909341SAndroid Build Coastguard Worker     return ascii_diff;
489*c0909341SAndroid Build Coastguard Worker }
490*c0909341SAndroid Build Coastguard Worker 
491*c0909341SAndroid Build Coastguard Worker /* Perform a tree rotation in the specified direction and return the new root */
rotate_tree(CheckasmFunc * const f,const int dir)492*c0909341SAndroid Build Coastguard Worker static CheckasmFunc *rotate_tree(CheckasmFunc *const f, const int dir) {
493*c0909341SAndroid Build Coastguard Worker     CheckasmFunc *const r = f->child[dir^1];
494*c0909341SAndroid Build Coastguard Worker     f->child[dir^1] = r->child[dir];
495*c0909341SAndroid Build Coastguard Worker     r->child[dir] = f;
496*c0909341SAndroid Build Coastguard Worker     r->color = f->color;
497*c0909341SAndroid Build Coastguard Worker     f->color = 0;
498*c0909341SAndroid Build Coastguard Worker     return r;
499*c0909341SAndroid Build Coastguard Worker }
500*c0909341SAndroid Build Coastguard Worker 
501*c0909341SAndroid Build Coastguard Worker #define is_red(f) ((f) && !(f)->color)
502*c0909341SAndroid Build Coastguard Worker 
503*c0909341SAndroid Build Coastguard Worker /* Balance a left-leaning red-black tree at the specified node */
balance_tree(CheckasmFunc ** const root)504*c0909341SAndroid Build Coastguard Worker static void balance_tree(CheckasmFunc **const root) {
505*c0909341SAndroid Build Coastguard Worker     CheckasmFunc *const f = *root;
506*c0909341SAndroid Build Coastguard Worker 
507*c0909341SAndroid Build Coastguard Worker     if (is_red(f->child[0]) && is_red(f->child[1])) {
508*c0909341SAndroid Build Coastguard Worker         f->color ^= 1;
509*c0909341SAndroid Build Coastguard Worker         f->child[0]->color = f->child[1]->color = 1;
510*c0909341SAndroid Build Coastguard Worker     }
511*c0909341SAndroid Build Coastguard Worker     else if (!is_red(f->child[0]) && is_red(f->child[1]))
512*c0909341SAndroid Build Coastguard Worker         *root = rotate_tree(f, 0); /* Rotate left */
513*c0909341SAndroid Build Coastguard Worker     else if (is_red(f->child[0]) && is_red(f->child[0]->child[0]))
514*c0909341SAndroid Build Coastguard Worker         *root = rotate_tree(f, 1); /* Rotate right */
515*c0909341SAndroid Build Coastguard Worker }
516*c0909341SAndroid Build Coastguard Worker 
517*c0909341SAndroid Build Coastguard Worker /* Get a node with the specified name, creating it if it doesn't exist */
get_func(CheckasmFunc ** const root,const char * const name)518*c0909341SAndroid Build Coastguard Worker static CheckasmFunc *get_func(CheckasmFunc **const root, const char *const name) {
519*c0909341SAndroid Build Coastguard Worker     CheckasmFunc *f = *root;
520*c0909341SAndroid Build Coastguard Worker 
521*c0909341SAndroid Build Coastguard Worker     if (f) {
522*c0909341SAndroid Build Coastguard Worker         /* Search the tree for a matching node */
523*c0909341SAndroid Build Coastguard Worker         const int cmp = cmp_func_names(name, f->name);
524*c0909341SAndroid Build Coastguard Worker         if (cmp) {
525*c0909341SAndroid Build Coastguard Worker             f = get_func(&f->child[cmp > 0], name);
526*c0909341SAndroid Build Coastguard Worker 
527*c0909341SAndroid Build Coastguard Worker             /* Rebalance the tree on the way up if a new node was inserted */
528*c0909341SAndroid Build Coastguard Worker             if (!f->versions.func)
529*c0909341SAndroid Build Coastguard Worker                 balance_tree(root);
530*c0909341SAndroid Build Coastguard Worker         }
531*c0909341SAndroid Build Coastguard Worker     } else {
532*c0909341SAndroid Build Coastguard Worker         /* Allocate and insert a new node into the tree */
533*c0909341SAndroid Build Coastguard Worker         const size_t name_length = strlen(name) + 1;
534*c0909341SAndroid Build Coastguard Worker         f = *root = checkasm_malloc(offsetof(CheckasmFunc, name) + name_length);
535*c0909341SAndroid Build Coastguard Worker         memcpy(f->name, name, name_length);
536*c0909341SAndroid Build Coastguard Worker     }
537*c0909341SAndroid Build Coastguard Worker 
538*c0909341SAndroid Build Coastguard Worker     return f;
539*c0909341SAndroid Build Coastguard Worker }
540*c0909341SAndroid Build Coastguard Worker 
541*c0909341SAndroid Build Coastguard Worker checkasm_context checkasm_context_buf;
542*c0909341SAndroid Build Coastguard Worker 
543*c0909341SAndroid Build Coastguard Worker /* Crash handling: attempt to catch crashes and handle them
544*c0909341SAndroid Build Coastguard Worker  * gracefully instead of just aborting abruptly. */
545*c0909341SAndroid Build Coastguard Worker #ifdef _WIN32
546*c0909341SAndroid Build Coastguard Worker #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
signal_handler(EXCEPTION_POINTERS * const e)547*c0909341SAndroid Build Coastguard Worker static LONG NTAPI signal_handler(EXCEPTION_POINTERS *const e) {
548*c0909341SAndroid Build Coastguard Worker     if (state.sig == SIG_ATOMIC_MAX) {
549*c0909341SAndroid Build Coastguard Worker         int s;
550*c0909341SAndroid Build Coastguard Worker         switch (e->ExceptionRecord->ExceptionCode) {
551*c0909341SAndroid Build Coastguard Worker         case EXCEPTION_FLT_DIVIDE_BY_ZERO:
552*c0909341SAndroid Build Coastguard Worker         case EXCEPTION_INT_DIVIDE_BY_ZERO:
553*c0909341SAndroid Build Coastguard Worker             s = SIGFPE;
554*c0909341SAndroid Build Coastguard Worker             break;
555*c0909341SAndroid Build Coastguard Worker         case EXCEPTION_ILLEGAL_INSTRUCTION:
556*c0909341SAndroid Build Coastguard Worker         case EXCEPTION_PRIV_INSTRUCTION:
557*c0909341SAndroid Build Coastguard Worker             s = SIGILL;
558*c0909341SAndroid Build Coastguard Worker             break;
559*c0909341SAndroid Build Coastguard Worker         case EXCEPTION_ACCESS_VIOLATION:
560*c0909341SAndroid Build Coastguard Worker         case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
561*c0909341SAndroid Build Coastguard Worker         case EXCEPTION_DATATYPE_MISALIGNMENT:
562*c0909341SAndroid Build Coastguard Worker         case EXCEPTION_STACK_OVERFLOW:
563*c0909341SAndroid Build Coastguard Worker             s = SIGSEGV;
564*c0909341SAndroid Build Coastguard Worker             break;
565*c0909341SAndroid Build Coastguard Worker         case EXCEPTION_IN_PAGE_ERROR:
566*c0909341SAndroid Build Coastguard Worker             s = SIGBUS;
567*c0909341SAndroid Build Coastguard Worker             break;
568*c0909341SAndroid Build Coastguard Worker         default:
569*c0909341SAndroid Build Coastguard Worker             return EXCEPTION_CONTINUE_SEARCH;
570*c0909341SAndroid Build Coastguard Worker         }
571*c0909341SAndroid Build Coastguard Worker         state.sig = s;
572*c0909341SAndroid Build Coastguard Worker         checkasm_load_context();
573*c0909341SAndroid Build Coastguard Worker     }
574*c0909341SAndroid Build Coastguard Worker     return EXCEPTION_CONTINUE_SEARCH;
575*c0909341SAndroid Build Coastguard Worker }
576*c0909341SAndroid Build Coastguard Worker #endif
577*c0909341SAndroid Build Coastguard Worker #else
578*c0909341SAndroid Build Coastguard Worker static void signal_handler(int s);
579*c0909341SAndroid Build Coastguard Worker 
580*c0909341SAndroid Build Coastguard Worker static const struct sigaction signal_handler_act = {
581*c0909341SAndroid Build Coastguard Worker     .sa_handler = signal_handler,
582*c0909341SAndroid Build Coastguard Worker     .sa_flags = SA_RESETHAND,
583*c0909341SAndroid Build Coastguard Worker };
584*c0909341SAndroid Build Coastguard Worker 
signal_handler(const int s)585*c0909341SAndroid Build Coastguard Worker static void signal_handler(const int s) {
586*c0909341SAndroid Build Coastguard Worker     if (state.sig == SIG_ATOMIC_MAX) {
587*c0909341SAndroid Build Coastguard Worker         state.sig = s;
588*c0909341SAndroid Build Coastguard Worker         sigaction(s, &signal_handler_act, NULL);
589*c0909341SAndroid Build Coastguard Worker         checkasm_load_context();
590*c0909341SAndroid Build Coastguard Worker     }
591*c0909341SAndroid Build Coastguard Worker }
592*c0909341SAndroid Build Coastguard Worker #endif
593*c0909341SAndroid Build Coastguard Worker 
594*c0909341SAndroid Build Coastguard Worker /* Compares a string with a wildcard pattern. */
wildstrcmp(const char * str,const char * pattern)595*c0909341SAndroid Build Coastguard Worker static int wildstrcmp(const char *str, const char *pattern) {
596*c0909341SAndroid Build Coastguard Worker     const char *wild = strchr(pattern, '*');
597*c0909341SAndroid Build Coastguard Worker     if (wild) {
598*c0909341SAndroid Build Coastguard Worker         const size_t len = wild - pattern;
599*c0909341SAndroid Build Coastguard Worker         if (strncmp(str, pattern, len)) return 1;
600*c0909341SAndroid Build Coastguard Worker         while (*++wild == '*');
601*c0909341SAndroid Build Coastguard Worker         if (!*wild) return 0;
602*c0909341SAndroid Build Coastguard Worker         str += len;
603*c0909341SAndroid Build Coastguard Worker         while (*str && wildstrcmp(str, wild)) str++;
604*c0909341SAndroid Build Coastguard Worker         return !*str;
605*c0909341SAndroid Build Coastguard Worker     }
606*c0909341SAndroid Build Coastguard Worker     return strcmp(str, pattern);
607*c0909341SAndroid Build Coastguard Worker }
608*c0909341SAndroid Build Coastguard Worker 
609*c0909341SAndroid Build Coastguard Worker /* Perform tests and benchmarks for the specified
610*c0909341SAndroid Build Coastguard Worker  * cpu flag if supported by the host */
check_cpu_flag(const char * const name,unsigned flag)611*c0909341SAndroid Build Coastguard Worker static void check_cpu_flag(const char *const name, unsigned flag) {
612*c0909341SAndroid Build Coastguard Worker     const unsigned old_cpu_flag = state.cpu_flag;
613*c0909341SAndroid Build Coastguard Worker 
614*c0909341SAndroid Build Coastguard Worker     flag |= old_cpu_flag;
615*c0909341SAndroid Build Coastguard Worker     dav1d_set_cpu_flags_mask(flag);
616*c0909341SAndroid Build Coastguard Worker     state.cpu_flag = dav1d_get_cpu_flags();
617*c0909341SAndroid Build Coastguard Worker 
618*c0909341SAndroid Build Coastguard Worker     if (!flag || state.cpu_flag != old_cpu_flag) {
619*c0909341SAndroid Build Coastguard Worker         state.cpu_flag_name = name;
620*c0909341SAndroid Build Coastguard Worker         state.suffix_length = (int)strlen(cpu_suffix(flag)) + 1;
621*c0909341SAndroid Build Coastguard Worker         for (int i = 0; tests[i].func; i++) {
622*c0909341SAndroid Build Coastguard Worker             if (state.test_pattern && wildstrcmp(tests[i].name, state.test_pattern))
623*c0909341SAndroid Build Coastguard Worker                 continue;
624*c0909341SAndroid Build Coastguard Worker             xor128_srand(state.seed);
625*c0909341SAndroid Build Coastguard Worker             state.current_test_name = tests[i].name;
626*c0909341SAndroid Build Coastguard Worker             tests[i].func();
627*c0909341SAndroid Build Coastguard Worker         }
628*c0909341SAndroid Build Coastguard Worker     }
629*c0909341SAndroid Build Coastguard Worker }
630*c0909341SAndroid Build Coastguard Worker 
631*c0909341SAndroid Build Coastguard Worker /* Print the name of the current CPU flag, but only do it once */
print_cpu_name(void)632*c0909341SAndroid Build Coastguard Worker static void print_cpu_name(void) {
633*c0909341SAndroid Build Coastguard Worker     if (state.cpu_flag_name) {
634*c0909341SAndroid Build Coastguard Worker         color_fprintf(stderr, COLOR_YELLOW, "%s:\n", state.cpu_flag_name);
635*c0909341SAndroid Build Coastguard Worker         state.cpu_flag_name = NULL;
636*c0909341SAndroid Build Coastguard Worker     }
637*c0909341SAndroid Build Coastguard Worker }
638*c0909341SAndroid Build Coastguard Worker 
get_seed(void)639*c0909341SAndroid Build Coastguard Worker static unsigned get_seed(void) {
640*c0909341SAndroid Build Coastguard Worker #ifdef _WIN32
641*c0909341SAndroid Build Coastguard Worker     LARGE_INTEGER i;
642*c0909341SAndroid Build Coastguard Worker     QueryPerformanceCounter(&i);
643*c0909341SAndroid Build Coastguard Worker     return i.LowPart;
644*c0909341SAndroid Build Coastguard Worker #elif defined(__APPLE__)
645*c0909341SAndroid Build Coastguard Worker     return (unsigned) mach_absolute_time();
646*c0909341SAndroid Build Coastguard Worker #else
647*c0909341SAndroid Build Coastguard Worker     struct timespec ts;
648*c0909341SAndroid Build Coastguard Worker     clock_gettime(CLOCK_MONOTONIC, &ts);
649*c0909341SAndroid Build Coastguard Worker     return (unsigned) (1000000000ULL * ts.tv_sec + ts.tv_nsec);
650*c0909341SAndroid Build Coastguard Worker #endif
651*c0909341SAndroid Build Coastguard Worker }
652*c0909341SAndroid Build Coastguard Worker 
checkasm_strtoul(unsigned long * const dst,const char * const str,const int base)653*c0909341SAndroid Build Coastguard Worker static int checkasm_strtoul(unsigned long *const dst, const char *const str, const int base) {
654*c0909341SAndroid Build Coastguard Worker     char *end;
655*c0909341SAndroid Build Coastguard Worker     errno = 0;
656*c0909341SAndroid Build Coastguard Worker     *dst = strtoul(str, &end, base);
657*c0909341SAndroid Build Coastguard Worker     return errno || end == str || *end;
658*c0909341SAndroid Build Coastguard Worker }
659*c0909341SAndroid Build Coastguard Worker 
main(int argc,char * argv[])660*c0909341SAndroid Build Coastguard Worker int main(int argc, char *argv[]) {
661*c0909341SAndroid Build Coastguard Worker     state.seed = get_seed();
662*c0909341SAndroid Build Coastguard Worker 
663*c0909341SAndroid Build Coastguard Worker     while (argc > 1) {
664*c0909341SAndroid Build Coastguard Worker         if (!strncmp(argv[1], "--help", 6) || !strcmp(argv[1], "-h")) {
665*c0909341SAndroid Build Coastguard Worker             fprintf(stderr,
666*c0909341SAndroid Build Coastguard Worker                     "checkasm [options] <random seed>\n"
667*c0909341SAndroid Build Coastguard Worker                     "    <random seed>              Numeric value to seed the rng\n"
668*c0909341SAndroid Build Coastguard Worker                     "Options:\n"
669*c0909341SAndroid Build Coastguard Worker                     "    --affinity=<cpu>           Run the process on CPU <cpu>\n"
670*c0909341SAndroid Build Coastguard Worker                     "    --test=<pattern> -t        Test only <pattern>\n"
671*c0909341SAndroid Build Coastguard Worker                     "    --function=<pattern> -f    Test only the functions matching <pattern>\n"
672*c0909341SAndroid Build Coastguard Worker                     "    --bench -b                 Benchmark the tested functions\n"
673*c0909341SAndroid Build Coastguard Worker                     "    --list-cpuflags            List available cpu flags\n"
674*c0909341SAndroid Build Coastguard Worker                     "    --list-functions           List available functions\n"
675*c0909341SAndroid Build Coastguard Worker                     "    --list-tests               List available tests\n"
676*c0909341SAndroid Build Coastguard Worker                     "    --verbose -v               Print verbose output\n");
677*c0909341SAndroid Build Coastguard Worker             return 0;
678*c0909341SAndroid Build Coastguard Worker         } else if (!strcmp(argv[1], "--bench") || !strcmp(argv[1], "-b")) {
679*c0909341SAndroid Build Coastguard Worker #ifndef readtime
680*c0909341SAndroid Build Coastguard Worker             fprintf(stderr,
681*c0909341SAndroid Build Coastguard Worker                     "checkasm: --bench is not supported on your system\n");
682*c0909341SAndroid Build Coastguard Worker             return 1;
683*c0909341SAndroid Build Coastguard Worker #endif
684*c0909341SAndroid Build Coastguard Worker             state.run_mode = RUN_BENCHMARK;
685*c0909341SAndroid Build Coastguard Worker         } else if (!strncmp(argv[1], "--test=", 7)) {
686*c0909341SAndroid Build Coastguard Worker             state.test_pattern = argv[1] + 7;
687*c0909341SAndroid Build Coastguard Worker         } else if (!strcmp(argv[1], "-t")) {
688*c0909341SAndroid Build Coastguard Worker             state.test_pattern = argc > 1 ? argv[2] : "";
689*c0909341SAndroid Build Coastguard Worker             argc--;
690*c0909341SAndroid Build Coastguard Worker             argv++;
691*c0909341SAndroid Build Coastguard Worker         } else if (!strncmp(argv[1], "--function=", 11)) {
692*c0909341SAndroid Build Coastguard Worker             state.function_pattern = argv[1] + 11;
693*c0909341SAndroid Build Coastguard Worker         } else if (!strcmp(argv[1], "-f")) {
694*c0909341SAndroid Build Coastguard Worker             state.function_pattern = argc > 1 ? argv[2] : "";
695*c0909341SAndroid Build Coastguard Worker             argc--;
696*c0909341SAndroid Build Coastguard Worker             argv++;
697*c0909341SAndroid Build Coastguard Worker         } else if (!strcmp(argv[1], "--list-cpuflags")) {
698*c0909341SAndroid Build Coastguard Worker             state.run_mode = RUN_CPUFLAG_LISTING;
699*c0909341SAndroid Build Coastguard Worker             break;
700*c0909341SAndroid Build Coastguard Worker         } else if (!strcmp(argv[1], "--list-functions")) {
701*c0909341SAndroid Build Coastguard Worker             state.run_mode = RUN_FUNCTION_LISTING;
702*c0909341SAndroid Build Coastguard Worker         } else if (!strcmp(argv[1], "--list-tests")) {
703*c0909341SAndroid Build Coastguard Worker             for (int i = 0; tests[i].name; i++)
704*c0909341SAndroid Build Coastguard Worker                 printf("%s\n", tests[i].name);
705*c0909341SAndroid Build Coastguard Worker             return 0;
706*c0909341SAndroid Build Coastguard Worker         } else if (!strcmp(argv[1], "--verbose") || !strcmp(argv[1], "-v")) {
707*c0909341SAndroid Build Coastguard Worker             state.verbose = 1;
708*c0909341SAndroid Build Coastguard Worker         } else if (!strncmp(argv[1], "--affinity=", 11)) {
709*c0909341SAndroid Build Coastguard Worker             const char *const s = argv[1] + 11;
710*c0909341SAndroid Build Coastguard Worker             unsigned long affinity;
711*c0909341SAndroid Build Coastguard Worker             if (checkasm_strtoul(&affinity, s, 16)) {
712*c0909341SAndroid Build Coastguard Worker                 fprintf(stderr, "checkasm: invalid cpu affinity (%s)\n", s);
713*c0909341SAndroid Build Coastguard Worker                 return 1;
714*c0909341SAndroid Build Coastguard Worker             }
715*c0909341SAndroid Build Coastguard Worker #ifdef _WIN32
716*c0909341SAndroid Build Coastguard Worker             int affinity_err;
717*c0909341SAndroid Build Coastguard Worker             HANDLE process = GetCurrentProcess();
718*c0909341SAndroid Build Coastguard Worker #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
719*c0909341SAndroid Build Coastguard Worker             BOOL (WINAPI *spdcs)(HANDLE, const ULONG*, ULONG) =
720*c0909341SAndroid Build Coastguard Worker                 (void*)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "SetProcessDefaultCpuSets");
721*c0909341SAndroid Build Coastguard Worker             if (spdcs)
722*c0909341SAndroid Build Coastguard Worker                 affinity_err = !spdcs(process, (ULONG[]){ affinity + 256 }, 1);
723*c0909341SAndroid Build Coastguard Worker             else
724*c0909341SAndroid Build Coastguard Worker #endif
725*c0909341SAndroid Build Coastguard Worker             {
726*c0909341SAndroid Build Coastguard Worker                 if (affinity < sizeof(DWORD_PTR) * 8)
727*c0909341SAndroid Build Coastguard Worker                     affinity_err = !SetProcessAffinityMask(process, (DWORD_PTR)1 << affinity);
728*c0909341SAndroid Build Coastguard Worker                 else
729*c0909341SAndroid Build Coastguard Worker                     affinity_err = 1;
730*c0909341SAndroid Build Coastguard Worker             }
731*c0909341SAndroid Build Coastguard Worker             if (affinity_err) {
732*c0909341SAndroid Build Coastguard Worker                 fprintf(stderr, "checkasm: invalid cpu affinity (%lu)\n", affinity);
733*c0909341SAndroid Build Coastguard Worker                 return 1;
734*c0909341SAndroid Build Coastguard Worker             } else {
735*c0909341SAndroid Build Coastguard Worker                 fprintf(stderr, "checkasm: running on cpu %lu\n", affinity);
736*c0909341SAndroid Build Coastguard Worker             }
737*c0909341SAndroid Build Coastguard Worker #elif HAVE_PTHREAD_SETAFFINITY_NP && defined(CPU_SET)
738*c0909341SAndroid Build Coastguard Worker             cpu_set_t set;
739*c0909341SAndroid Build Coastguard Worker             CPU_ZERO(&set);
740*c0909341SAndroid Build Coastguard Worker             CPU_SET(affinity, &set);
741*c0909341SAndroid Build Coastguard Worker             if (pthread_setaffinity_np(pthread_self(), sizeof(set), &set)) {
742*c0909341SAndroid Build Coastguard Worker                 fprintf(stderr, "checkasm: invalid cpu affinity (%lu)\n", affinity);
743*c0909341SAndroid Build Coastguard Worker                 return 1;
744*c0909341SAndroid Build Coastguard Worker             } else {
745*c0909341SAndroid Build Coastguard Worker                 fprintf(stderr, "checkasm: running on cpu %lu\n", affinity);
746*c0909341SAndroid Build Coastguard Worker             }
747*c0909341SAndroid Build Coastguard Worker #else
748*c0909341SAndroid Build Coastguard Worker             (void)affinity;
749*c0909341SAndroid Build Coastguard Worker             fprintf(stderr,
750*c0909341SAndroid Build Coastguard Worker                     "checkasm: --affinity is not supported on your system\n");
751*c0909341SAndroid Build Coastguard Worker             return 1;
752*c0909341SAndroid Build Coastguard Worker #endif
753*c0909341SAndroid Build Coastguard Worker         } else {
754*c0909341SAndroid Build Coastguard Worker             unsigned long seed;
755*c0909341SAndroid Build Coastguard Worker             if (checkasm_strtoul(&seed, argv[1], 10)) {
756*c0909341SAndroid Build Coastguard Worker                 fprintf(stderr, "checkasm: unknown option (%s)\n", argv[1]);
757*c0909341SAndroid Build Coastguard Worker                 return 1;
758*c0909341SAndroid Build Coastguard Worker             }
759*c0909341SAndroid Build Coastguard Worker             state.seed = (unsigned)seed;
760*c0909341SAndroid Build Coastguard Worker         }
761*c0909341SAndroid Build Coastguard Worker 
762*c0909341SAndroid Build Coastguard Worker         argc--;
763*c0909341SAndroid Build Coastguard Worker         argv++;
764*c0909341SAndroid Build Coastguard Worker     }
765*c0909341SAndroid Build Coastguard Worker 
766*c0909341SAndroid Build Coastguard Worker #if TRIM_DSP_FUNCTIONS
767*c0909341SAndroid Build Coastguard Worker     fprintf(stderr, "checkasm: reference functions unavailable, reconfigure using '-Dtrim_dsp=false'\n");
768*c0909341SAndroid Build Coastguard Worker     return 0;
769*c0909341SAndroid Build Coastguard Worker #endif
770*c0909341SAndroid Build Coastguard Worker 
771*c0909341SAndroid Build Coastguard Worker     dav1d_init_cpu();
772*c0909341SAndroid Build Coastguard Worker 
773*c0909341SAndroid Build Coastguard Worker #ifdef _WIN32
774*c0909341SAndroid Build Coastguard Worker #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
775*c0909341SAndroid Build Coastguard Worker     AddVectoredExceptionHandler(0, signal_handler);
776*c0909341SAndroid Build Coastguard Worker 
777*c0909341SAndroid Build Coastguard Worker     HANDLE con = GetStdHandle(state.run_mode >= RUN_CPUFLAG_LISTING ?
778*c0909341SAndroid Build Coastguard Worker                               STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
779*c0909341SAndroid Build Coastguard Worker     DWORD con_mode = 0;
780*c0909341SAndroid Build Coastguard Worker     use_printf_color = con && con != INVALID_HANDLE_VALUE &&
781*c0909341SAndroid Build Coastguard Worker                        GetConsoleMode(con, &con_mode) &&
782*c0909341SAndroid Build Coastguard Worker                        SetConsoleMode(con, con_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
783*c0909341SAndroid Build Coastguard Worker #endif
784*c0909341SAndroid Build Coastguard Worker #else
785*c0909341SAndroid Build Coastguard Worker     sigaction(SIGBUS,  &signal_handler_act, NULL);
786*c0909341SAndroid Build Coastguard Worker     sigaction(SIGFPE,  &signal_handler_act, NULL);
787*c0909341SAndroid Build Coastguard Worker     sigaction(SIGILL,  &signal_handler_act, NULL);
788*c0909341SAndroid Build Coastguard Worker     sigaction(SIGSEGV, &signal_handler_act, NULL);
789*c0909341SAndroid Build Coastguard Worker 
790*c0909341SAndroid Build Coastguard Worker     if (isatty(state.run_mode >= RUN_CPUFLAG_LISTING ? 1 : 2)) {
791*c0909341SAndroid Build Coastguard Worker         const char *const term = getenv("TERM");
792*c0909341SAndroid Build Coastguard Worker         use_printf_color = term && strcmp(term, "dumb");
793*c0909341SAndroid Build Coastguard Worker     }
794*c0909341SAndroid Build Coastguard Worker #endif
795*c0909341SAndroid Build Coastguard Worker 
796*c0909341SAndroid Build Coastguard Worker #ifdef readtime
797*c0909341SAndroid Build Coastguard Worker     if (state.run_mode == RUN_BENCHMARK) {
798*c0909341SAndroid Build Coastguard Worker #if CONFIG_MACOS_KPERF
799*c0909341SAndroid Build Coastguard Worker         if (kperf_init())
800*c0909341SAndroid Build Coastguard Worker             return 1;
801*c0909341SAndroid Build Coastguard Worker #endif
802*c0909341SAndroid Build Coastguard Worker         if (!checkasm_save_context()) {
803*c0909341SAndroid Build Coastguard Worker             checkasm_set_signal_handler_state(1);
804*c0909341SAndroid Build Coastguard Worker             readtime();
805*c0909341SAndroid Build Coastguard Worker             checkasm_set_signal_handler_state(0);
806*c0909341SAndroid Build Coastguard Worker         } else {
807*c0909341SAndroid Build Coastguard Worker             fprintf(stderr, "checkasm: unable to access cycle counter\n");
808*c0909341SAndroid Build Coastguard Worker             return 1;
809*c0909341SAndroid Build Coastguard Worker         }
810*c0909341SAndroid Build Coastguard Worker     }
811*c0909341SAndroid Build Coastguard Worker #endif
812*c0909341SAndroid Build Coastguard Worker 
813*c0909341SAndroid Build Coastguard Worker     int ret = 0;
814*c0909341SAndroid Build Coastguard Worker 
815*c0909341SAndroid Build Coastguard Worker     if (state.run_mode != RUN_FUNCTION_LISTING) {
816*c0909341SAndroid Build Coastguard Worker         const unsigned cpu_flags = dav1d_get_cpu_flags();
817*c0909341SAndroid Build Coastguard Worker         if (state.run_mode == RUN_CPUFLAG_LISTING) {
818*c0909341SAndroid Build Coastguard Worker             const int last_i = (int)(sizeof(cpus) / sizeof(*cpus)) - 2;
819*c0909341SAndroid Build Coastguard Worker             for (int i = 0; i <= last_i ; i++) {
820*c0909341SAndroid Build Coastguard Worker                 if (cpus[i].flag & cpu_flags)
821*c0909341SAndroid Build Coastguard Worker                     color_fprintf(stdout, COLOR_GREEN, "%s", cpus[i].suffix);
822*c0909341SAndroid Build Coastguard Worker                 else
823*c0909341SAndroid Build Coastguard Worker                     color_fprintf(stdout, COLOR_RED, "~%s", cpus[i].suffix);
824*c0909341SAndroid Build Coastguard Worker                 printf(i == last_i ? "\n" : ", ");
825*c0909341SAndroid Build Coastguard Worker             }
826*c0909341SAndroid Build Coastguard Worker             return 0;
827*c0909341SAndroid Build Coastguard Worker         }
828*c0909341SAndroid Build Coastguard Worker #if ARCH_X86_64
829*c0909341SAndroid Build Coastguard Worker         void checkasm_warmup_avx2(void);
830*c0909341SAndroid Build Coastguard Worker         void checkasm_warmup_avx512(void);
831*c0909341SAndroid Build Coastguard Worker         if (cpu_flags & DAV1D_X86_CPU_FLAG_AVX512ICL)
832*c0909341SAndroid Build Coastguard Worker             state.simd_warmup = checkasm_warmup_avx512;
833*c0909341SAndroid Build Coastguard Worker         else if (cpu_flags & DAV1D_X86_CPU_FLAG_AVX2)
834*c0909341SAndroid Build Coastguard Worker             state.simd_warmup = checkasm_warmup_avx2;
835*c0909341SAndroid Build Coastguard Worker         checkasm_simd_warmup();
836*c0909341SAndroid Build Coastguard Worker #endif
837*c0909341SAndroid Build Coastguard Worker #if ARCH_ARM
838*c0909341SAndroid Build Coastguard Worker         void checkasm_checked_call_vfp(void *func, int dummy, ...);
839*c0909341SAndroid Build Coastguard Worker         void checkasm_checked_call_novfp(void *func, int dummy, ...);
840*c0909341SAndroid Build Coastguard Worker         if (cpu_flags & DAV1D_ARM_CPU_FLAG_NEON)
841*c0909341SAndroid Build Coastguard Worker             checkasm_checked_call_ptr = checkasm_checked_call_vfp;
842*c0909341SAndroid Build Coastguard Worker         else
843*c0909341SAndroid Build Coastguard Worker             checkasm_checked_call_ptr = checkasm_checked_call_novfp;
844*c0909341SAndroid Build Coastguard Worker #endif
845*c0909341SAndroid Build Coastguard Worker #if ARCH_X86
846*c0909341SAndroid Build Coastguard Worker         unsigned checkasm_init_x86(char *name);
847*c0909341SAndroid Build Coastguard Worker         char name[48];
848*c0909341SAndroid Build Coastguard Worker         const unsigned cpuid = checkasm_init_x86(name);
849*c0909341SAndroid Build Coastguard Worker         for (size_t len = strlen(name); len && name[len-1] == ' '; len--)
850*c0909341SAndroid Build Coastguard Worker             name[len-1] = '\0'; /* trim trailing whitespace */
851*c0909341SAndroid Build Coastguard Worker         fprintf(stderr, "checkasm: %s (%08X) using random seed %u\n", name, cpuid, state.seed);
852*c0909341SAndroid Build Coastguard Worker #elif ARCH_RISCV
853*c0909341SAndroid Build Coastguard Worker         char buf[32] = "";
854*c0909341SAndroid Build Coastguard Worker         if (cpu_flags & DAV1D_RISCV_CPU_FLAG_V)
855*c0909341SAndroid Build Coastguard Worker             snprintf(buf, sizeof(buf), "VLEN=%i bits, ", dav1d_get_vlen());
856*c0909341SAndroid Build Coastguard Worker         fprintf(stderr, "checkasm: %susing random seed %u\n", buf, state.seed);
857*c0909341SAndroid Build Coastguard Worker #elif ARCH_AARCH64 && HAVE_SVE
858*c0909341SAndroid Build Coastguard Worker         char buf[48] = "";
859*c0909341SAndroid Build Coastguard Worker         if (cpu_flags & DAV1D_ARM_CPU_FLAG_SVE)
860*c0909341SAndroid Build Coastguard Worker             snprintf(buf, sizeof(buf), "SVE %d bits, ", checkasm_sve_length());
861*c0909341SAndroid Build Coastguard Worker         fprintf(stderr, "checkasm: %susing random seed %u\n", buf, state.seed);
862*c0909341SAndroid Build Coastguard Worker #else
863*c0909341SAndroid Build Coastguard Worker         fprintf(stderr, "checkasm: using random seed %u\n", state.seed);
864*c0909341SAndroid Build Coastguard Worker #endif
865*c0909341SAndroid Build Coastguard Worker     }
866*c0909341SAndroid Build Coastguard Worker 
867*c0909341SAndroid Build Coastguard Worker     check_cpu_flag(NULL, 0);
868*c0909341SAndroid Build Coastguard Worker     for (int i = 0; cpus[i].flag; i++)
869*c0909341SAndroid Build Coastguard Worker         check_cpu_flag(cpus[i].name, cpus[i].flag);
870*c0909341SAndroid Build Coastguard Worker 
871*c0909341SAndroid Build Coastguard Worker     if (state.run_mode == RUN_FUNCTION_LISTING) {
872*c0909341SAndroid Build Coastguard Worker         print_functions(state.funcs);
873*c0909341SAndroid Build Coastguard Worker     } else if (state.num_failed) {
874*c0909341SAndroid Build Coastguard Worker         fprintf(stderr, "checkasm: %d of %d tests failed\n",
875*c0909341SAndroid Build Coastguard Worker                 state.num_failed, state.num_checked);
876*c0909341SAndroid Build Coastguard Worker         ret = 1;
877*c0909341SAndroid Build Coastguard Worker     } else {
878*c0909341SAndroid Build Coastguard Worker         if (state.num_checked)
879*c0909341SAndroid Build Coastguard Worker             fprintf(stderr, "checkasm: all %d tests passed\n", state.num_checked);
880*c0909341SAndroid Build Coastguard Worker         else
881*c0909341SAndroid Build Coastguard Worker             fprintf(stderr, "checkasm: no tests to perform\n");
882*c0909341SAndroid Build Coastguard Worker #ifdef readtime
883*c0909341SAndroid Build Coastguard Worker         if (state.run_mode == RUN_BENCHMARK && state.max_function_name_length) {
884*c0909341SAndroid Build Coastguard Worker             state.nop_time = measure_nop_time();
885*c0909341SAndroid Build Coastguard Worker             if (state.verbose)
886*c0909341SAndroid Build Coastguard Worker                 printf("nop:%*.1f\n", state.max_function_name_length + 6, state.nop_time);
887*c0909341SAndroid Build Coastguard Worker             print_benchs(state.funcs);
888*c0909341SAndroid Build Coastguard Worker         }
889*c0909341SAndroid Build Coastguard Worker #endif
890*c0909341SAndroid Build Coastguard Worker     }
891*c0909341SAndroid Build Coastguard Worker 
892*c0909341SAndroid Build Coastguard Worker     destroy_func_tree(state.funcs);
893*c0909341SAndroid Build Coastguard Worker     return ret;
894*c0909341SAndroid Build Coastguard Worker }
895*c0909341SAndroid Build Coastguard Worker 
896*c0909341SAndroid Build Coastguard Worker /* Decide whether or not the specified function needs to be tested and
897*c0909341SAndroid Build Coastguard Worker  * allocate/initialize data structures if needed. Returns a pointer to a
898*c0909341SAndroid Build Coastguard Worker  * reference function if the function should be tested, otherwise NULL */
checkasm_check_func(void * const func,const char * const name,...)899*c0909341SAndroid Build Coastguard Worker void *checkasm_check_func(void *const func, const char *const name, ...) {
900*c0909341SAndroid Build Coastguard Worker     char name_buf[256];
901*c0909341SAndroid Build Coastguard Worker     va_list arg;
902*c0909341SAndroid Build Coastguard Worker 
903*c0909341SAndroid Build Coastguard Worker     va_start(arg, name);
904*c0909341SAndroid Build Coastguard Worker     int name_length = vsnprintf(name_buf, sizeof(name_buf), name, arg);
905*c0909341SAndroid Build Coastguard Worker     va_end(arg);
906*c0909341SAndroid Build Coastguard Worker 
907*c0909341SAndroid Build Coastguard Worker     if (!func || name_length <= 0 || (size_t)name_length >= sizeof(name_buf) ||
908*c0909341SAndroid Build Coastguard Worker         (state.function_pattern && wildstrcmp(name_buf, state.function_pattern)))
909*c0909341SAndroid Build Coastguard Worker     {
910*c0909341SAndroid Build Coastguard Worker         return NULL;
911*c0909341SAndroid Build Coastguard Worker     }
912*c0909341SAndroid Build Coastguard Worker 
913*c0909341SAndroid Build Coastguard Worker     state.current_func = get_func(&state.funcs, name_buf);
914*c0909341SAndroid Build Coastguard Worker 
915*c0909341SAndroid Build Coastguard Worker     state.funcs->color = 1;
916*c0909341SAndroid Build Coastguard Worker     CheckasmFuncVersion *v = &state.current_func->versions;
917*c0909341SAndroid Build Coastguard Worker     void *ref = func;
918*c0909341SAndroid Build Coastguard Worker 
919*c0909341SAndroid Build Coastguard Worker     if (v->func) {
920*c0909341SAndroid Build Coastguard Worker         CheckasmFuncVersion *prev;
921*c0909341SAndroid Build Coastguard Worker         do {
922*c0909341SAndroid Build Coastguard Worker             /* Only test functions that haven't already been tested */
923*c0909341SAndroid Build Coastguard Worker             if (v->func == func)
924*c0909341SAndroid Build Coastguard Worker                 return NULL;
925*c0909341SAndroid Build Coastguard Worker 
926*c0909341SAndroid Build Coastguard Worker             if (v->ok)
927*c0909341SAndroid Build Coastguard Worker                 ref = v->func;
928*c0909341SAndroid Build Coastguard Worker 
929*c0909341SAndroid Build Coastguard Worker             prev = v;
930*c0909341SAndroid Build Coastguard Worker         } while ((v = v->next));
931*c0909341SAndroid Build Coastguard Worker 
932*c0909341SAndroid Build Coastguard Worker         v = prev->next = checkasm_malloc(sizeof(CheckasmFuncVersion));
933*c0909341SAndroid Build Coastguard Worker     }
934*c0909341SAndroid Build Coastguard Worker 
935*c0909341SAndroid Build Coastguard Worker     name_length += state.suffix_length;
936*c0909341SAndroid Build Coastguard Worker     if (name_length > state.max_function_name_length)
937*c0909341SAndroid Build Coastguard Worker         state.max_function_name_length = name_length;
938*c0909341SAndroid Build Coastguard Worker 
939*c0909341SAndroid Build Coastguard Worker     v->func = func;
940*c0909341SAndroid Build Coastguard Worker     v->ok = 1;
941*c0909341SAndroid Build Coastguard Worker     v->cpu = state.cpu_flag;
942*c0909341SAndroid Build Coastguard Worker     state.current_func_ver = v;
943*c0909341SAndroid Build Coastguard Worker     if (state.run_mode == RUN_FUNCTION_LISTING) /* Save function names without running tests */
944*c0909341SAndroid Build Coastguard Worker         return NULL;
945*c0909341SAndroid Build Coastguard Worker 
946*c0909341SAndroid Build Coastguard Worker     xor128_srand(state.seed);
947*c0909341SAndroid Build Coastguard Worker 
948*c0909341SAndroid Build Coastguard Worker     if (state.cpu_flag)
949*c0909341SAndroid Build Coastguard Worker         state.num_checked++;
950*c0909341SAndroid Build Coastguard Worker 
951*c0909341SAndroid Build Coastguard Worker     return ref;
952*c0909341SAndroid Build Coastguard Worker }
953*c0909341SAndroid Build Coastguard Worker 
954*c0909341SAndroid Build Coastguard Worker /* Decide whether or not the current function needs to be benchmarked */
checkasm_bench_func(void)955*c0909341SAndroid Build Coastguard Worker int checkasm_bench_func(void) {
956*c0909341SAndroid Build Coastguard Worker     return !state.num_failed && state.run_mode == RUN_BENCHMARK;
957*c0909341SAndroid Build Coastguard Worker }
958*c0909341SAndroid Build Coastguard Worker 
959*c0909341SAndroid Build Coastguard Worker /* Indicate that the current test has failed, return whether verbose printing
960*c0909341SAndroid Build Coastguard Worker  * is requested. */
checkasm_fail_func(const char * const msg,...)961*c0909341SAndroid Build Coastguard Worker int checkasm_fail_func(const char *const msg, ...) {
962*c0909341SAndroid Build Coastguard Worker     if (state.current_func_ver && state.current_func_ver->cpu &&
963*c0909341SAndroid Build Coastguard Worker         state.current_func_ver->ok)
964*c0909341SAndroid Build Coastguard Worker     {
965*c0909341SAndroid Build Coastguard Worker         va_list arg;
966*c0909341SAndroid Build Coastguard Worker 
967*c0909341SAndroid Build Coastguard Worker         print_cpu_name();
968*c0909341SAndroid Build Coastguard Worker         fprintf(stderr, "   %s_%s (", state.current_func->name,
969*c0909341SAndroid Build Coastguard Worker                 cpu_suffix(state.current_func_ver->cpu));
970*c0909341SAndroid Build Coastguard Worker         va_start(arg, msg);
971*c0909341SAndroid Build Coastguard Worker         vfprintf(stderr, msg, arg);
972*c0909341SAndroid Build Coastguard Worker         va_end(arg);
973*c0909341SAndroid Build Coastguard Worker         fprintf(stderr, ")\n");
974*c0909341SAndroid Build Coastguard Worker 
975*c0909341SAndroid Build Coastguard Worker         state.current_func_ver->ok = 0;
976*c0909341SAndroid Build Coastguard Worker         state.num_failed++;
977*c0909341SAndroid Build Coastguard Worker     }
978*c0909341SAndroid Build Coastguard Worker     return state.verbose;
979*c0909341SAndroid Build Coastguard Worker }
980*c0909341SAndroid Build Coastguard Worker 
981*c0909341SAndroid Build Coastguard Worker /* Update benchmark results of the current function */
checkasm_update_bench(const int iterations,const uint64_t cycles)982*c0909341SAndroid Build Coastguard Worker void checkasm_update_bench(const int iterations, const uint64_t cycles) {
983*c0909341SAndroid Build Coastguard Worker     state.current_func_ver->iterations += iterations;
984*c0909341SAndroid Build Coastguard Worker     state.current_func_ver->cycles += cycles;
985*c0909341SAndroid Build Coastguard Worker }
986*c0909341SAndroid Build Coastguard Worker 
987*c0909341SAndroid Build Coastguard Worker /* Print the outcome of all tests performed since
988*c0909341SAndroid Build Coastguard Worker  * the last time this function was called */
checkasm_report(const char * const name,...)989*c0909341SAndroid Build Coastguard Worker void checkasm_report(const char *const name, ...) {
990*c0909341SAndroid Build Coastguard Worker     static int prev_checked, prev_failed;
991*c0909341SAndroid Build Coastguard Worker     static size_t max_length;
992*c0909341SAndroid Build Coastguard Worker 
993*c0909341SAndroid Build Coastguard Worker     if (state.num_checked > prev_checked) {
994*c0909341SAndroid Build Coastguard Worker         int pad_length = (int) max_length + 4;
995*c0909341SAndroid Build Coastguard Worker         va_list arg;
996*c0909341SAndroid Build Coastguard Worker 
997*c0909341SAndroid Build Coastguard Worker         print_cpu_name();
998*c0909341SAndroid Build Coastguard Worker         pad_length -= fprintf(stderr, " - %s.", state.current_test_name);
999*c0909341SAndroid Build Coastguard Worker         va_start(arg, name);
1000*c0909341SAndroid Build Coastguard Worker         pad_length -= vfprintf(stderr, name, arg);
1001*c0909341SAndroid Build Coastguard Worker         va_end(arg);
1002*c0909341SAndroid Build Coastguard Worker         fprintf(stderr, "%*c", imax(pad_length, 0) + 2, '[');
1003*c0909341SAndroid Build Coastguard Worker 
1004*c0909341SAndroid Build Coastguard Worker         if (state.num_failed == prev_failed)
1005*c0909341SAndroid Build Coastguard Worker             color_fprintf(stderr, COLOR_GREEN, "OK");
1006*c0909341SAndroid Build Coastguard Worker         else
1007*c0909341SAndroid Build Coastguard Worker             color_fprintf(stderr, COLOR_RED, "FAILED");
1008*c0909341SAndroid Build Coastguard Worker         fprintf(stderr, "]\n");
1009*c0909341SAndroid Build Coastguard Worker 
1010*c0909341SAndroid Build Coastguard Worker         prev_checked = state.num_checked;
1011*c0909341SAndroid Build Coastguard Worker         prev_failed  = state.num_failed;
1012*c0909341SAndroid Build Coastguard Worker     } else if (!state.cpu_flag) {
1013*c0909341SAndroid Build Coastguard Worker         /* Calculate the amount of padding required
1014*c0909341SAndroid Build Coastguard Worker          * to make the output vertically aligned */
1015*c0909341SAndroid Build Coastguard Worker         size_t length = strlen(state.current_test_name);
1016*c0909341SAndroid Build Coastguard Worker         va_list arg;
1017*c0909341SAndroid Build Coastguard Worker 
1018*c0909341SAndroid Build Coastguard Worker         va_start(arg, name);
1019*c0909341SAndroid Build Coastguard Worker         length += vsnprintf(NULL, 0, name, arg);
1020*c0909341SAndroid Build Coastguard Worker         va_end(arg);
1021*c0909341SAndroid Build Coastguard Worker 
1022*c0909341SAndroid Build Coastguard Worker         if (length > max_length)
1023*c0909341SAndroid Build Coastguard Worker             max_length = length;
1024*c0909341SAndroid Build Coastguard Worker     }
1025*c0909341SAndroid Build Coastguard Worker }
1026*c0909341SAndroid Build Coastguard Worker 
checkasm_set_signal_handler_state(const int enabled)1027*c0909341SAndroid Build Coastguard Worker void checkasm_set_signal_handler_state(const int enabled) {
1028*c0909341SAndroid Build Coastguard Worker     state.sig = enabled ? SIG_ATOMIC_MAX : 0;
1029*c0909341SAndroid Build Coastguard Worker }
1030*c0909341SAndroid Build Coastguard Worker 
checkasm_handle_signal(void)1031*c0909341SAndroid Build Coastguard Worker void checkasm_handle_signal(void) {
1032*c0909341SAndroid Build Coastguard Worker     const int s = state.sig;
1033*c0909341SAndroid Build Coastguard Worker     checkasm_fail_func(s == SIGFPE ? "fatal arithmetic error" :
1034*c0909341SAndroid Build Coastguard Worker                        s == SIGILL ? "illegal instruction" :
1035*c0909341SAndroid Build Coastguard Worker                        s == SIGBUS ? "bus error" :
1036*c0909341SAndroid Build Coastguard Worker                                      "segmentation fault");
1037*c0909341SAndroid Build Coastguard Worker }
1038*c0909341SAndroid Build Coastguard Worker 
check_err(const char * const file,const int line,const char * const name,const int w,const int h,int * const err)1039*c0909341SAndroid Build Coastguard Worker static int check_err(const char *const file, const int line,
1040*c0909341SAndroid Build Coastguard Worker                      const char *const name, const int w, const int h,
1041*c0909341SAndroid Build Coastguard Worker                      int *const err)
1042*c0909341SAndroid Build Coastguard Worker {
1043*c0909341SAndroid Build Coastguard Worker     if (*err)
1044*c0909341SAndroid Build Coastguard Worker         return 0;
1045*c0909341SAndroid Build Coastguard Worker     if (!checkasm_fail_func("%s:%d", file, line))
1046*c0909341SAndroid Build Coastguard Worker         return 1;
1047*c0909341SAndroid Build Coastguard Worker     *err = 1;
1048*c0909341SAndroid Build Coastguard Worker     fprintf(stderr, "%s (%dx%d):\n", name, w, h);
1049*c0909341SAndroid Build Coastguard Worker     return 0;
1050*c0909341SAndroid Build Coastguard Worker }
1051*c0909341SAndroid Build Coastguard Worker 
1052*c0909341SAndroid Build Coastguard Worker #define DEF_CHECKASM_CHECK_FUNC(type, fmt) \
1053*c0909341SAndroid Build Coastguard Worker int checkasm_check_##type(const char *const file, const int line, \
1054*c0909341SAndroid Build Coastguard Worker                           const type *buf1, ptrdiff_t stride1, \
1055*c0909341SAndroid Build Coastguard Worker                           const type *buf2, ptrdiff_t stride2, \
1056*c0909341SAndroid Build Coastguard Worker                           const int w, int h, const char *const name, \
1057*c0909341SAndroid Build Coastguard Worker                           const int align_w, const int align_h, \
1058*c0909341SAndroid Build Coastguard Worker                           const int padding) \
1059*c0909341SAndroid Build Coastguard Worker { \
1060*c0909341SAndroid Build Coastguard Worker     int aligned_w = (w + align_w - 1) & ~(align_w - 1); \
1061*c0909341SAndroid Build Coastguard Worker     int aligned_h = (h + align_h - 1) & ~(align_h - 1); \
1062*c0909341SAndroid Build Coastguard Worker     int err = 0; \
1063*c0909341SAndroid Build Coastguard Worker     stride1 /= sizeof(*buf1); \
1064*c0909341SAndroid Build Coastguard Worker     stride2 /= sizeof(*buf2); \
1065*c0909341SAndroid Build Coastguard Worker     int y = 0; \
1066*c0909341SAndroid Build Coastguard Worker     for (y = 0; y < h; y++) \
1067*c0909341SAndroid Build Coastguard Worker         if (memcmp(&buf1[y*stride1], &buf2[y*stride2], w*sizeof(*buf1))) \
1068*c0909341SAndroid Build Coastguard Worker             break; \
1069*c0909341SAndroid Build Coastguard Worker     if (y != h) { \
1070*c0909341SAndroid Build Coastguard Worker         if (check_err(file, line, name, w, h, &err)) \
1071*c0909341SAndroid Build Coastguard Worker             return 1; \
1072*c0909341SAndroid Build Coastguard Worker         for (y = 0; y < h; y++) { \
1073*c0909341SAndroid Build Coastguard Worker             for (int x = 0; x < w; x++) \
1074*c0909341SAndroid Build Coastguard Worker                 fprintf(stderr, " " fmt, buf1[x]); \
1075*c0909341SAndroid Build Coastguard Worker             fprintf(stderr, "    "); \
1076*c0909341SAndroid Build Coastguard Worker             for (int x = 0; x < w; x++) \
1077*c0909341SAndroid Build Coastguard Worker                 fprintf(stderr, " " fmt, buf2[x]); \
1078*c0909341SAndroid Build Coastguard Worker             fprintf(stderr, "    "); \
1079*c0909341SAndroid Build Coastguard Worker             for (int x = 0; x < w; x++) \
1080*c0909341SAndroid Build Coastguard Worker                 fprintf(stderr, "%c", buf1[x] != buf2[x] ? 'x' : '.'); \
1081*c0909341SAndroid Build Coastguard Worker             buf1 += stride1; \
1082*c0909341SAndroid Build Coastguard Worker             buf2 += stride2; \
1083*c0909341SAndroid Build Coastguard Worker             fprintf(stderr, "\n"); \
1084*c0909341SAndroid Build Coastguard Worker         } \
1085*c0909341SAndroid Build Coastguard Worker         buf1 -= h*stride1; \
1086*c0909341SAndroid Build Coastguard Worker         buf2 -= h*stride2; \
1087*c0909341SAndroid Build Coastguard Worker     } \
1088*c0909341SAndroid Build Coastguard Worker     for (y = -padding; y < 0; y++) \
1089*c0909341SAndroid Build Coastguard Worker         if (memcmp(&buf1[y*stride1 - padding], &buf2[y*stride2 - padding], \
1090*c0909341SAndroid Build Coastguard Worker                    (w + 2*padding)*sizeof(*buf1))) { \
1091*c0909341SAndroid Build Coastguard Worker             if (check_err(file, line, name, w, h, &err)) \
1092*c0909341SAndroid Build Coastguard Worker                 return 1; \
1093*c0909341SAndroid Build Coastguard Worker             fprintf(stderr, " overwrite above\n"); \
1094*c0909341SAndroid Build Coastguard Worker             break; \
1095*c0909341SAndroid Build Coastguard Worker         } \
1096*c0909341SAndroid Build Coastguard Worker     for (y = aligned_h; y < aligned_h + padding; y++) \
1097*c0909341SAndroid Build Coastguard Worker         if (memcmp(&buf1[y*stride1 - padding], &buf2[y*stride2 - padding], \
1098*c0909341SAndroid Build Coastguard Worker                    (w + 2*padding)*sizeof(*buf1))) { \
1099*c0909341SAndroid Build Coastguard Worker             if (check_err(file, line, name, w, h, &err)) \
1100*c0909341SAndroid Build Coastguard Worker                 return 1; \
1101*c0909341SAndroid Build Coastguard Worker             fprintf(stderr, " overwrite below\n"); \
1102*c0909341SAndroid Build Coastguard Worker             break; \
1103*c0909341SAndroid Build Coastguard Worker         } \
1104*c0909341SAndroid Build Coastguard Worker     for (y = 0; y < h; y++) \
1105*c0909341SAndroid Build Coastguard Worker         if (memcmp(&buf1[y*stride1 - padding], &buf2[y*stride2 - padding], \
1106*c0909341SAndroid Build Coastguard Worker                    padding*sizeof(*buf1))) { \
1107*c0909341SAndroid Build Coastguard Worker             if (check_err(file, line, name, w, h, &err)) \
1108*c0909341SAndroid Build Coastguard Worker                 return 1; \
1109*c0909341SAndroid Build Coastguard Worker             fprintf(stderr, " overwrite left\n"); \
1110*c0909341SAndroid Build Coastguard Worker             break; \
1111*c0909341SAndroid Build Coastguard Worker         } \
1112*c0909341SAndroid Build Coastguard Worker     for (y = 0; y < h; y++) \
1113*c0909341SAndroid Build Coastguard Worker         if (memcmp(&buf1[y*stride1 + aligned_w], &buf2[y*stride2 + aligned_w], \
1114*c0909341SAndroid Build Coastguard Worker                    padding*sizeof(*buf1))) { \
1115*c0909341SAndroid Build Coastguard Worker             if (check_err(file, line, name, w, h, &err)) \
1116*c0909341SAndroid Build Coastguard Worker                 return 1; \
1117*c0909341SAndroid Build Coastguard Worker             fprintf(stderr, " overwrite right\n"); \
1118*c0909341SAndroid Build Coastguard Worker             break; \
1119*c0909341SAndroid Build Coastguard Worker         } \
1120*c0909341SAndroid Build Coastguard Worker     return err; \
1121*c0909341SAndroid Build Coastguard Worker }
1122*c0909341SAndroid Build Coastguard Worker 
1123*c0909341SAndroid Build Coastguard Worker DEF_CHECKASM_CHECK_FUNC(int8_t,   "%4d")
1124*c0909341SAndroid Build Coastguard Worker DEF_CHECKASM_CHECK_FUNC(int16_t,  "%6d")
1125*c0909341SAndroid Build Coastguard Worker DEF_CHECKASM_CHECK_FUNC(int32_t,  "%9d")
1126*c0909341SAndroid Build Coastguard Worker DEF_CHECKASM_CHECK_FUNC(uint8_t,  "%02x")
1127*c0909341SAndroid Build Coastguard Worker DEF_CHECKASM_CHECK_FUNC(uint16_t, "%04x")
1128*c0909341SAndroid Build Coastguard Worker DEF_CHECKASM_CHECK_FUNC(uint32_t, "%08x")
1129*c0909341SAndroid Build Coastguard Worker 
1130*c0909341SAndroid Build Coastguard Worker #if ARCH_X86_64
checkasm_simd_warmup(void)1131*c0909341SAndroid Build Coastguard Worker void checkasm_simd_warmup(void)
1132*c0909341SAndroid Build Coastguard Worker {
1133*c0909341SAndroid Build Coastguard Worker     if (state.simd_warmup)
1134*c0909341SAndroid Build Coastguard Worker         state.simd_warmup();
1135*c0909341SAndroid Build Coastguard Worker }
1136*c0909341SAndroid Build Coastguard Worker #endif
1137*c0909341SAndroid Build Coastguard Worker 
1138*c0909341SAndroid Build Coastguard Worker #if ARCH_ARM
1139*c0909341SAndroid Build Coastguard Worker void (*checkasm_checked_call_ptr)(void *func, int dummy, ...);
1140*c0909341SAndroid Build Coastguard Worker #endif
1141