FFmpeg
tests.c
Go to the documentation of this file.
1 #include <inttypes.h>
2 #include <stdio.h>
3 
4 #include "tests.h"
5 
6 #if ARCH_X86
7 
8 /* Re-use helpers from main checkasm library */
9 #include "src/cpu.h"
10 
11 uint64_t selftest_get_cpu_flags_x86(void)
12 {
13  uint64_t flags = SELFTEST_CPU_FLAG_X86;
14  CpuidRegisters r;
15  checkasm_cpu_cpuid(&r, 0, 0);
16  const uint32_t max_leaf = r.eax;
17  if (max_leaf < 1)
18  return flags;
19 
20  checkasm_cpu_cpuid(&r, 1, 0);
21  if (r.edx & 0x00800000) /* MMX */
22  flags |= SELFTEST_CPU_FLAG_MMX;
23  if (r.edx & 0x02000000) /* SSE2 */
24  flags |= SELFTEST_CPU_FLAG_SSE2;
25  if (~r.ecx & 0x18000000) /* OSXSAVE/AVX */
26  return flags;
27 
28  const uint64_t xcr0 = checkasm_cpu_xgetbv(0);
29  if (max_leaf < 7 || ~xcr0 & 0x6) /* XMM/YMM */
30  return flags;
31 
32  checkasm_cpu_cpuid(&r, 7, 0);
33  if (r.ebx & 0x00000020) /* AVX2 */
34  flags |= SELFTEST_CPU_FLAG_AVX2;
35 
36  if (~xcr0 & 0xe0) /* ZMM/OPMASK */
37  return flags;
38 
39  if (r.ebx & 0x00000020) /* AVX512F */
40  flags |= SELFTEST_CPU_FLAG_AVX512;
41  return flags;
42 }
43 
44 DEF_COPY_FUNC(copy_x86);
45 DEF_COPY_FUNC(copy_mmx);
46 DEF_COPY_FUNC(copy_sse2);
47 DEF_COPY_FUNC(copy_avx2);
48 DEF_COPY_FUNC(copy_avx512);
49 
50 DEF_NOOP_FUNC(clobber_r0);
51 DEF_NOOP_FUNC(clobber_r1);
52 DEF_NOOP_FUNC(clobber_r2);
53 DEF_NOOP_FUNC(clobber_r3);
54 DEF_NOOP_FUNC(clobber_r4);
55 DEF_NOOP_FUNC(clobber_r5);
56 DEF_NOOP_FUNC(clobber_r6);
57 #if ARCH_X86_64
58 DEF_NOOP_FUNC(clobber_r7);
59 DEF_NOOP_FUNC(clobber_r8);
60 DEF_NOOP_FUNC(clobber_r9);
61 DEF_NOOP_FUNC(clobber_r10);
62 DEF_NOOP_FUNC(clobber_r11);
63 DEF_NOOP_FUNC(clobber_r12);
64 DEF_NOOP_FUNC(clobber_r13);
65 DEF_NOOP_FUNC(clobber_r14);
66 #endif
67 
68 DEF_NOOP_FUNC(sigill_x86);
69 DEF_NOOP_FUNC(corrupt_stack_x86);
70 
71 DEF_COPY_FUNC(copy_noemms_mmx);
72 DEF_COPY_FUNC(copy_novzeroupper_avx2);
73 
74 static copy_func *get_copy_x86(void)
75 {
76  const uint64_t flags = checkasm_get_cpu_flags();
77 #if ARCH_X86
78  if (flags & SELFTEST_CPU_FLAG_AVX512)
79  return selftest_copy_avx512;
80  if (flags & SELFTEST_CPU_FLAG_AVX2)
81  return selftest_copy_avx2;
82  if (flags & SELFTEST_CPU_FLAG_SSE2)
83  return selftest_copy_sse2;
84  if (flags & SELFTEST_CPU_FLAG_MMX)
85  return selftest_copy_mmx;
86  if (flags & SELFTEST_CPU_FLAG_X86)
87  return selftest_copy_x86;
88 #endif
89  return selftest_copy_c;
90 }
91 
92 #if ARCH_X86_64
93  #ifdef _WIN32
94  #define NUM_SAFE 7
95  #else
96  #define NUM_SAFE 9
97  #endif
98  #define NUM_REGS 15
99  #define STACK_ALIGN 16
100 #else
101  #define NUM_SAFE 3
102  #define NUM_REGS 7
103  #define STACK_ALIGN 4
104 #endif
105 
106 static noop_func *get_clobber(int reg)
107 {
108  if (!(checkasm_get_cpu_flags() & SELFTEST_CPU_FLAG_X86))
109  return NULL;
110 
111  switch (reg) {
112  case 0: return selftest_clobber_r0;
113  case 1: return selftest_clobber_r1;
114  case 2: return selftest_clobber_r2;
115  case 3: return selftest_clobber_r3;
116  case 4: return selftest_clobber_r4;
117  case 5: return selftest_clobber_r5;
118  case 6: return selftest_clobber_r6;
119 #if ARCH_X86_64
120  case 7: return selftest_clobber_r7;
121  case 8: return selftest_clobber_r8;
122  case 9: return selftest_clobber_r9;
123  case 10: return selftest_clobber_r10;
124  case 11: return selftest_clobber_r11;
125  case 12: return selftest_clobber_r12;
126  case 13: return selftest_clobber_r13;
127  case 14: return selftest_clobber_r14;
128 #endif
129  /* can't clobber rsp without completely crashing the program */
130  default: return NULL;
131  }
132 }
133 
134 DEF_NOOP_GETTER(SELFTEST_CPU_FLAG_X86, sigill_x86)
135 DEF_NOOP_GETTER(SELFTEST_CPU_FLAG_X86, corrupt_stack_x86)
136 DEF_COPY_GETTER(SELFTEST_CPU_FLAG_MMX, copy_noemms_mmx)
137 DEF_COPY_GETTER(SELFTEST_CPU_FLAG_AVX2, copy_novzeroupper_avx2)
138 
139 uintptr_t selftest_get_stack_pointer_x86(int unused);
140 
141 static void check_stack_alignment(void)
142 {
143  checkasm_declare(uintptr_t, int);
144 
145  if (checkasm_check_func(selftest_get_stack_pointer_x86, "stack_alignment")) {
146  uintptr_t sp = checkasm_call_new(0);
147 
148  /* Subtract return address */
149  sp -= sizeof(sp);
150  if (sp & (STACK_ALIGN - 1)) {
151  if (checkasm_fail()) {
152  fprintf(stderr, "stack pointer not %d-byte aligned: 0x%" PRIxPTR "\n",
153  STACK_ALIGN, sp);
154  }
155  }
156  }
157 }
158 
159 static void check_clobber(int from, int to)
160 {
161  checkasm_declare(void, int);
162 
163  for (int reg = from; reg < to; reg++) {
164  noop_func *clobber = get_clobber(reg);
165  if (!clobber)
166  break;
167 
168  if (checkasm_check_func(clobber, "clobber_r%d", reg)) {
170  }
171  }
172 
173  checkasm_report("clobber");
174 }
175 
176 static void test_copy_emms(copy_func fun, const char *name)
177 {
178  CHECKASM_ALIGN(uint8_t c_dst[256]);
179  CHECKASM_ALIGN(uint8_t a_dst[256]);
180  CHECKASM_ALIGN(uint8_t src[256]);
182 
183  checkasm_declare_emms(SELFTEST_CPU_FLAG_MMX, void, uint8_t *dest,
184  const uint8_t *src, size_t n);
185 
186  for (size_t w = 8; w <= 256; w *= 2) {
187  if (checkasm_check_func(fun, "%s_%zu", name, w)) {
188  CLEAR_BUF(c_dst);
189  CLEAR_BUF(a_dst);
190 
191  checkasm_call_ref(c_dst, src, w);
192  checkasm_call_new(a_dst, src, w);
193  checkasm_check(uint8_t, c_dst, 0, a_dst, 0, 256, 1, "dst data");
194  checkasm_bench_new(a_dst, src, w);
195  }
196  }
197 
198  checkasm_report("%s", name);
199 }
200 
201 void selftest_check_x86(void)
202 {
203  selftest_test_copy(get_copy_x86(), "copy", 1);
204  test_copy_emms(get_copy_noemms_mmx(), "copy_noemms");
205  check_stack_alignment();
206  check_clobber(0, NUM_SAFE);
207 
208  if (!checkasm_should_fail(SELFTEST_CPU_FLAG_X86))
209  return;
210 
211  selftest_test_noop(get_sigill_x86(), "sigill");
212  selftest_test_noop(get_corrupt_stack_x86(), "corrupt_stack");
213  selftest_test_copy(get_copy_noemms_mmx(), "noemms", 8);
214  check_clobber(NUM_SAFE, NUM_REGS);
215 
216  if (checkasm_get_check_vzeroupper())
217  selftest_test_copy(get_copy_novzeroupper_avx2(), "novzeroupper", 32);
218 }
219 
220 #endif
flags
const SwsFlags flags[]
Definition: swscale.c:85
DEF_COPY_FUNC
#define DEF_COPY_FUNC(NAME)
Definition: tests.h:78
name
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option name
Definition: writing_filters.txt:88
checkasm_declare_emms
#define checkasm_declare_emms(cpu_flags, ret,...)
Definition: x86_32.h:66
checkasm_check_func
#define checkasm_check_func(func,...)
Check if a function should be tested and set up function references.
Definition: test.h:77
r
const char * r
Definition: vf_curves.c:127
DEF_COPY_GETTER
#define DEF_COPY_GETTER(FLAG, NAME)
Definition: tests.h:81
CHECKASM_ALIGN
#define CHECKASM_ALIGN(x)
Declare a variable with platform-specific alignment requirements.
Definition: utils.h:408
INITIALIZE_BUF
#define INITIALIZE_BUF(buf)
Fill a fixed size buffer with pathological test data (convenience macro)
Definition: utils.h:269
selftest_check_x86
void selftest_check_x86(void)
from
const char * from
Definition: jacosubdec.c:64
CLEAR_BUF
#define CLEAR_BUF(buf)
Clear a fixed size buffer (convenience macro)
Definition: utils.h:254
NULL
#define NULL
Definition: coverity.c:32
checkasm_call_ref
#define checkasm_call_ref(...)
Call the reference implementation.
Definition: test.h:366
noop_func
void() noop_func(int unused)
Do nothing.
Definition: tests.h:94
to
const char * to
Definition: webvttdec.c:36
selftest_test_copy
void selftest_test_copy(copy_func fun, const char *name, const int min_width)
Definition: generic.c:37
checkasm_fail
#define checkasm_fail()
Mark the current test as failed.
Definition: test.h:155
cpu.h
checkasm_declare
#define checkasm_declare(ret,...)
Declare a function signature for testing.
Definition: test.h:205
checkasm_report
CHECKASM_API void checkasm_report(const char *name,...) CHECKASM_PRINTF(1
Report test outcome for a named group of functions.
checkasm_get_cpu_flags
CHECKASM_API CheckasmCpu checkasm_get_cpu_flags(void)
Get the current active set of CPU flags.
Definition: checkasm.c:121
tests.h
DEF_NOOP_GETTER
#define DEF_NOOP_GETTER(FLAG, NAME)
Definition: tests.h:98
selftest_test_noop
void selftest_test_noop(noop_func fun, const char *name)
Definition: generic.c:83
DEF_NOOP_FUNC
#define DEF_NOOP_FUNC(NAME)
Definition: tests.h:97
w
uint8_t w
Definition: llvidencdsp.c:39
checkasm_should_fail
CHECKASM_API int checkasm_should_fail(CheckasmCpu cpu_flags)
Mark a block of tests as expected to fail.
Definition: checkasm.c:1017
checkasm_call_new
#define checkasm_call_new(...)
Call the implementation being tested with validation.
Definition: test.h:381
selftest_get_cpu_flags_x86
uint64_t selftest_get_cpu_flags_x86(void)
copy_func
void() copy_func(uint8_t *dst, const uint8_t *src, size_t size)
Copy size (power-of-two) bytes from aligned buffers src to dst.
Definition: tests.h:75
src
#define src
Definition: vp8dsp.c:248
checkasm_bench_new
#define checkasm_bench_new(...)
Benchmark the optimized implementation.
Definition: test.h:446