checkasm: fix build on ARM
[x264/x264-sandbox.git] / tools / checkasm.c
1 /*****************************************************************************
2  * checkasm.c: assembly check tool
3  *****************************************************************************
4  * Copyright (C) 2003-2011 x264 project
5  *
6  * Authors: Loren Merritt <lorenm@u.washington.edu>
7  *          Laurent Aimar <fenrir@via.ecp.fr>
8  *          Fiona Glaser <fiona@x264.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
23  *
24  * This program is also available under a commercial proprietary license.
25  * For more information, contact us at licensing@x264.com.
26  *****************************************************************************/
27
28 #include <ctype.h>
29 #include "common/common.h"
30 #include "common/cpu.h"
31
32 // GCC doesn't align stack variables on ARM, so use .bss
33 #if ARCH_ARM
34 #undef ALIGNED_16
35 #define ALIGNED_16( var ) DECLARE_ALIGNED( static var, 16 )
36 #endif
37
38 /* buf1, buf2: initialised to random data and shouldn't write into them */
39 uint8_t *buf1, *buf2;
40 /* buf3, buf4: used to store output */
41 uint8_t *buf3, *buf4;
42 /* pbuf1, pbuf2: initialised to random pixel data and shouldn't write into them. */
43 pixel *pbuf1, *pbuf2;
44 /* pbuf3, pbuf4: point to buf3, buf4, just for type convenience */
45 pixel *pbuf3, *pbuf4;
46
47 int quiet = 0;
48
49 #define report( name ) { \
50     if( used_asm && !quiet ) \
51         fprintf( stderr, " - %-21s [%s]\n", name, ok ? "OK" : "FAILED" ); \
52     if( !ok ) ret = -1; \
53 }
54
55 #define BENCH_RUNS 100  // tradeoff between accuracy and speed
56 #define BENCH_ALIGNS 16 // number of stack+heap data alignments (another accuracy vs speed tradeoff)
57 #define MAX_FUNCS 1000  // just has to be big enough to hold all the existing functions
58 #define MAX_CPUS 10     // number of different combinations of cpu flags
59
60 typedef struct
61 {
62     void *pointer; // just for detecting duplicates
63     uint32_t cpu;
64     uint32_t cycles;
65     uint32_t den;
66 } bench_t;
67
68 typedef struct
69 {
70     char *name;
71     bench_t vers[MAX_CPUS];
72 } bench_func_t;
73
74 int do_bench = 0;
75 int bench_pattern_len = 0;
76 const char *bench_pattern = "";
77 char func_name[100];
78 static bench_func_t benchs[MAX_FUNCS];
79
80 static const char *pixel_names[12] = { "16x16", "16x8", "8x16", "8x8", "8x4", "4x8", "4x4", "4x16", "4x2", "2x8", "2x4", "2x2" };
81 static const char *intra_predict_16x16_names[7] = { "v", "h", "dc", "p", "dcl", "dct", "dc8" };
82 static const char *intra_predict_8x8c_names[7] = { "dc", "h", "v", "p", "dcl", "dct", "dc8" };
83 static const char *intra_predict_4x4_names[12] = { "v", "h", "dc", "ddl", "ddr", "vr", "hd", "vl", "hu", "dcl", "dct", "dc8" };
84 static const char **intra_predict_8x8_names = intra_predict_4x4_names;
85 static const char **intra_predict_8x16c_names = intra_predict_8x8c_names;
86
87 #define set_func_name(...) snprintf( func_name, sizeof(func_name), __VA_ARGS__ )
88
89 static inline uint32_t read_time(void)
90 {
91     uint32_t a = 0;
92 #if HAVE_X86_INLINE_ASM
93     asm volatile( "rdtsc" :"=a"(a) ::"edx" );
94 #elif ARCH_PPC
95     asm volatile( "mftb %0" : "=r" (a) );
96 #elif ARCH_ARM     // ARMv7 only
97     asm volatile( "mrc p15, 0, %0, c9, c13, 0" : "=r"(a) );
98 #endif
99     return a;
100 }
101
102 static bench_t* get_bench( const char *name, int cpu )
103 {
104     int i, j;
105     for( i = 0; benchs[i].name && strcmp(name, benchs[i].name); i++ )
106         assert( i < MAX_FUNCS );
107     if( !benchs[i].name )
108         benchs[i].name = strdup( name );
109     if( !cpu )
110         return &benchs[i].vers[0];
111     for( j = 1; benchs[i].vers[j].cpu && benchs[i].vers[j].cpu != cpu; j++ )
112         assert( j < MAX_CPUS );
113     benchs[i].vers[j].cpu = cpu;
114     return &benchs[i].vers[j];
115 }
116
117 static int cmp_nop( const void *a, const void *b )
118 {
119     return *(uint16_t*)a - *(uint16_t*)b;
120 }
121
122 static int cmp_bench( const void *a, const void *b )
123 {
124     // asciibetical sort except preserving numbers
125     const char *sa = ((bench_func_t*)a)->name;
126     const char *sb = ((bench_func_t*)b)->name;
127     for( ;; sa++, sb++ )
128     {
129         if( !*sa && !*sb )
130             return 0;
131         if( isdigit( *sa ) && isdigit( *sb ) && isdigit( sa[1] ) != isdigit( sb[1] ) )
132             return isdigit( sa[1] ) - isdigit( sb[1] );
133         if( *sa != *sb )
134             return *sa - *sb;
135     }
136 }
137
138 static void print_bench(void)
139 {
140     uint16_t nops[10000] = {0};
141     int nfuncs, nop_time=0;
142
143     for( int i = 0; i < 10000; i++ )
144     {
145         int t = read_time();
146         nops[i] = read_time() - t;
147     }
148     qsort( nops, 10000, sizeof(uint16_t), cmp_nop );
149     for( int i = 500; i < 9500; i++ )
150         nop_time += nops[i];
151     nop_time /= 900;
152     printf( "nop: %d\n", nop_time );
153
154     for( nfuncs = 0; nfuncs < MAX_FUNCS && benchs[nfuncs].name; nfuncs++ );
155     qsort( benchs, nfuncs, sizeof(bench_func_t), cmp_bench );
156     for( int i = 0; i < nfuncs; i++ )
157         for( int j = 0; j < MAX_CPUS && (!j || benchs[i].vers[j].cpu); j++ )
158         {
159             int k;
160             bench_t *b = &benchs[i].vers[j];
161             if( !b->den )
162                 continue;
163             for( k = 0; k < j && benchs[i].vers[k].pointer != b->pointer; k++ );
164             if( k < j )
165                 continue;
166             printf( "%s_%s%s: %"PRId64"\n", benchs[i].name,
167                     b->cpu&X264_CPU_FMA4 ? "fma4" :
168                     b->cpu&X264_CPU_XOP ? "xop" :
169                     b->cpu&X264_CPU_AVX ? "avx" :
170                     b->cpu&X264_CPU_SSE4 ? "sse4" :
171                     b->cpu&X264_CPU_SHUFFLE_IS_FAST ? "fastshuffle" :
172                     b->cpu&X264_CPU_SSSE3 ? "ssse3" :
173                     b->cpu&X264_CPU_SSE3 ? "sse3" :
174                     /* print sse2slow only if there's also a sse2fast version of the same func */
175                     b->cpu&X264_CPU_SSE2_IS_SLOW && j<MAX_CPUS && b[1].cpu&X264_CPU_SSE2_IS_FAST && !(b[1].cpu&X264_CPU_SSE3) ? "sse2slow" :
176                     b->cpu&X264_CPU_SSE2 ? "sse2" :
177                     b->cpu&X264_CPU_MMX ? "mmx" :
178                     b->cpu&X264_CPU_ALTIVEC ? "altivec" :
179                     b->cpu&X264_CPU_NEON ? "neon" :
180                     b->cpu&X264_CPU_ARMV6 ? "armv6" : "c",
181                     b->cpu&X264_CPU_CACHELINE_32 ? "_c32" :
182                     b->cpu&X264_CPU_CACHELINE_64 ? "_c64" :
183                     b->cpu&X264_CPU_SSE_MISALIGN ? "_misalign" :
184                     b->cpu&X264_CPU_LZCNT ? "_lzcnt" :
185                     b->cpu&X264_CPU_FAST_NEON_MRC ? "_fast_mrc" :
186                     b->cpu&X264_CPU_SLOW_CTZ ? "_slow_ctz" :
187                     b->cpu&X264_CPU_SLOW_ATOM ? "_slow_atom" : "",
188                     ((int64_t)10*b->cycles/b->den - nop_time)/4 );
189         }
190 }
191
192 #if ARCH_X86 || ARCH_X86_64
193 int x264_stack_pagealign( int (*func)(), int align );
194 #else
195 #define x264_stack_pagealign( func, align ) func()
196 #endif
197
198 #define call_c1(func,...) func(__VA_ARGS__)
199
200 #if ARCH_X86 || defined(_WIN64)
201 /* detect when callee-saved regs aren't saved.
202  * needs an explicit asm check because it only sometimes crashes in normal use. */
203 intptr_t x264_checkasm_call( intptr_t (*func)(), int *ok, ... );
204 #define call_a1(func,...) x264_checkasm_call((intptr_t(*)())func, &ok, __VA_ARGS__)
205 #else
206 #define call_a1 call_c1
207 #endif
208
209 #define call_bench(func,cpu,...)\
210     if( do_bench && !strncmp(func_name, bench_pattern, bench_pattern_len) )\
211     {\
212         uint32_t tsum = 0;\
213         int tcount = 0;\
214         call_a1(func, __VA_ARGS__);\
215         for( int ti = 0; ti < (cpu?BENCH_RUNS:BENCH_RUNS/4); ti++ )\
216         {\
217             uint32_t t = read_time();\
218             func(__VA_ARGS__);\
219             func(__VA_ARGS__);\
220             func(__VA_ARGS__);\
221             func(__VA_ARGS__);\
222             t = read_time() - t;\
223             if( t*tcount <= tsum*4 && ti > 0 )\
224             {\
225                 tsum += t;\
226                 tcount++;\
227             }\
228         }\
229         bench_t *b = get_bench( func_name, cpu );\
230         b->cycles += tsum;\
231         b->den += tcount;\
232         b->pointer = func;\
233     }
234
235 /* for most functions, run benchmark and correctness test at the same time.
236  * for those that modify their inputs, run the above macros separately */
237 #define call_a(func,...) ({ call_a2(func,__VA_ARGS__); call_a1(func,__VA_ARGS__); })
238 #define call_c(func,...) ({ call_c2(func,__VA_ARGS__); call_c1(func,__VA_ARGS__); })
239 #define call_a2(func,...) ({ call_bench(func,cpu_new,__VA_ARGS__); })
240 #define call_c2(func,...) ({ call_bench(func,0,__VA_ARGS__); })
241
242
243 static int check_pixel( int cpu_ref, int cpu_new )
244 {
245     x264_pixel_function_t pixel_c;
246     x264_pixel_function_t pixel_ref;
247     x264_pixel_function_t pixel_asm;
248     x264_predict_t predict_4x4[12];
249     x264_predict8x8_t predict_8x8[12];
250     x264_predict_8x8_filter_t predict_8x8_filter;
251     ALIGNED_16( pixel edge[36] );
252     uint16_t cost_mv[32];
253     int ret = 0, ok, used_asm;
254
255     x264_pixel_init( 0, &pixel_c );
256     x264_pixel_init( cpu_ref, &pixel_ref );
257     x264_pixel_init( cpu_new, &pixel_asm );
258     x264_predict_4x4_init( 0, predict_4x4 );
259     x264_predict_8x8_init( 0, predict_8x8, &predict_8x8_filter );
260     predict_8x8_filter( pbuf2+40, edge, ALL_NEIGHBORS, ALL_NEIGHBORS );
261
262     // maximize sum
263     for( int i = 0; i < 256; i++ )
264     {
265         int z = i|(i>>4);
266         z ^= z>>2;
267         z ^= z>>1;
268         pbuf4[i] = -(z&1) & PIXEL_MAX;
269         pbuf3[i] = ~pbuf4[i] & PIXEL_MAX;
270     }
271     // random pattern made of maxed pixel differences, in case an intermediate value overflows
272     for( int i = 256; i < 0x1000; i++ )
273     {
274         pbuf4[i] = -(pbuf1[i&~0x88]&1) & PIXEL_MAX;
275         pbuf3[i] = ~(pbuf4[i]) & PIXEL_MAX;
276     }
277
278 #define TEST_PIXEL( name, align ) \
279     ok = 1, used_asm = 0; \
280     for( int i = 0; i < 8; i++ ) \
281     { \
282         int res_c, res_asm; \
283         if( pixel_asm.name[i] != pixel_ref.name[i] ) \
284         { \
285             set_func_name( "%s_%s", #name, pixel_names[i] ); \
286             used_asm = 1; \
287             for( int j = 0; j < 64; j++ ) \
288             { \
289                 res_c   = call_c( pixel_c.name[i], pbuf1, 16, pbuf2+j*!align, 64 ); \
290                 res_asm = call_a( pixel_asm.name[i], pbuf1, 16, pbuf2+j*!align, 64 ); \
291                 if( res_c != res_asm ) \
292                 { \
293                     ok = 0; \
294                     fprintf( stderr, #name "[%d]: %d != %d [FAILED]\n", i, res_c, res_asm ); \
295                     break; \
296                 } \
297             } \
298             for( int j = 0; j < 0x1000 && ok; j += 256 ) \
299             { \
300                 res_c   = pixel_c  .name[i]( pbuf3+j, 16, pbuf4+j, 16 ); \
301                 res_asm = pixel_asm.name[i]( pbuf3+j, 16, pbuf4+j, 16 ); \
302                 if( res_c != res_asm ) \
303                 { \
304                     ok = 0; \
305                     fprintf( stderr, #name "[%d]: overflow %d != %d\n", i, res_c, res_asm ); \
306                 } \
307             } \
308         } \
309     } \
310     report( "pixel " #name " :" );
311
312     TEST_PIXEL( sad, 0 );
313     TEST_PIXEL( sad_aligned, 1 );
314     TEST_PIXEL( ssd, 1 );
315     TEST_PIXEL( satd, 0 );
316     TEST_PIXEL( sa8d, 1 );
317
318 #define TEST_PIXEL_X( N ) \
319     ok = 1; used_asm = 0; \
320     for( int i = 0; i < 7; i++ ) \
321     { \
322         int res_c[4]={0}, res_asm[4]={0}; \
323         if( pixel_asm.sad_x##N[i] && pixel_asm.sad_x##N[i] != pixel_ref.sad_x##N[i] ) \
324         { \
325             set_func_name( "sad_x%d_%s", N, pixel_names[i] ); \
326             used_asm = 1; \
327             for( int j = 0; j < 64; j++ ) \
328             { \
329                 pixel *pix2 = pbuf2+j; \
330                 res_c[0] = pixel_c.sad[i]( pbuf1, 16, pix2, 64 ); \
331                 res_c[1] = pixel_c.sad[i]( pbuf1, 16, pix2+6, 64 ); \
332                 res_c[2] = pixel_c.sad[i]( pbuf1, 16, pix2+1, 64 ); \
333                 if( N == 4 ) \
334                 { \
335                     res_c[3] = pixel_c.sad[i]( pbuf1, 16, pix2+10, 64 ); \
336                     call_a( pixel_asm.sad_x4[i], pbuf1, pix2, pix2+6, pix2+1, pix2+10, 64, res_asm ); \
337                 } \
338                 else \
339                     call_a( pixel_asm.sad_x3[i], pbuf1, pix2, pix2+6, pix2+1, 64, res_asm ); \
340                 if( memcmp(res_c, res_asm, sizeof(res_c)) ) \
341                 { \
342                     ok = 0; \
343                     fprintf( stderr, "sad_x"#N"[%d]: %d,%d,%d,%d != %d,%d,%d,%d [FAILED]\n", \
344                              i, res_c[0], res_c[1], res_c[2], res_c[3], \
345                              res_asm[0], res_asm[1], res_asm[2], res_asm[3] ); \
346                 } \
347                 if( N == 4 ) \
348                     call_c2( pixel_c.sad_x4[i], pbuf1, pix2, pix2+6, pix2+1, pix2+10, 64, res_asm ); \
349                 else \
350                     call_c2( pixel_c.sad_x3[i], pbuf1, pix2, pix2+6, pix2+1, 64, res_asm ); \
351             } \
352         } \
353     } \
354     report( "pixel sad_x"#N" :" );
355
356     TEST_PIXEL_X(3);
357     TEST_PIXEL_X(4);
358
359 #define TEST_PIXEL_VAR( i ) \
360     if( pixel_asm.var[i] != pixel_ref.var[i] ) \
361     { \
362         set_func_name( "%s_%s", "var", pixel_names[i] ); \
363         used_asm = 1; \
364         /* abi-check wrapper can't return uint64_t, so separate it from return value check */ \
365         call_c1( pixel_c.var[i], pbuf1, 16 ); \
366         call_a1( pixel_asm.var[i], pbuf1, 16 ); \
367         uint64_t res_c   = pixel_c.var[i]( pbuf1, 16 ); \
368         uint64_t res_asm = pixel_asm.var[i]( pbuf1, 16 ); \
369         if( res_c != res_asm ) \
370         { \
371             ok = 0; \
372             fprintf( stderr, "var[%d]: %d %d != %d %d [FAILED]\n", i, (int)res_c, (int)(res_c>>32), (int)res_asm, (int)(res_asm>>32) ); \
373         } \
374         call_c2( pixel_c.var[i], pbuf1, 16 ); \
375         call_a2( pixel_asm.var[i], pbuf1, 16 ); \
376     }
377
378     ok = 1; used_asm = 0;
379     TEST_PIXEL_VAR( PIXEL_16x16 );
380     TEST_PIXEL_VAR( PIXEL_8x16 );
381     TEST_PIXEL_VAR( PIXEL_8x8 );
382     report( "pixel var :" );
383
384 #define TEST_PIXEL_VAR2( i ) \
385     if( pixel_asm.var2[i] != pixel_ref.var2[i] ) \
386     { \
387         int res_c, res_asm, ssd_c, ssd_asm; \
388         set_func_name( "%s_%s", "var2", pixel_names[i] ); \
389         used_asm = 1; \
390         res_c   = call_c( pixel_c.var2[i], pbuf1, 16, pbuf2, 16, &ssd_c ); \
391         res_asm = call_a( pixel_asm.var2[i], pbuf1, 16, pbuf2, 16, &ssd_asm ); \
392         if( res_c != res_asm || ssd_c != ssd_asm ) \
393         { \
394             ok = 0; \
395             fprintf( stderr, "var2[%d]: %d != %d or %d != %d [FAILED]\n", i, res_c, res_asm, ssd_c, ssd_asm ); \
396         } \
397     }
398
399     ok = 1; used_asm = 0;
400     TEST_PIXEL_VAR2( PIXEL_8x16 );
401     TEST_PIXEL_VAR2( PIXEL_8x8 );
402     report( "pixel var2 :" );
403
404     ok = 1; used_asm = 0;
405     for( int i = 0; i < 4; i++ )
406         if( pixel_asm.hadamard_ac[i] != pixel_ref.hadamard_ac[i] )
407         {
408             set_func_name( "hadamard_ac_%s", pixel_names[i] );
409             used_asm = 1;
410             for( int j = 0; j < 32; j++ )
411             {
412                 pixel *pix = (j&16 ? pbuf1 : pbuf3) + (j&15)*256;
413                 call_c1( pixel_c.hadamard_ac[i], pbuf1, 16 );
414                 call_a1( pixel_asm.hadamard_ac[i], pbuf1, 16 );
415                 uint64_t rc = pixel_c.hadamard_ac[i]( pix, 16 );
416                 uint64_t ra = pixel_asm.hadamard_ac[i]( pix, 16 );
417                 if( rc != ra )
418                 {
419                     ok = 0;
420                     fprintf( stderr, "hadamard_ac[%d]: %d,%d != %d,%d\n", i, (int)rc, (int)(rc>>32), (int)ra, (int)(ra>>32) );
421                     break;
422                 }
423             }
424             call_c2( pixel_c.hadamard_ac[i], pbuf1, 16 );
425             call_a2( pixel_asm.hadamard_ac[i], pbuf1, 16 );
426         }
427     report( "pixel hadamard_ac :" );
428
429     ok = 1; used_asm = 0;
430     if( pixel_asm.vsad != pixel_ref.vsad )
431     {
432         for( int h = 2; h <= 32; h += 2 )
433         {
434             int res_c, res_asm;
435             set_func_name( "vsad" );
436             used_asm = 1;
437             res_c   = call_c( pixel_c.vsad,   pbuf1, 16, h );
438             res_asm = call_a( pixel_asm.vsad, pbuf1, 16, h );
439             if( res_c != res_asm )
440             {
441                 ok = 0;
442                 fprintf( stderr, "vsad: height=%d, %d != %d\n", h, res_c, res_asm );
443                 break;
444             }
445         }
446     }
447     report( "pixel vsad :" );
448
449 #define TEST_INTRA_X3( name, i8x8, ... ) \
450     if( pixel_asm.name && pixel_asm.name != pixel_ref.name ) \
451     { \
452         int res_c[3], res_asm[3]; \
453         set_func_name( #name ); \
454         used_asm = 1; \
455         call_c( pixel_c.name, pbuf1+48, i8x8 ? edge : pbuf3+48, res_c ); \
456         call_a( pixel_asm.name, pbuf1+48, i8x8 ? edge : pbuf3+48, res_asm ); \
457         if( memcmp(res_c, res_asm, sizeof(res_c)) ) \
458         { \
459             ok = 0; \
460             fprintf( stderr, #name": %d,%d,%d != %d,%d,%d [FAILED]\n", \
461                      res_c[0], res_c[1], res_c[2], \
462                      res_asm[0], res_asm[1], res_asm[2] ); \
463         } \
464     }
465
466 #define TEST_INTRA_X9( name, cmp ) \
467     if( pixel_asm.name && pixel_asm.name != pixel_ref.name ) \
468     { \
469         set_func_name( #name ); \
470         used_asm = 1; \
471         ALIGNED_ARRAY_64( uint16_t, bitcosts,[17] ); \
472         for( int i=0; i<17; i++ ) \
473             bitcosts[i] = 9*(i!=8); \
474         memcpy( pbuf3, pbuf2, 20*FDEC_STRIDE*sizeof(pixel) ); \
475         memcpy( pbuf4, pbuf2, 20*FDEC_STRIDE*sizeof(pixel) ); \
476         for( int i=0; i<32; i++ ) \
477         { \
478             pixel *fenc = pbuf1+48+i*12; \
479             pixel *fdec1 = pbuf3+48+i*12; \
480             pixel *fdec2 = pbuf4+48+i*12; \
481             int pred_mode = i%9; \
482             int res_c = INT_MAX; \
483             for( int j=0; j<9; j++ ) \
484             { \
485                 predict_4x4[j]( fdec1 ); \
486                 int cost = pixel_c.cmp[PIXEL_4x4]( fenc, FENC_STRIDE, fdec1, FDEC_STRIDE ) + 9*(j!=pred_mode); \
487                 if( cost < (uint16_t)res_c ) \
488                     res_c = cost + (j<<16); \
489             } \
490             predict_4x4[res_c>>16]( fdec1 ); \
491             int res_a = call_a( pixel_asm.name, fenc, fdec2, bitcosts+8-pred_mode ); \
492             if( res_c != res_a ) \
493             { \
494                 ok = 0; \
495                 fprintf( stderr, #name": %d,%d != %d,%d [FAILED]\n", res_c>>16, res_c&0xffff, res_a>>16, res_a&0xffff ); \
496                 break; \
497             } \
498             if( memcmp(fdec1, fdec2, 4*FDEC_STRIDE*sizeof(pixel)) ) \
499             { \
500                 ok = 0; \
501                 fprintf( stderr, #name" [FAILED]\n" ); \
502                 for( int j=0; j<16; j++ ) \
503                     fprintf( stderr, "%02x ", fdec1[(j&3)+(j>>2)*FDEC_STRIDE] ); \
504                 fprintf( stderr, "\n" ); \
505                 for( int j=0; j<16; j++ ) \
506                     fprintf( stderr, "%02x ", fdec2[(j&3)+(j>>2)*FDEC_STRIDE] ); \
507                 fprintf( stderr, "\n" ); \
508                 break; \
509             } \
510         } \
511     }
512
513 #define TEST_INTRA8_X9( name, cmp ) \
514     if( pixel_asm.name && pixel_asm.name != pixel_ref.name ) \
515     { \
516         set_func_name( #name ); \
517         used_asm = 1; \
518         ALIGNED_ARRAY_64( uint16_t, bitcosts,[17] ); \
519         ALIGNED_ARRAY_16( uint16_t, satds_c,[16] ); \
520         ALIGNED_ARRAY_16( uint16_t, satds_a,[16] ); \
521         memset( satds_c, 0, 16 * sizeof(*satds_c) ); \
522         memset( satds_a, 0, 16 * sizeof(*satds_a) ); \
523         for( int i=0; i<17; i++ ) \
524             bitcosts[i] = 9*(i!=8); \
525         for( int i=0; i<32; i++ ) \
526         { \
527             pixel *fenc = pbuf1+48+i*12; \
528             pixel *fdec1 = pbuf3+48+i*12; \
529             pixel *fdec2 = pbuf4+48+i*12; \
530             int pred_mode = i%9; \
531             int res_c = INT_MAX; \
532             predict_8x8_filter( fdec1, edge, ALL_NEIGHBORS, ALL_NEIGHBORS ); \
533             for( int j=0; j<9; j++ ) \
534             { \
535                 predict_8x8[j]( fdec1, edge ); \
536                 satds_c[j] = pixel_c.cmp[PIXEL_8x8]( fenc, FENC_STRIDE, fdec1, FDEC_STRIDE ) + 9*(j!=pred_mode); \
537                 if( satds_c[j] < (uint16_t)res_c ) \
538                     res_c = satds_c[j] + (j<<16); \
539             } \
540             predict_8x8[res_c>>16]( fdec1, edge ); \
541             int res_a = call_a( pixel_asm.name, fenc, fdec2, edge, bitcosts+8-pred_mode, satds_a ); \
542             if( res_c != res_a || memcmp(satds_c, satds_a, sizeof(satds_c)) ) \
543             { \
544                 ok = 0; \
545                 fprintf( stderr, #name": %d,%d != %d,%d [FAILED]\n", res_c>>16, res_c&0xffff, res_a>>16, res_a&0xffff ); \
546                 for( int j = 0; j < 9; j++ ) \
547                     fprintf( stderr, "%5d ", satds_c[j]); \
548                 fprintf( stderr, "\n" ); \
549                 for( int j = 0; j < 9; j++ ) \
550                     fprintf( stderr, "%5d ", satds_a[j]); \
551                 fprintf( stderr, "\n" ); \
552                 break; \
553             } \
554             for( int j=0; j<8; j++ ) \
555                 if( memcmp(fdec1+j*FDEC_STRIDE, fdec2+j*FDEC_STRIDE, 8*sizeof(pixel)) ) \
556                     ok = 0; \
557             if( !ok ) \
558             { \
559                 fprintf( stderr, #name" [FAILED]\n" ); \
560                 for( int j=0; j<8; j++ ) \
561                 { \
562                     for( int k=0; k<8; k++ ) \
563                         fprintf( stderr, "%02x ", fdec1[k+j*FDEC_STRIDE] ); \
564                     fprintf( stderr, "\n" ); \
565                 } \
566                 fprintf( stderr, "\n" ); \
567                 for( int j=0; j<8; j++ ) \
568                 { \
569                     for( int k=0; k<8; k++ ) \
570                         fprintf( stderr, "%02x ", fdec2[k+j*FDEC_STRIDE] ); \
571                     fprintf( stderr, "\n" ); \
572                 } \
573                 fprintf( stderr, "\n" ); \
574                 break; \
575             } \
576         } \
577     }
578
579     memcpy( pbuf3, pbuf2, 20*FDEC_STRIDE*sizeof(pixel) );
580     ok = 1; used_asm = 0;
581     TEST_INTRA_X3( intra_satd_x3_16x16, 0 );
582     TEST_INTRA_X3( intra_satd_x3_8x16c, 0 );
583     TEST_INTRA_X3( intra_satd_x3_8x8c, 0 );
584     TEST_INTRA_X3( intra_sa8d_x3_8x8, 1, edge );
585     TEST_INTRA_X3( intra_satd_x3_4x4, 0 );
586     report( "intra satd_x3 :" );
587     ok = 1; used_asm = 0;
588     TEST_INTRA_X3( intra_sad_x3_16x16, 0 );
589     TEST_INTRA_X3( intra_sad_x3_8x16c, 0 );
590     TEST_INTRA_X3( intra_sad_x3_8x8c, 0 );
591     TEST_INTRA_X3( intra_sad_x3_8x8, 1, edge );
592     TEST_INTRA_X3( intra_sad_x3_4x4, 0 );
593     report( "intra sad_x3 :" );
594     ok = 1; used_asm = 0;
595     TEST_INTRA_X9( intra_satd_x9_4x4, satd );
596     TEST_INTRA8_X9( intra_sa8d_x9_8x8, sa8d );
597     report( "intra satd_x9 :" );
598     ok = 1; used_asm = 0;
599     TEST_INTRA_X9( intra_sad_x9_4x4, sad );
600     TEST_INTRA8_X9( intra_sad_x9_8x8, sad );
601     report( "intra sad_x9 :" );
602
603     ok = 1; used_asm = 0;
604     if( pixel_asm.ssd_nv12_core != pixel_ref.ssd_nv12_core )
605     {
606         used_asm = 1;
607         set_func_name( "ssd_nv12" );
608         uint64_t res_u_c, res_v_c, res_u_a, res_v_a;
609         pixel_c.ssd_nv12_core(   pbuf1, 368, pbuf2, 368, 360, 8, &res_u_c, &res_v_c );
610         pixel_asm.ssd_nv12_core( pbuf1, 368, pbuf2, 368, 360, 8, &res_u_a, &res_v_a );
611         if( res_u_c != res_u_a || res_v_c != res_v_a )
612         {
613             ok = 0;
614             fprintf( stderr, "ssd_nv12: %"PRIu64",%"PRIu64" != %"PRIu64",%"PRIu64"\n",
615                      res_u_c, res_v_c, res_u_a, res_v_a );
616         }
617         call_c( pixel_c.ssd_nv12_core,   pbuf1, 368, pbuf2, 368, 360, 8, &res_u_c, &res_v_c );
618         call_a( pixel_asm.ssd_nv12_core, pbuf1, 368, pbuf2, 368, 360, 8, &res_u_a, &res_v_a );
619     }
620     report( "ssd_nv12 :" );
621
622     if( pixel_asm.ssim_4x4x2_core != pixel_ref.ssim_4x4x2_core ||
623         pixel_asm.ssim_end4 != pixel_ref.ssim_end4 )
624     {
625         int cnt;
626         float res_c, res_a;
627         ALIGNED_16( int sums[5][4] ) = {{0}};
628         used_asm = ok = 1;
629         x264_emms();
630         res_c = x264_pixel_ssim_wxh( &pixel_c,   pbuf1+2, 32, pbuf2+2, 32, 32, 28, pbuf3, &cnt );
631         res_a = x264_pixel_ssim_wxh( &pixel_asm, pbuf1+2, 32, pbuf2+2, 32, 32, 28, pbuf3, &cnt );
632         if( fabs( res_c - res_a ) > 1e-6 )
633         {
634             ok = 0;
635             fprintf( stderr, "ssim: %.7f != %.7f [FAILED]\n", res_c, res_a );
636         }
637         set_func_name( "ssim_core" );
638         call_c2( pixel_c.ssim_4x4x2_core,   pbuf1+2, 32, pbuf2+2, 32, sums );
639         call_a2( pixel_asm.ssim_4x4x2_core, pbuf1+2, 32, pbuf2+2, 32, sums );
640         set_func_name( "ssim_end" );
641         call_c2( pixel_c.ssim_end4,   sums, sums, 4 );
642         call_a2( pixel_asm.ssim_end4, sums, sums, 4 );
643         report( "ssim :" );
644     }
645
646     ok = 1; used_asm = 0;
647     for( int i = 0; i < 32; i++ )
648         cost_mv[i] = i*10;
649     for( int i = 0; i < 100 && ok; i++ )
650         if( pixel_asm.ads[i&3] != pixel_ref.ads[i&3] )
651         {
652             ALIGNED_16( uint16_t sums[72] );
653             ALIGNED_16( int dc[4] );
654             int16_t mvs_a[32], mvs_c[32];
655             int mvn_a, mvn_c;
656             int thresh = rand() & 0x3fff;
657             set_func_name( "esa_ads" );
658             for( int j = 0; j < 72; j++ )
659                 sums[j] = rand() & 0x3fff;
660             for( int j = 0; j < 4; j++ )
661                 dc[j] = rand() & 0x3fff;
662             used_asm = 1;
663             mvn_c = call_c( pixel_c.ads[i&3], dc, sums, 32, cost_mv, mvs_c, 28, thresh );
664             mvn_a = call_a( pixel_asm.ads[i&3], dc, sums, 32, cost_mv, mvs_a, 28, thresh );
665             if( mvn_c != mvn_a || memcmp( mvs_c, mvs_a, mvn_c*sizeof(*mvs_c) ) )
666             {
667                 ok = 0;
668                 printf( "c%d: ", i&3 );
669                 for( int j = 0; j < mvn_c; j++ )
670                     printf( "%d ", mvs_c[j] );
671                 printf( "\na%d: ", i&3 );
672                 for( int j = 0; j < mvn_a; j++ )
673                     printf( "%d ", mvs_a[j] );
674                 printf( "\n\n" );
675             }
676         }
677     report( "esa ads:" );
678
679     return ret;
680 }
681
682 static int check_dct( int cpu_ref, int cpu_new )
683 {
684     x264_dct_function_t dct_c;
685     x264_dct_function_t dct_ref;
686     x264_dct_function_t dct_asm;
687     x264_quant_function_t qf;
688     int ret = 0, ok, used_asm, interlace = 0;
689     ALIGNED_16( dctcoef dct1[16][16] );
690     ALIGNED_16( dctcoef dct2[16][16] );
691     ALIGNED_16( dctcoef dct4[16][16] );
692     ALIGNED_16( dctcoef dct8[4][64] );
693     ALIGNED_16( dctcoef dctdc[2][8] );
694     x264_t h_buf;
695     x264_t *h = &h_buf;
696
697     x264_dct_init( 0, &dct_c );
698     x264_dct_init( cpu_ref, &dct_ref);
699     x264_dct_init( cpu_new, &dct_asm );
700
701     memset( h, 0, sizeof(*h) );
702     x264_param_default( &h->param );
703     h->sps->i_chroma_format_idc = 1;
704     h->chroma_qp_table = i_chroma_qp_table + 12;
705     h->param.analyse.i_luma_deadzone[0] = 0;
706     h->param.analyse.i_luma_deadzone[1] = 0;
707     h->param.analyse.b_transform_8x8 = 1;
708     for( int i = 0; i < 6; i++ )
709         h->pps->scaling_list[i] = x264_cqm_flat16;
710     x264_cqm_init( h );
711     x264_quant_init( h, 0, &qf );
712
713     /* overflow test cases */
714     for( int i = 0; i < 5; i++ )
715     {
716         pixel *enc = &pbuf3[16*i*FENC_STRIDE];
717         pixel *dec = &pbuf4[16*i*FDEC_STRIDE];
718
719         for( int j = 0; j < 16; j++ )
720         {
721             int cond_a = (i < 2) ? 1 : ((j&3) == 0 || (j&3) == (i-1));
722             int cond_b = (i == 0) ? 1 : !cond_a;
723             enc[0] = enc[1] = cond_a ? PIXEL_MAX : 0;
724             enc[2] = enc[3] = cond_b ? PIXEL_MAX : 0;
725
726             for( int k = 0; k < 4; k++ )
727                 dec[k] = PIXEL_MAX - enc[k];
728
729             enc += FENC_STRIDE;
730             dec += FDEC_STRIDE;
731         }
732     }
733
734 #define TEST_DCT( name, t1, t2, size ) \
735     if( dct_asm.name != dct_ref.name ) \
736     { \
737         set_func_name( #name ); \
738         used_asm = 1; \
739         pixel *enc = pbuf3; \
740         pixel *dec = pbuf4; \
741         for( int j = 0; j < 5; j++) \
742         { \
743             call_c( dct_c.name, t1, &pbuf1[j*64], &pbuf2[j*64] ); \
744             call_a( dct_asm.name, t2, &pbuf1[j*64], &pbuf2[j*64] ); \
745             if( memcmp( t1, t2, size*sizeof(dctcoef) ) ) \
746             { \
747                 ok = 0; \
748                 fprintf( stderr, #name " [FAILED]\n" ); \
749                 break; \
750             } \
751             call_c( dct_c.name, t1, enc, dec ); \
752             call_a( dct_asm.name, t2, enc, dec ); \
753             if( memcmp( t1, t2, size*sizeof(dctcoef) ) ) \
754             { \
755                 ok = 0; \
756                 fprintf( stderr, #name " [FAILED] (overflow)\n" ); \
757                 break; \
758             } \
759             enc += 16*FENC_STRIDE; \
760             dec += 16*FDEC_STRIDE; \
761         } \
762     }
763     ok = 1; used_asm = 0;
764     TEST_DCT( sub4x4_dct, dct1[0], dct2[0], 16 );
765     TEST_DCT( sub8x8_dct, dct1, dct2, 16*4 );
766     TEST_DCT( sub8x8_dct_dc, dctdc[0], dctdc[1], 4 );
767     TEST_DCT( sub8x16_dct_dc, dctdc[0], dctdc[1], 8 );
768     TEST_DCT( sub16x16_dct, dct1, dct2, 16*16 );
769     report( "sub_dct4 :" );
770
771     ok = 1; used_asm = 0;
772     TEST_DCT( sub8x8_dct8, (void*)dct1[0], (void*)dct2[0], 64 );
773     TEST_DCT( sub16x16_dct8, (void*)dct1, (void*)dct2, 64*4 );
774     report( "sub_dct8 :" );
775 #undef TEST_DCT
776
777     // fdct and idct are denormalized by different factors, so quant/dequant
778     // is needed to force the coefs into the right range.
779     dct_c.sub16x16_dct( dct4, pbuf1, pbuf2 );
780     dct_c.sub16x16_dct8( dct8, pbuf1, pbuf2 );
781     for( int i = 0; i < 16; i++ )
782     {
783         qf.quant_4x4( dct4[i], h->quant4_mf[CQM_4IY][20], h->quant4_bias[CQM_4IY][20] );
784         qf.dequant_4x4( dct4[i], h->dequant4_mf[CQM_4IY], 20 );
785     }
786     for( int i = 0; i < 4; i++ )
787     {
788         qf.quant_8x8( dct8[i], h->quant8_mf[CQM_8IY][20], h->quant8_bias[CQM_8IY][20] );
789         qf.dequant_8x8( dct8[i], h->dequant8_mf[CQM_8IY], 20 );
790     }
791     x264_cqm_delete( h );
792
793 #define TEST_IDCT( name, src ) \
794     if( dct_asm.name != dct_ref.name ) \
795     { \
796         set_func_name( #name ); \
797         used_asm = 1; \
798         memcpy( pbuf3, pbuf1, 32*32 * sizeof(pixel) ); \
799         memcpy( pbuf4, pbuf1, 32*32 * sizeof(pixel) ); \
800         memcpy( dct1, src, 256 * sizeof(dctcoef) ); \
801         memcpy( dct2, src, 256 * sizeof(dctcoef) ); \
802         call_c1( dct_c.name, pbuf3, (void*)dct1 ); \
803         call_a1( dct_asm.name, pbuf4, (void*)dct2 ); \
804         if( memcmp( pbuf3, pbuf4, 32*32 * sizeof(pixel) ) ) \
805         { \
806             ok = 0; \
807             fprintf( stderr, #name " [FAILED]\n" ); \
808         } \
809         call_c2( dct_c.name, pbuf3, (void*)dct1 ); \
810         call_a2( dct_asm.name, pbuf4, (void*)dct2 ); \
811     }
812     ok = 1; used_asm = 0;
813     TEST_IDCT( add4x4_idct, dct4 );
814     TEST_IDCT( add8x8_idct, dct4 );
815     TEST_IDCT( add8x8_idct_dc, dct4 );
816     TEST_IDCT( add16x16_idct, dct4 );
817     TEST_IDCT( add16x16_idct_dc, dct4 );
818     report( "add_idct4 :" );
819
820     ok = 1; used_asm = 0;
821     TEST_IDCT( add8x8_idct8, dct8 );
822     TEST_IDCT( add16x16_idct8, dct8 );
823     report( "add_idct8 :" );
824 #undef TEST_IDCT
825
826 #define TEST_DCTDC( name )\
827     ok = 1; used_asm = 0;\
828     if( dct_asm.name != dct_ref.name )\
829     {\
830         set_func_name( #name );\
831         used_asm = 1;\
832         uint16_t *p = (uint16_t*)buf1;\
833         for( int i = 0; i < 16 && ok; i++ )\
834         {\
835             for( int j = 0; j < 16; j++ )\
836                 dct1[0][j] = !i ? (j^j>>1^j>>2^j>>3)&1 ? PIXEL_MAX*16 : -PIXEL_MAX*16 /* max dc */\
837                            : i<8 ? (*p++)&1 ? PIXEL_MAX*16 : -PIXEL_MAX*16 /* max elements */\
838                            : ((*p++)&0x1fff)-0x1000; /* general case */\
839             memcpy( dct2, dct1, 16 * sizeof(dctcoef) );\
840             call_c1( dct_c.name, dct1[0] );\
841             call_a1( dct_asm.name, dct2[0] );\
842             if( memcmp( dct1, dct2, 16 * sizeof(dctcoef) ) )\
843                 ok = 0;\
844         }\
845         call_c2( dct_c.name, dct1[0] );\
846         call_a2( dct_asm.name, dct2[0] );\
847     }\
848     report( #name " :" );
849
850     TEST_DCTDC(  dct4x4dc );
851     TEST_DCTDC( idct4x4dc );
852 #undef TEST_DCTDC
853
854 #define TEST_DCTDC_CHROMA( name )\
855     ok = 1; used_asm = 0;\
856     if( dct_asm.name != dct_ref.name )\
857     {\
858         set_func_name( #name );\
859         used_asm = 1;\
860         uint16_t *p = (uint16_t*)buf1;\
861         for( int i = 0; i < 16 && ok; i++ )\
862         {\
863             for( int j = 0; j < 8; j++ )\
864                 dct1[j][0] = !i ? (j^j>>1^j>>2)&1 ? PIXEL_MAX*16 : -PIXEL_MAX*16 /* max dc */\
865                            : i<8 ? (*p++)&1 ? PIXEL_MAX*16 : -PIXEL_MAX*16 /* max elements */\
866                            : ((*p++)&0x1fff)-0x1000; /* general case */\
867             memcpy( dct2, dct1, 8*16 * sizeof(dctcoef) );\
868             call_c1( dct_c.name, dctdc[0], dct1 );\
869             call_a1( dct_asm.name, dctdc[1], dct2 );\
870             if( memcmp( dctdc[0], dctdc[1], 8 * sizeof(dctcoef) ) || memcmp( dct1, dct2, 8*16 * sizeof(dctcoef) ) )\
871             {\
872                 ok = 0;\
873                 fprintf( stderr, #name " [FAILED]\n" ); \
874             }\
875         }\
876         call_c2( dct_c.name, dctdc[0], dct1 );\
877         call_a2( dct_asm.name, dctdc[1], dct2 );\
878     }\
879     report( #name " :" );
880
881     TEST_DCTDC_CHROMA( dct2x4dc );
882 #undef TEST_DCTDC_CHROMA
883
884     x264_zigzag_function_t zigzag_c[2];
885     x264_zigzag_function_t zigzag_ref[2];
886     x264_zigzag_function_t zigzag_asm[2];
887
888     ALIGNED_16( dctcoef level1[64] );
889     ALIGNED_16( dctcoef level2[64] );
890
891 #define TEST_ZIGZAG_SCAN( name, t1, t2, dct, size ) \
892     if( zigzag_asm[interlace].name != zigzag_ref[interlace].name ) \
893     { \
894         set_func_name( "zigzag_"#name"_%s", interlace?"field":"frame" ); \
895         used_asm = 1; \
896         memcpy(dct, buf1, size*sizeof(dctcoef)); \
897         call_c( zigzag_c[interlace].name, t1, dct ); \
898         call_a( zigzag_asm[interlace].name, t2, dct ); \
899         if( memcmp( t1, t2, size*sizeof(dctcoef) ) ) \
900         { \
901             ok = 0; \
902             fprintf( stderr, #name " [FAILED]\n" ); \
903         } \
904     }
905
906 #define TEST_ZIGZAG_SUB( name, t1, t2, size ) \
907     if( zigzag_asm[interlace].name != zigzag_ref[interlace].name ) \
908     { \
909         int nz_a, nz_c; \
910         set_func_name( "zigzag_"#name"_%s", interlace?"field":"frame" ); \
911         used_asm = 1; \
912         memcpy( pbuf3, pbuf1, 16*FDEC_STRIDE * sizeof(pixel) ); \
913         memcpy( pbuf4, pbuf1, 16*FDEC_STRIDE * sizeof(pixel) ); \
914         nz_c = call_c1( zigzag_c[interlace].name, t1, pbuf2, pbuf3 ); \
915         nz_a = call_a1( zigzag_asm[interlace].name, t2, pbuf2, pbuf4 ); \
916         if( memcmp( t1, t2, size*sizeof(dctcoef) ) || memcmp( pbuf3, pbuf4, 16*FDEC_STRIDE*sizeof(pixel) ) || nz_c != nz_a ) \
917         { \
918             ok = 0; \
919             fprintf( stderr, #name " [FAILED]\n" ); \
920         } \
921         call_c2( zigzag_c[interlace].name, t1, pbuf2, pbuf3 ); \
922         call_a2( zigzag_asm[interlace].name, t2, pbuf2, pbuf4 ); \
923     }
924
925 #define TEST_ZIGZAG_SUBAC( name, t1, t2 ) \
926     if( zigzag_asm[interlace].name != zigzag_ref[interlace].name ) \
927     { \
928         int nz_a, nz_c; \
929         dctcoef dc_a, dc_c; \
930         set_func_name( "zigzag_"#name"_%s", interlace?"field":"frame" ); \
931         used_asm = 1; \
932         for( int i = 0; i < 2; i++ ) \
933         { \
934             memcpy( pbuf3, pbuf2, 16*FDEC_STRIDE * sizeof(pixel) ); \
935             memcpy( pbuf4, pbuf2, 16*FDEC_STRIDE * sizeof(pixel) ); \
936             for( int j = 0; j < 4; j++ ) \
937             { \
938                 memcpy( pbuf3 + j*FDEC_STRIDE, (i?pbuf1:pbuf2) + j*FENC_STRIDE, 4 * sizeof(pixel) ); \
939                 memcpy( pbuf4 + j*FDEC_STRIDE, (i?pbuf1:pbuf2) + j*FENC_STRIDE, 4 * sizeof(pixel) ); \
940             } \
941             nz_c = call_c1( zigzag_c[interlace].name, t1, pbuf2, pbuf3, &dc_c ); \
942             nz_a = call_a1( zigzag_asm[interlace].name, t2, pbuf2, pbuf4, &dc_a ); \
943             if( memcmp( t1+1, t2+1, 15*sizeof(dctcoef) ) || memcmp( pbuf3, pbuf4, 16*FDEC_STRIDE * sizeof(pixel) ) || nz_c != nz_a || dc_c != dc_a ) \
944             { \
945                 ok = 0; \
946                 fprintf( stderr, #name " [FAILED]\n" ); \
947                 break; \
948             } \
949         } \
950         call_c2( zigzag_c[interlace].name, t1, pbuf2, pbuf3, &dc_c ); \
951         call_a2( zigzag_asm[interlace].name, t2, pbuf2, pbuf4, &dc_a ); \
952     }
953
954 #define TEST_INTERLEAVE( name, t1, t2, dct, size ) \
955     if( zigzag_asm[interlace].name != zigzag_ref[interlace].name ) \
956     { \
957         for( int j = 0; j < 100; j++ ) \
958         { \
959             set_func_name( "zigzag_"#name"_%s", interlace?"field":"frame" ); \
960             used_asm = 1; \
961             memcpy(dct, buf1, size*sizeof(dctcoef)); \
962             for( int i = 0; i < size; i++ ) \
963                 dct[i] = rand()&0x1F ? 0 : dct[i]; \
964             memcpy(buf3, buf4, 10); \
965             call_c( zigzag_c[interlace].name, t1, dct, buf3 ); \
966             call_a( zigzag_asm[interlace].name, t2, dct, buf4 ); \
967             if( memcmp( t1, t2, size*sizeof(dctcoef) ) || memcmp( buf3, buf4, 10 ) ) \
968             { \
969                 ok = 0; \
970             } \
971         } \
972     }
973
974     x264_zigzag_init( 0, &zigzag_c[0], &zigzag_c[1] );
975     x264_zigzag_init( cpu_ref, &zigzag_ref[0], &zigzag_ref[1] );
976     x264_zigzag_init( cpu_new, &zigzag_asm[0], &zigzag_asm[1] );
977
978     ok = 1; used_asm = 0;
979     TEST_INTERLEAVE( interleave_8x8_cavlc, level1, level2, dct1[0], 64 );
980     report( "zigzag_interleave :" );
981
982     for( interlace = 0; interlace <= 1; interlace++ )
983     {
984         ok = 1; used_asm = 0;
985         TEST_ZIGZAG_SCAN( scan_8x8, level1, level2, (void*)dct1, 64 );
986         TEST_ZIGZAG_SCAN( scan_4x4, level1, level2, dct1[0], 16  );
987         TEST_ZIGZAG_SUB( sub_4x4, level1, level2, 16 );
988         TEST_ZIGZAG_SUBAC( sub_4x4ac, level1, level2 );
989         report( interlace ? "zigzag_field :" : "zigzag_frame :" );
990     }
991 #undef TEST_ZIGZAG_SCAN
992 #undef TEST_ZIGZAG_SUB
993
994     return ret;
995 }
996
997 static int check_mc( int cpu_ref, int cpu_new )
998 {
999     x264_mc_functions_t mc_c;
1000     x264_mc_functions_t mc_ref;
1001     x264_mc_functions_t mc_a;
1002     x264_pixel_function_t pixf;
1003
1004     pixel *src     = &(pbuf1)[2*64+2];
1005     pixel *src2[4] = { &(pbuf1)[3*64+2], &(pbuf1)[5*64+2],
1006                        &(pbuf1)[7*64+2], &(pbuf1)[9*64+2] };
1007     pixel *dst1    = pbuf3;
1008     pixel *dst2    = pbuf4;
1009
1010     int ret = 0, ok, used_asm;
1011
1012     x264_mc_init( 0, &mc_c );
1013     x264_mc_init( cpu_ref, &mc_ref );
1014     x264_mc_init( cpu_new, &mc_a );
1015     x264_pixel_init( 0, &pixf );
1016
1017 #define MC_TEST_LUMA( w, h ) \
1018         if( mc_a.mc_luma != mc_ref.mc_luma && !(w&(w-1)) && h<=16 ) \
1019         { \
1020             const x264_weight_t *weight = x264_weight_none; \
1021             set_func_name( "mc_luma_%dx%d", w, h ); \
1022             used_asm = 1; \
1023             for( int i = 0; i < 1024; i++ ) \
1024                 pbuf3[i] = pbuf4[i] = 0xCD; \
1025             call_c( mc_c.mc_luma, dst1, 32, src2, 64, dx, dy, w, h, weight ); \
1026             call_a( mc_a.mc_luma, dst2, 32, src2, 64, dx, dy, w, h, weight ); \
1027             if( memcmp( pbuf3, pbuf4, 1024 * sizeof(pixel) ) ) \
1028             { \
1029                 fprintf( stderr, "mc_luma[mv(%d,%d) %2dx%-2d]     [FAILED]\n", dx, dy, w, h ); \
1030                 ok = 0; \
1031             } \
1032         } \
1033         if( mc_a.get_ref != mc_ref.get_ref ) \
1034         { \
1035             pixel *ref = dst2; \
1036             int ref_stride = 32; \
1037             int w_checked = ( ( sizeof(pixel) == 2 && (w == 12 || w == 20)) ? w-2 : w ); \
1038             const x264_weight_t *weight = x264_weight_none; \
1039             set_func_name( "get_ref_%dx%d", w_checked, h ); \
1040             used_asm = 1; \
1041             for( int i = 0; i < 1024; i++ ) \
1042                 pbuf3[i] = pbuf4[i] = 0xCD; \
1043             call_c( mc_c.mc_luma, dst1, 32, src2, 64, dx, dy, w, h, weight ); \
1044             ref = (pixel*)call_a( mc_a.get_ref, ref, &ref_stride, src2, 64, dx, dy, w, h, weight ); \
1045             for( int i = 0; i < h; i++ ) \
1046                 if( memcmp( dst1+i*32, ref+i*ref_stride, w_checked * sizeof(pixel) ) ) \
1047                 { \
1048                     fprintf( stderr, "get_ref[mv(%d,%d) %2dx%-2d]     [FAILED]\n", dx, dy, w_checked, h ); \
1049                     ok = 0; \
1050                     break; \
1051                 } \
1052         }
1053
1054 #define MC_TEST_CHROMA( w, h ) \
1055         if( mc_a.mc_chroma != mc_ref.mc_chroma ) \
1056         { \
1057             set_func_name( "mc_chroma_%dx%d", w, h ); \
1058             used_asm = 1; \
1059             for( int i = 0; i < 1024; i++ ) \
1060                 pbuf3[i] = pbuf4[i] = 0xCD; \
1061             call_c( mc_c.mc_chroma, dst1, dst1+8, 16, src, 64, dx, dy, w, h ); \
1062             call_a( mc_a.mc_chroma, dst2, dst2+8, 16, src, 64, dx, dy, w, h ); \
1063             /* mc_chroma width=2 may write garbage to the right of dst. ignore that. */ \
1064             for( int j = 0; j < h; j++ ) \
1065                 for( int i = w; i < 8; i++ ) \
1066                 { \
1067                     dst2[i+j*16+8] = dst1[i+j*16+8]; \
1068                     dst2[i+j*16] = dst1[i+j*16]; \
1069                 } \
1070             if( memcmp( pbuf3, pbuf4, 1024 * sizeof(pixel) ) ) \
1071             { \
1072                 fprintf( stderr, "mc_chroma[mv(%d,%d) %2dx%-2d]     [FAILED]\n", dx, dy, w, h ); \
1073                 ok = 0; \
1074             } \
1075         }
1076     ok = 1; used_asm = 0;
1077     for( int dy = -8; dy < 8; dy++ )
1078         for( int dx = -128; dx < 128; dx++ )
1079         {
1080             if( rand()&15 ) continue; // running all of them is too slow
1081             MC_TEST_LUMA( 20, 18 );
1082             MC_TEST_LUMA( 16, 16 );
1083             MC_TEST_LUMA( 16, 8 );
1084             MC_TEST_LUMA( 12, 10 );
1085             MC_TEST_LUMA( 8, 16 );
1086             MC_TEST_LUMA( 8, 8 );
1087             MC_TEST_LUMA( 8, 4 );
1088             MC_TEST_LUMA( 4, 8 );
1089             MC_TEST_LUMA( 4, 4 );
1090         }
1091     report( "mc luma :" );
1092
1093     ok = 1; used_asm = 0;
1094     for( int dy = -1; dy < 9; dy++ )
1095         for( int dx = -128; dx < 128; dx++ )
1096         {
1097             if( rand()&15 ) continue;
1098             MC_TEST_CHROMA( 8, 8 );
1099             MC_TEST_CHROMA( 8, 4 );
1100             MC_TEST_CHROMA( 4, 8 );
1101             MC_TEST_CHROMA( 4, 4 );
1102             MC_TEST_CHROMA( 4, 2 );
1103             MC_TEST_CHROMA( 2, 4 );
1104             MC_TEST_CHROMA( 2, 2 );
1105         }
1106     report( "mc chroma :" );
1107 #undef MC_TEST_LUMA
1108 #undef MC_TEST_CHROMA
1109
1110 #define MC_TEST_AVG( name, weight ) \
1111 { \
1112     ok = 1, used_asm = 0; \
1113     for( int i = 0; i < 12; i++ ) \
1114     { \
1115         memcpy( pbuf3, pbuf1+320, 320 * sizeof(pixel) ); \
1116         memcpy( pbuf4, pbuf1+320, 320 * sizeof(pixel) ); \
1117         if( mc_a.name[i] != mc_ref.name[i] ) \
1118         { \
1119             set_func_name( "%s_%s", #name, pixel_names[i] ); \
1120             used_asm = 1; \
1121             call_c1( mc_c.name[i], pbuf3, 16, pbuf2+1, 16, pbuf1+18, 16, weight ); \
1122             call_a1( mc_a.name[i], pbuf4, 16, pbuf2+1, 16, pbuf1+18, 16, weight ); \
1123             if( memcmp( pbuf3, pbuf4, 320 * sizeof(pixel) ) ) \
1124             { \
1125                 ok = 0; \
1126                 fprintf( stderr, #name "[%d]: [FAILED]\n", i ); \
1127             } \
1128             call_c2( mc_c.name[i], pbuf3, 16, pbuf2+1, 16, pbuf1+18, 16, weight ); \
1129             call_a2( mc_a.name[i], pbuf4, 16, pbuf2+1, 16, pbuf1+18, 16, weight ); \
1130         } \
1131     } \
1132 }
1133
1134     for( int w = -63; w <= 127 && ok; w++ )
1135         MC_TEST_AVG( avg, w );
1136     report( "mc wpredb :" );
1137
1138 #define MC_TEST_WEIGHT( name, weight, aligned ) \
1139     int align_off = (aligned ? 0 : rand()%16); \
1140     ok = 1, used_asm = 0; \
1141     for( int i = 1; i <= 5; i++ ) \
1142     { \
1143         ALIGNED_16( pixel buffC[640] ); \
1144         ALIGNED_16( pixel buffA[640] ); \
1145         int j = X264_MAX( i*4, 2 ); \
1146         memset( buffC, 0, 640 * sizeof(pixel) ); \
1147         memset( buffA, 0, 640 * sizeof(pixel) ); \
1148         x264_t ha; \
1149         ha.mc = mc_a; \
1150         /* w12 is the same as w16 in some cases */ \
1151         if( i == 3 && mc_a.name[i] == mc_a.name[i+1] ) \
1152             continue; \
1153         if( mc_a.name[i] != mc_ref.name[i] ) \
1154         { \
1155             set_func_name( "%s_w%d", #name, j ); \
1156             used_asm = 1; \
1157             call_c1( mc_c.weight[i], buffC, 32, pbuf2+align_off, 32, &weight, 16 ); \
1158             mc_a.weight_cache(&ha, &weight); \
1159             call_a1( weight.weightfn[i], buffA, 32, pbuf2+align_off, 32, &weight, 16 ); \
1160             for( int k = 0; k < 16; k++ ) \
1161                 if( memcmp( &buffC[k*32], &buffA[k*32], j * sizeof(pixel) ) ) \
1162                 { \
1163                     ok = 0; \
1164                     fprintf( stderr, #name "[%d]: [FAILED] s:%d o:%d d%d\n", i, s, o, d ); \
1165                     break; \
1166                 } \
1167             call_c2( mc_c.weight[i], buffC, 32, pbuf2+align_off, 32, &weight, 16 ); \
1168             call_a2( weight.weightfn[i], buffA, 32, pbuf2+align_off, 32, &weight, 16 ); \
1169         } \
1170     }
1171
1172     ok = 1; used_asm = 0;
1173
1174     int align_cnt = 0;
1175     for( int s = 0; s <= 127 && ok; s++ )
1176     {
1177         for( int o = -128; o <= 127 && ok; o++ )
1178         {
1179             if( rand() & 2047 ) continue;
1180             for( int d = 0; d <= 7 && ok; d++ )
1181             {
1182                 if( s == 1<<d )
1183                     continue;
1184                 x264_weight_t weight = { .i_scale = s, .i_denom = d, .i_offset = o };
1185                 MC_TEST_WEIGHT( weight, weight, (align_cnt++ % 4) );
1186             }
1187         }
1188
1189     }
1190     report( "mc weight :" );
1191
1192     ok = 1; used_asm = 0;
1193     for( int o = 0; o <= 127 && ok; o++ )
1194     {
1195         int s = 1, d = 0;
1196         if( rand() & 15 ) continue;
1197         x264_weight_t weight = { .i_scale = 1, .i_denom = 0, .i_offset = o };
1198         MC_TEST_WEIGHT( offsetadd, weight, (align_cnt++ % 4) );
1199     }
1200     report( "mc offsetadd :" );
1201     ok = 1; used_asm = 0;
1202     for( int o = -128; o < 0 && ok; o++ )
1203     {
1204         int s = 1, d = 0;
1205         if( rand() & 15 ) continue;
1206         x264_weight_t weight = { .i_scale = 1, .i_denom = 0, .i_offset = o };
1207         MC_TEST_WEIGHT( offsetsub, weight, (align_cnt++ % 4) );
1208     }
1209     report( "mc offsetsub :" );
1210
1211     ok = 1; used_asm = 0;
1212     for( int height = 8; height <= 16; height += 8 )
1213     {
1214         if( mc_a.store_interleave_chroma != mc_ref.store_interleave_chroma )
1215         {
1216             set_func_name( "store_interleave_chroma" );
1217             used_asm = 1;
1218             memset( pbuf3, 0, 64*height );
1219             memset( pbuf4, 0, 64*height );
1220             call_c( mc_c.store_interleave_chroma, pbuf3, 64, pbuf1, pbuf1+16, height );
1221             call_a( mc_a.store_interleave_chroma, pbuf4, 64, pbuf1, pbuf1+16, height );
1222             if( memcmp( pbuf3, pbuf4, 64*height ) )
1223             {
1224                 ok = 0;
1225                 fprintf( stderr, "store_interleave_chroma FAILED: h=%d\n", height );
1226                 break;
1227             }
1228         }
1229         if( mc_a.load_deinterleave_chroma_fenc != mc_ref.load_deinterleave_chroma_fenc )
1230         {
1231             set_func_name( "load_deinterleave_chroma_fenc" );
1232             used_asm = 1;
1233             call_c( mc_c.load_deinterleave_chroma_fenc, pbuf3, pbuf1, 64, height );
1234             call_a( mc_a.load_deinterleave_chroma_fenc, pbuf4, pbuf1, 64, height );
1235             if( memcmp( pbuf3, pbuf4, FENC_STRIDE*height ) )
1236             {
1237                 ok = 0;
1238                 fprintf( stderr, "load_deinterleave_chroma_fenc FAILED: h=%d\n", height );
1239                 break;
1240             }
1241         }
1242         if( mc_a.load_deinterleave_chroma_fdec != mc_ref.load_deinterleave_chroma_fdec )
1243         {
1244             set_func_name( "load_deinterleave_chroma_fdec" );
1245             used_asm = 1;
1246             call_c( mc_c.load_deinterleave_chroma_fdec, pbuf3, pbuf1, 64, height );
1247             call_a( mc_a.load_deinterleave_chroma_fdec, pbuf4, pbuf1, 64, height );
1248             if( memcmp( pbuf3, pbuf4, FDEC_STRIDE*height ) )
1249             {
1250                 ok = 0;
1251                 fprintf( stderr, "load_deinterleave_chroma_fdec FAILED: h=%d\n", height );
1252                 break;
1253             }
1254         }
1255     }
1256     report( "store_interleave :" );
1257
1258     struct plane_spec {
1259         int w, h, src_stride;
1260     } plane_specs[] = { {2,2,2}, {8,6,8}, {20,31,24}, {32,8,40}, {256,10,272}, {504,7,505}, {528,6,528}, {256,10,-256}, {263,9,-264}, {1904,1,0} };
1261     ok = 1; used_asm = 0;
1262     if( mc_a.plane_copy != mc_ref.plane_copy )
1263     {
1264         set_func_name( "plane_copy" );
1265         used_asm = 1;
1266         for( int i = 0; i < sizeof(plane_specs)/sizeof(*plane_specs); i++ )
1267         {
1268             int w = plane_specs[i].w;
1269             int h = plane_specs[i].h;
1270             int src_stride = plane_specs[i].src_stride;
1271             int dst_stride = (w + 127) & ~63;
1272             assert( dst_stride * h <= 0x1000 );
1273             pixel *src1 = pbuf1 + X264_MAX(0, -src_stride) * (h-1);
1274             memset( pbuf3, 0, 0x1000*sizeof(pixel) );
1275             memset( pbuf4, 0, 0x1000*sizeof(pixel) );
1276             call_c( mc_c.plane_copy, pbuf3, dst_stride, src1, src_stride, w, h );
1277             call_a( mc_a.plane_copy, pbuf4, dst_stride, src1, src_stride, w, h );
1278             for( int y = 0; y < h; y++ )
1279                 if( memcmp( pbuf3+y*dst_stride, pbuf4+y*dst_stride, w*sizeof(pixel) ) )
1280                 {
1281                     ok = 0;
1282                     fprintf( stderr, "plane_copy FAILED: w=%d h=%d stride=%d\n", w, h, src_stride );
1283                     break;
1284                 }
1285         }
1286     }
1287
1288     if( mc_a.plane_copy_interleave != mc_ref.plane_copy_interleave )
1289     {
1290         set_func_name( "plane_copy_interleave" );
1291         used_asm = 1;
1292         for( int i = 0; i < sizeof(plane_specs)/sizeof(*plane_specs); i++ )
1293         {
1294             int w = (plane_specs[i].w + 1) >> 1;
1295             int h = plane_specs[i].h;
1296             int src_stride = (plane_specs[i].src_stride + 1) >> 1;
1297             int dst_stride = (2*w + 127) & ~63;
1298             assert( dst_stride * h <= 0x1000 );
1299             pixel *src1 = pbuf1 + X264_MAX(0, -src_stride) * (h-1);
1300             memset( pbuf3, 0, 0x1000*sizeof(pixel) );
1301             memset( pbuf4, 0, 0x1000*sizeof(pixel) );
1302             call_c( mc_c.plane_copy_interleave, pbuf3, dst_stride, src1, src_stride, src1+1024, src_stride+16, w, h );
1303             call_a( mc_a.plane_copy_interleave, pbuf4, dst_stride, src1, src_stride, src1+1024, src_stride+16, w, h );
1304             for( int y = 0; y < h; y++ )
1305                 if( memcmp( pbuf3+y*dst_stride, pbuf4+y*dst_stride, 2*w*sizeof(pixel) ) )
1306                 {
1307                     ok = 0;
1308                     fprintf( stderr, "plane_copy_interleave FAILED: w=%d h=%d stride=%d\n", w, h, src_stride );
1309                     break;
1310                 }
1311         }
1312     }
1313
1314     if( mc_a.plane_copy_deinterleave != mc_ref.plane_copy_deinterleave )
1315     {
1316         set_func_name( "plane_copy_deinterleave" );
1317         used_asm = 1;
1318         for( int i = 0; i < sizeof(plane_specs)/sizeof(*plane_specs); i++ )
1319         {
1320             int w = (plane_specs[i].w + 1) >> 1;
1321             int h = plane_specs[i].h;
1322             int dst_stride = w;
1323             int src_stride = (2*w + 127) & ~63;
1324             int offv = (dst_stride*h + 31) & ~15;
1325             memset( pbuf3, 0, 0x1000 );
1326             memset( pbuf4, 0, 0x1000 );
1327             call_c( mc_c.plane_copy_deinterleave, pbuf3, dst_stride, pbuf3+offv, dst_stride, pbuf1, src_stride, w, h );
1328             call_a( mc_a.plane_copy_deinterleave, pbuf4, dst_stride, pbuf4+offv, dst_stride, pbuf1, src_stride, w, h );
1329             for( int y = 0; y < h; y++ )
1330                 if( memcmp( pbuf3+y*dst_stride,      pbuf4+y*dst_stride, w ) ||
1331                     memcmp( pbuf3+y*dst_stride+offv, pbuf4+y*dst_stride+offv, w ) )
1332                 {
1333                     ok = 0;
1334                     fprintf( stderr, "plane_copy_deinterleave FAILED: w=%d h=%d stride=%d\n", w, h, src_stride );
1335                     break;
1336                 }
1337         }
1338     }
1339     report( "plane_copy :" );
1340
1341     if( mc_a.hpel_filter != mc_ref.hpel_filter )
1342     {
1343         pixel *srchpel = pbuf1+8+2*64;
1344         pixel *dstc[3] = { pbuf3+8, pbuf3+8+16*64, pbuf3+8+32*64 };
1345         pixel *dsta[3] = { pbuf4+8, pbuf4+8+16*64, pbuf4+8+32*64 };
1346         void *tmp = pbuf3+49*64;
1347         set_func_name( "hpel_filter" );
1348         ok = 1; used_asm = 1;
1349         memset( pbuf3, 0, 4096 * sizeof(pixel) );
1350         memset( pbuf4, 0, 4096 * sizeof(pixel) );
1351         call_c( mc_c.hpel_filter, dstc[0], dstc[1], dstc[2], srchpel, 64, 48, 10, tmp );
1352         call_a( mc_a.hpel_filter, dsta[0], dsta[1], dsta[2], srchpel, 64, 48, 10, tmp );
1353         for( int i = 0; i < 3; i++ )
1354             for( int j = 0; j < 10; j++ )
1355                 //FIXME ideally the first pixels would match too, but they aren't actually used
1356                 if( memcmp( dstc[i]+j*64+2, dsta[i]+j*64+2, 43 * sizeof(pixel) ) )
1357                 {
1358                     ok = 0;
1359                     fprintf( stderr, "hpel filter differs at plane %c line %d\n", "hvc"[i], j );
1360                     for( int k = 0; k < 48; k++ )
1361                         printf( "%02x%s", dstc[i][j*64+k], (k+1)&3 ? "" : " " );
1362                     printf( "\n" );
1363                     for( int k = 0; k < 48; k++ )
1364                         printf( "%02x%s", dsta[i][j*64+k], (k+1)&3 ? "" : " " );
1365                     printf( "\n" );
1366                     break;
1367                 }
1368         report( "hpel filter :" );
1369     }
1370
1371     if( mc_a.frame_init_lowres_core != mc_ref.frame_init_lowres_core )
1372     {
1373         pixel *dstc[4] = { pbuf3, pbuf3+1024, pbuf3+2048, pbuf3+3072 };
1374         pixel *dsta[4] = { pbuf4, pbuf4+1024, pbuf4+2048, pbuf4+3072 };
1375         set_func_name( "lowres_init" );
1376         ok = 1; used_asm = 1;
1377         for( int w = 40; w <= 48; w += 8 )
1378         {
1379             int stride = (w+8)&~15;
1380             call_c( mc_c.frame_init_lowres_core, pbuf1, dstc[0], dstc[1], dstc[2], dstc[3], w*2, stride, w, 16 );
1381             call_a( mc_a.frame_init_lowres_core, pbuf1, dsta[0], dsta[1], dsta[2], dsta[3], w*2, stride, w, 16 );
1382             for( int i = 0; i < 16; i++ )
1383             {
1384                 for( int j = 0; j < 4; j++ )
1385                     if( memcmp( dstc[j]+i*stride, dsta[j]+i*stride, w * sizeof(pixel) ) )
1386                     {
1387                         ok = 0;
1388                         fprintf( stderr, "frame_init_lowres differs at plane %d line %d\n", j, i );
1389                         for( int k = 0; k < w; k++ )
1390                             printf( "%d ", dstc[j][k+i*stride] );
1391                         printf( "\n" );
1392                         for( int k = 0; k < w; k++ )
1393                             printf( "%d ", dsta[j][k+i*stride] );
1394                         printf( "\n" );
1395                         break;
1396                     }
1397             }
1398         }
1399         report( "lowres init :" );
1400     }
1401
1402 #define INTEGRAL_INIT( name, size, ... )\
1403     if( mc_a.name != mc_ref.name )\
1404     {\
1405         int stride = 80;\
1406         set_func_name( #name );\
1407         used_asm = 1;\
1408         memcpy( buf3, buf1, size*2*stride );\
1409         memcpy( buf4, buf1, size*2*stride );\
1410         uint16_t *sum = (uint16_t*)buf3;\
1411         call_c1( mc_c.name, __VA_ARGS__ );\
1412         sum = (uint16_t*)buf4;\
1413         call_a1( mc_a.name, __VA_ARGS__ );\
1414         if( memcmp( buf3, buf4, (stride-8)*2 ) \
1415             || (size>9 && memcmp( buf3+18*stride, buf4+18*stride, (stride-8)*2 )))\
1416             ok = 0;\
1417         call_c2( mc_c.name, __VA_ARGS__ );\
1418         call_a2( mc_a.name, __VA_ARGS__ );\
1419     }
1420     ok = 1; used_asm = 0;
1421     INTEGRAL_INIT( integral_init4h, 2, sum+stride, pbuf2, stride );
1422     INTEGRAL_INIT( integral_init8h, 2, sum+stride, pbuf2, stride );
1423     INTEGRAL_INIT( integral_init4v, 14, sum, sum+9*stride, stride );
1424     INTEGRAL_INIT( integral_init8v, 9, sum, stride );
1425     report( "integral init :" );
1426
1427     if( mc_a.mbtree_propagate_cost != mc_ref.mbtree_propagate_cost )
1428     {
1429         x264_emms();
1430         for( int i = 0; i < 10; i++ )
1431         {
1432             float fps_factor = (rand()&65535) / 256.;
1433             ok = 1; used_asm = 1;
1434             set_func_name( "mbtree_propagate" );
1435             int *dsta = (int*)buf3;
1436             int *dstc = dsta+400;
1437             uint16_t *prop = (uint16_t*)buf1;
1438             uint16_t *intra = (uint16_t*)buf4;
1439             uint16_t *inter = intra+128;
1440             uint16_t *qscale = inter+128;
1441             uint16_t *rnd = (uint16_t*)buf2;
1442             x264_emms();
1443             for( int j = 0; j < 100; j++ )
1444             {
1445                 intra[j]  = *rnd++ & 0x7fff;
1446                 intra[j] += !intra[j];
1447                 inter[j]  = *rnd++ & 0x7fff;
1448                 qscale[j] = *rnd++ & 0x7fff;
1449             }
1450             call_c( mc_c.mbtree_propagate_cost, dstc, prop, intra, inter, qscale, &fps_factor, 100 );
1451             call_a( mc_a.mbtree_propagate_cost, dsta, prop, intra, inter, qscale, &fps_factor, 100 );
1452             // I don't care about exact rounding, this is just how close the floating-point implementation happens to be
1453             x264_emms();
1454             for( int j = 0; j < 100 && ok; j++ )
1455             {
1456                 ok &= abs( dstc[j]-dsta[j] ) <= 1 || fabs( (double)dstc[j]/dsta[j]-1 ) < 1e-4;
1457                 if( !ok )
1458                     fprintf( stderr, "mbtree_propagate FAILED: %f !~= %f\n", (double)dstc[j], (double)dsta[j] );
1459             }
1460         }
1461         report( "mbtree propagate :" );
1462     }
1463
1464     if( mc_a.memcpy_aligned != mc_ref.memcpy_aligned )
1465     {
1466         set_func_name( "memcpy_aligned" );
1467         ok = 1; used_asm = 1;
1468         for( int size = 16; size < 256; size += 16 )
1469         {
1470             memset( buf4, 0xAA, size + 1 );
1471             call_c( mc_c.memcpy_aligned, buf3, buf1, size );
1472             call_a( mc_a.memcpy_aligned, buf4, buf1, size );
1473             if( memcmp( buf3, buf4, size ) || buf4[size] != 0xAA )
1474             {
1475                 ok = 0;
1476                 fprintf( stderr, "memcpy_aligned FAILED: size=%d\n", size );
1477                 break;
1478             }
1479         }
1480         report( "memcpy aligned :" );
1481     }
1482
1483     if( mc_a.memzero_aligned != mc_ref.memzero_aligned )
1484     {
1485         set_func_name( "memzero_aligned" );
1486         ok = 1; used_asm = 1;
1487         for( int size = 128; size < 1024; size += 128 )
1488         {
1489             memset( buf4, 0xAA, size + 1 );
1490             call_c( mc_c.memzero_aligned, buf3, size );
1491             call_a( mc_a.memzero_aligned, buf4, size );
1492             if( memcmp( buf3, buf4, size ) || buf4[size] != 0xAA )
1493             {
1494                 ok = 0;
1495                 fprintf( stderr, "memzero_aligned FAILED: size=%d\n", size );
1496                 break;
1497             }
1498         }
1499         report( "memzero aligned :" );
1500     }
1501
1502     return ret;
1503 }
1504
1505 static int check_deblock( int cpu_ref, int cpu_new )
1506 {
1507     x264_deblock_function_t db_c;
1508     x264_deblock_function_t db_ref;
1509     x264_deblock_function_t db_a;
1510     int ret = 0, ok = 1, used_asm = 0;
1511     int alphas[36], betas[36];
1512     int8_t tcs[36][4];
1513
1514     x264_deblock_init( 0, &db_c, 0 );
1515     x264_deblock_init( cpu_ref, &db_ref, 0 );
1516     x264_deblock_init( cpu_new, &db_a, 0 );
1517
1518     /* not exactly the real values of a,b,tc but close enough */
1519     for( int i = 35, a = 255, c = 250; i >= 0; i-- )
1520     {
1521         alphas[i] = a << (BIT_DEPTH-8);
1522         betas[i] = (i+1)/2 << (BIT_DEPTH-8);
1523         tcs[i][0] = tcs[i][3] = (c+6)/10 << (BIT_DEPTH-8);
1524         tcs[i][1] = (c+7)/15 << (BIT_DEPTH-8);
1525         tcs[i][2] = (c+9)/20 << (BIT_DEPTH-8);
1526         a = a*9/10;
1527         c = c*9/10;
1528     }
1529
1530 #define TEST_DEBLOCK( name, align, ... ) \
1531     for( int i = 0; i < 36; i++ ) \
1532     { \
1533         int off = 8*32 + (i&15)*4*!align; /* benchmark various alignments of h filter */ \
1534         for( int j = 0; j < 1024; j++ ) \
1535             /* two distributions of random to excersize different failure modes */ \
1536             pbuf3[j] = rand() & (i&1 ? 0xf : PIXEL_MAX ); \
1537         memcpy( pbuf4, pbuf3, 1024 * sizeof(pixel) ); \
1538         if( db_a.name != db_ref.name ) \
1539         { \
1540             set_func_name( #name ); \
1541             used_asm = 1; \
1542             call_c1( db_c.name, pbuf3+off, 32, alphas[i], betas[i], ##__VA_ARGS__ ); \
1543             call_a1( db_a.name, pbuf4+off, 32, alphas[i], betas[i], ##__VA_ARGS__ ); \
1544             if( memcmp( pbuf3, pbuf4, 1024 * sizeof(pixel) ) ) \
1545             { \
1546                 ok = 0; \
1547                 fprintf( stderr, #name "(a=%d, b=%d): [FAILED]\n", alphas[i], betas[i] ); \
1548                 break; \
1549             } \
1550             call_c2( db_c.name, pbuf3+off, 32, alphas[i], betas[i], ##__VA_ARGS__ ); \
1551             call_a2( db_a.name, pbuf4+off, 32, alphas[i], betas[i], ##__VA_ARGS__ ); \
1552         } \
1553     }
1554
1555     TEST_DEBLOCK( deblock_luma[0], 0, tcs[i] );
1556     TEST_DEBLOCK( deblock_luma[1], 1, tcs[i] );
1557     TEST_DEBLOCK( deblock_h_chroma_420, 0, tcs[i] );
1558     TEST_DEBLOCK( deblock_h_chroma_422, 0, tcs[i] );
1559     TEST_DEBLOCK( deblock_chroma[1], 1, tcs[i] );
1560     TEST_DEBLOCK( deblock_luma_intra[0], 0 );
1561     TEST_DEBLOCK( deblock_luma_intra[1], 1 );
1562     TEST_DEBLOCK( deblock_h_chroma_420_intra, 0 );
1563     TEST_DEBLOCK( deblock_h_chroma_422_intra, 0 );
1564     TEST_DEBLOCK( deblock_chroma_intra[1], 1 );
1565
1566     if( db_a.deblock_strength != db_ref.deblock_strength )
1567     {
1568         for( int i = 0; i < 100; i++ )
1569         {
1570             ALIGNED_ARRAY_16( uint8_t, nnz, [X264_SCAN8_SIZE] );
1571             ALIGNED_4( int8_t ref[2][X264_SCAN8_LUMA_SIZE] );
1572             ALIGNED_ARRAY_16( int16_t, mv, [2],[X264_SCAN8_LUMA_SIZE][2] );
1573             ALIGNED_ARRAY_16( uint8_t, bs, [2],[2][8][4] );
1574             memset( bs, 99, sizeof(bs) );
1575             for( int j = 0; j < X264_SCAN8_SIZE; j++ )
1576                 nnz[j] = ((rand()&7) == 7) * rand() & 0xf;
1577             for( int j = 0; j < 2; j++ )
1578                 for( int k = 0; k < X264_SCAN8_LUMA_SIZE; k++ )
1579                 {
1580                     ref[j][k] = ((rand()&3) != 3) ? 0 : (rand() & 31) - 2;
1581                     for( int l = 0; l < 2; l++ )
1582                         mv[j][k][l] = ((rand()&7) != 7) ? (rand()&7) - 3 : (rand()&1023) - 512;
1583                 }
1584             set_func_name( "deblock_strength" );
1585             call_c( db_c.deblock_strength, nnz, ref, mv, bs[0], 2<<(i&1), ((i>>1)&1) );
1586             call_a( db_a.deblock_strength, nnz, ref, mv, bs[1], 2<<(i&1), ((i>>1)&1) );
1587             if( memcmp( bs[0], bs[1], sizeof(bs[0]) ) )
1588             {
1589                 ok = 0;
1590                 fprintf( stderr, "deblock_strength: [FAILED]\n" );
1591                 for( int j = 0; j < 2; j++ )
1592                 {
1593                     for( int k = 0; k < 2; k++ )
1594                         for( int l = 0; l < 4; l++ )
1595                         {
1596                             for( int m = 0; m < 4; m++ )
1597                                 printf("%d ",bs[j][k][l][m]);
1598                             printf("\n");
1599                         }
1600                     printf("\n");
1601                 }
1602                 break;
1603             }
1604         }
1605     }
1606
1607     report( "deblock :" );
1608
1609     return ret;
1610 }
1611
1612 static int check_quant( int cpu_ref, int cpu_new )
1613 {
1614     x264_quant_function_t qf_c;
1615     x264_quant_function_t qf_ref;
1616     x264_quant_function_t qf_a;
1617     ALIGNED_16( dctcoef dct1[64] );
1618     ALIGNED_16( dctcoef dct2[64] );
1619     ALIGNED_16( dctcoef dct3[8][16] );
1620     ALIGNED_16( dctcoef dct4[8][16] );
1621     ALIGNED_16( uint8_t cqm_buf[64] );
1622     int ret = 0, ok, used_asm;
1623     int oks[3] = {1,1,1}, used_asms[3] = {0,0,0};
1624     x264_t h_buf;
1625     x264_t *h = &h_buf;
1626     memset( h, 0, sizeof(*h) );
1627     h->sps->i_chroma_format_idc = 1;
1628     x264_param_default( &h->param );
1629     h->chroma_qp_table = i_chroma_qp_table + 12;
1630     h->param.analyse.b_transform_8x8 = 1;
1631
1632     for( int i_cqm = 0; i_cqm < 4; i_cqm++ )
1633     {
1634         if( i_cqm == 0 )
1635         {
1636             for( int i = 0; i < 6; i++ )
1637                 h->pps->scaling_list[i] = x264_cqm_flat16;
1638             h->param.i_cqm_preset = h->pps->i_cqm_preset = X264_CQM_FLAT;
1639         }
1640         else if( i_cqm == 1 )
1641         {
1642             for( int i = 0; i < 6; i++ )
1643                 h->pps->scaling_list[i] = x264_cqm_jvt[i];
1644             h->param.i_cqm_preset = h->pps->i_cqm_preset = X264_CQM_JVT;
1645         }
1646         else
1647         {
1648             int max_scale = BIT_DEPTH < 10 ? 255 : 228;
1649             if( i_cqm == 2 )
1650                 for( int i = 0; i < 64; i++ )
1651                     cqm_buf[i] = 10 + rand() % (max_scale - 9);
1652             else
1653                 for( int i = 0; i < 64; i++ )
1654                     cqm_buf[i] = 1;
1655             for( int i = 0; i < 6; i++ )
1656                 h->pps->scaling_list[i] = cqm_buf;
1657             h->param.i_cqm_preset = h->pps->i_cqm_preset = X264_CQM_CUSTOM;
1658         }
1659
1660         h->param.rc.i_qp_min = 0;
1661         h->param.rc.i_qp_max = QP_MAX;
1662         x264_cqm_init( h );
1663         x264_quant_init( h, 0, &qf_c );
1664         x264_quant_init( h, cpu_ref, &qf_ref );
1665         x264_quant_init( h, cpu_new, &qf_a );
1666
1667 #define INIT_QUANT8(j) \
1668         { \
1669             static const int scale1d[8] = {32,31,24,31,32,31,24,31}; \
1670             for( int i = 0; i < 64; i++ ) \
1671             { \
1672                 unsigned int scale = (255*scale1d[i>>3]*scale1d[i&7])/16; \
1673                 dct1[i] = dct2[i] = j ? (rand()%(2*scale+1))-scale : 0; \
1674             } \
1675         }
1676
1677 #define INIT_QUANT4(j) \
1678         { \
1679             static const int scale1d[4] = {4,6,4,6}; \
1680             for( int i = 0; i < 16; i++ ) \
1681             { \
1682                 unsigned int scale = 255*scale1d[i>>2]*scale1d[i&3]; \
1683                 dct1[i] = dct2[i] = j ? (rand()%(2*scale+1))-scale : 0; \
1684             } \
1685         }
1686
1687 #define TEST_QUANT_DC( name, cqm ) \
1688         if( qf_a.name != qf_ref.name ) \
1689         { \
1690             set_func_name( #name ); \
1691             used_asms[0] = 1; \
1692             for( int qp = h->param.rc.i_qp_max; qp >= h->param.rc.i_qp_min; qp-- ) \
1693             { \
1694                 for( int j = 0; j < 2; j++ ) \
1695                 { \
1696                     int result_c, result_a; \
1697                     for( int i = 0; i < 16; i++ ) \
1698                         dct1[i] = dct2[i] = j ? (rand() & 0x1fff) - 0xfff : 0; \
1699                     result_c = call_c1( qf_c.name, dct1, h->quant4_mf[CQM_4IY][qp][0], h->quant4_bias[CQM_4IY][qp][0] ); \
1700                     result_a = call_a1( qf_a.name, dct2, h->quant4_mf[CQM_4IY][qp][0], h->quant4_bias[CQM_4IY][qp][0] ); \
1701                     if( memcmp( dct1, dct2, 16*sizeof(dctcoef) ) || result_c != result_a ) \
1702                     { \
1703                         oks[0] = 0; \
1704                         fprintf( stderr, #name "(cqm=%d): [FAILED]\n", i_cqm ); \
1705                         break; \
1706                     } \
1707                     call_c2( qf_c.name, dct1, h->quant4_mf[CQM_4IY][qp][0], h->quant4_bias[CQM_4IY][qp][0] ); \
1708                     call_a2( qf_a.name, dct2, h->quant4_mf[CQM_4IY][qp][0], h->quant4_bias[CQM_4IY][qp][0] ); \
1709                 } \
1710             } \
1711         }
1712
1713 #define TEST_QUANT( qname, block, w ) \
1714         if( qf_a.qname != qf_ref.qname ) \
1715         { \
1716             set_func_name( #qname ); \
1717             used_asms[0] = 1; \
1718             for( int qp = h->param.rc.i_qp_max; qp >= h->param.rc.i_qp_min; qp-- ) \
1719             { \
1720                 for( int j = 0; j < 2; j++ ) \
1721                 { \
1722                     INIT_QUANT##w(j) \
1723                     int result_c = call_c1( qf_c.qname, dct1, h->quant##w##_mf[block][qp], h->quant##w##_bias[block][qp] ); \
1724                     int result_a = call_a1( qf_a.qname, dct2, h->quant##w##_mf[block][qp], h->quant##w##_bias[block][qp] ); \
1725                     if( memcmp( dct1, dct2, w*w*sizeof(dctcoef) ) || result_c != result_a ) \
1726                     { \
1727                         oks[0] = 0; \
1728                         fprintf( stderr, #qname "(qp=%d, cqm=%d, block="#block"): [FAILED]\n", qp, i_cqm ); \
1729                         break; \
1730                     } \
1731                     call_c2( qf_c.qname, dct1, h->quant##w##_mf[block][qp], h->quant##w##_bias[block][qp] ); \
1732                     call_a2( qf_a.qname, dct2, h->quant##w##_mf[block][qp], h->quant##w##_bias[block][qp] ); \
1733                 } \
1734             } \
1735         }
1736
1737         TEST_QUANT( quant_8x8, CQM_8IY, 8 );
1738         TEST_QUANT( quant_8x8, CQM_8PY, 8 );
1739         TEST_QUANT( quant_4x4, CQM_4IY, 4 );
1740         TEST_QUANT( quant_4x4, CQM_4PY, 4 );
1741         TEST_QUANT_DC( quant_4x4_dc, **h->quant4_mf[CQM_4IY] );
1742         TEST_QUANT_DC( quant_2x2_dc, **h->quant4_mf[CQM_4IC] );
1743
1744 #define TEST_DEQUANT( qname, dqname, block, w ) \
1745         if( qf_a.dqname != qf_ref.dqname ) \
1746         { \
1747             set_func_name( "%s_%s", #dqname, i_cqm?"cqm":"flat" ); \
1748             used_asms[1] = 1; \
1749             for( int qp = h->param.rc.i_qp_max; qp >= h->param.rc.i_qp_min; qp-- ) \
1750             { \
1751                 INIT_QUANT##w(1) \
1752                 qf_c.qname( dct1, h->quant##w##_mf[block][qp], h->quant##w##_bias[block][qp] ); \
1753                 memcpy( dct2, dct1, w*w*sizeof(dctcoef) ); \
1754                 call_c1( qf_c.dqname, dct1, h->dequant##w##_mf[block], qp ); \
1755                 call_a1( qf_a.dqname, dct2, h->dequant##w##_mf[block], qp ); \
1756                 if( memcmp( dct1, dct2, w*w*sizeof(dctcoef) ) ) \
1757                 { \
1758                     oks[1] = 0; \
1759                     fprintf( stderr, #dqname "(qp=%d, cqm=%d, block="#block"): [FAILED]\n", qp, i_cqm ); \
1760                     break; \
1761                 } \
1762                 call_c2( qf_c.dqname, dct1, h->dequant##w##_mf[block], qp ); \
1763                 call_a2( qf_a.dqname, dct2, h->dequant##w##_mf[block], qp ); \
1764             } \
1765         }
1766
1767         TEST_DEQUANT( quant_8x8, dequant_8x8, CQM_8IY, 8 );
1768         TEST_DEQUANT( quant_8x8, dequant_8x8, CQM_8PY, 8 );
1769         TEST_DEQUANT( quant_4x4, dequant_4x4, CQM_4IY, 4 );
1770         TEST_DEQUANT( quant_4x4, dequant_4x4, CQM_4PY, 4 );
1771
1772 #define TEST_DEQUANT_DC( qname, dqname, block, w ) \
1773         if( qf_a.dqname != qf_ref.dqname ) \
1774         { \
1775             set_func_name( "%s_%s", #dqname, i_cqm?"cqm":"flat" ); \
1776             used_asms[1] = 1; \
1777             for( int qp = h->param.rc.i_qp_max; qp >= h->param.rc.i_qp_min; qp-- ) \
1778             { \
1779                 for( int i = 0; i < 16; i++ ) \
1780                     dct1[i] = rand()%(PIXEL_MAX*16*2+1) - PIXEL_MAX*16; \
1781                 qf_c.qname( dct1, h->quant##w##_mf[block][qp][0]>>1, h->quant##w##_bias[block][qp][0]>>1 ); \
1782                 memcpy( dct2, dct1, w*w*sizeof(dctcoef) ); \
1783                 call_c1( qf_c.dqname, dct1, h->dequant##w##_mf[block], qp ); \
1784                 call_a1( qf_a.dqname, dct2, h->dequant##w##_mf[block], qp ); \
1785                 if( memcmp( dct1, dct2, w*w*sizeof(dctcoef) ) ) \
1786                 { \
1787                     oks[1] = 0; \
1788                     fprintf( stderr, #dqname "(qp=%d, cqm=%d, block="#block"): [FAILED]\n", qp, i_cqm ); \
1789                 } \
1790                 call_c2( qf_c.dqname, dct1, h->dequant##w##_mf[block], qp ); \
1791                 call_a2( qf_a.dqname, dct2, h->dequant##w##_mf[block], qp ); \
1792             } \
1793         }
1794
1795         TEST_DEQUANT_DC( quant_4x4_dc, dequant_4x4_dc, CQM_4IY, 4 );
1796
1797         if( qf_a.idct_dequant_2x4_dc != qf_ref.idct_dequant_2x4_dc )
1798         {
1799             set_func_name( "idct_dequant_2x4_dc_%s", i_cqm?"cqm":"flat" );
1800             used_asms[1] = 1;
1801             for( int qp = h->param.rc.i_qp_max; qp >= h->param.rc.i_qp_min; qp-- )
1802             {
1803                 for( int i = 0; i < 8; i++ )
1804                     dct1[i] = rand()%(PIXEL_MAX*16*2+1) - PIXEL_MAX*16;
1805                 qf_c.quant_2x2_dc( &dct1[0], h->quant4_mf[CQM_4IC][qp+3][0]>>1, h->quant4_bias[CQM_4IC][qp+3][0]>>1 );
1806                 qf_c.quant_2x2_dc( &dct1[4], h->quant4_mf[CQM_4IC][qp+3][0]>>1, h->quant4_bias[CQM_4IC][qp+3][0]>>1 );
1807                 call_c( qf_c.idct_dequant_2x4_dc, dct1, dct3, h->dequant4_mf[CQM_4IC], qp+3 );
1808                 call_a( qf_a.idct_dequant_2x4_dc, dct1, dct4, h->dequant4_mf[CQM_4IC], qp+3 );
1809                 for( int i = 0; i < 8; i++ )
1810                     if( dct3[i][0] != dct4[i][0] )
1811                     {
1812                         oks[1] = 0;
1813                         fprintf( stderr, "idct_dequant_2x4_dc (qp=%d, cqm=%d): [FAILED]\n", qp, i_cqm );
1814                         break;
1815                     }
1816             }
1817         }
1818
1819         if( qf_a.idct_dequant_2x4_dconly != qf_ref.idct_dequant_2x4_dconly )
1820         {
1821             set_func_name( "idct_dequant_2x4_dc_%s", i_cqm?"cqm":"flat" );
1822             used_asms[1] = 1;
1823             for( int qp = h->param.rc.i_qp_max; qp >= h->param.rc.i_qp_min; qp-- )
1824             {
1825                 for( int i = 0; i < 8; i++ )
1826                     dct1[i] = rand()%(PIXEL_MAX*16*2+1) - PIXEL_MAX*16;
1827                 qf_c.quant_2x2_dc( &dct1[0], h->quant4_mf[CQM_4IC][qp+3][0]>>1, h->quant4_bias[CQM_4IC][qp+3][0]>>1 );
1828                 qf_c.quant_2x2_dc( &dct1[4], h->quant4_mf[CQM_4IC][qp+3][0]>>1, h->quant4_bias[CQM_4IC][qp+3][0]>>1 );
1829                 memcpy( dct2, dct1, 8*sizeof(dctcoef) );
1830                 call_c1( qf_c.idct_dequant_2x4_dconly, dct1, h->dequant4_mf[CQM_4IC], qp+3 );
1831                 call_a1( qf_a.idct_dequant_2x4_dconly, dct2, h->dequant4_mf[CQM_4IC], qp+3 );
1832                 if( memcmp( dct1, dct2, 8*sizeof(dctcoef) ) )
1833                 {
1834                     oks[1] = 0;
1835                     fprintf( stderr, "idct_dequant_2x4_dconly (qp=%d, cqm=%d): [FAILED]\n", qp, i_cqm );
1836                     break;
1837                 }
1838                 call_c2( qf_c.idct_dequant_2x4_dconly, dct1, h->dequant4_mf[CQM_4IC], qp+3 );
1839                 call_a2( qf_a.idct_dequant_2x4_dconly, dct2, h->dequant4_mf[CQM_4IC], qp+3 );
1840             }
1841         }
1842
1843 #define TEST_OPTIMIZE_CHROMA_DC( optname, size ) \
1844         if( qf_a.optname != qf_ref.optname ) \
1845         { \
1846             set_func_name( #optname ); \
1847             used_asms[2] = 1; \
1848             for( int qp = h->param.rc.i_qp_max; qp >= h->param.rc.i_qp_min; qp-- ) \
1849             { \
1850                 int qpdc = qp + (size == 8 ? 3 : 0); \
1851                 int dmf = h->dequant4_mf[CQM_4IC][qpdc%6][0] << qpdc/6; \
1852                 if( dmf > 32*64 ) \
1853                     continue; \
1854                 for( int i = 16; ; i <<= 1 ) \
1855                 { \
1856                     int res_c, res_asm; \
1857                     int max = X264_MIN( i, PIXEL_MAX*16 ); \
1858                     for( int j = 0; j < size; j++ ) \
1859                         dct1[j] = rand()%(max*2+1) - max; \
1860                     for( int j = 0; i <= size; j += 4 ) \
1861                         qf_c.quant_2x2_dc( &dct1[j], h->quant4_mf[CQM_4IC][qpdc][0]>>1, h->quant4_bias[CQM_4IC][qpdc][0]>>1 ); \
1862                     memcpy( dct2, dct1, size*sizeof(dctcoef) ); \
1863                     res_c   = call_c1( qf_c.optname, dct1, dmf ); \
1864                     res_asm = call_a1( qf_a.optname, dct2, dmf ); \
1865                     if( res_c != res_asm || memcmp( dct1, dct2, size*sizeof(dctcoef) ) ) \
1866                     { \
1867                         oks[2] = 0; \
1868                         fprintf( stderr, #optname "(qp=%d, res_c=%d, res_asm=%d): [FAILED]\n", qp, res_c, res_asm ); \
1869                     } \
1870                     call_c2( qf_c.optname, dct1, dmf ); \
1871                     call_a2( qf_a.optname, dct2, dmf ); \
1872                     if( i >= PIXEL_MAX*16 ) \
1873                         break; \
1874                 } \
1875             } \
1876         }
1877
1878         TEST_OPTIMIZE_CHROMA_DC( optimize_chroma_2x2_dc, 4 );
1879         TEST_OPTIMIZE_CHROMA_DC( optimize_chroma_2x4_dc, 8 );
1880
1881         x264_cqm_delete( h );
1882     }
1883
1884     ok = oks[0]; used_asm = used_asms[0];
1885     report( "quant :" );
1886
1887     ok = oks[1]; used_asm = used_asms[1];
1888     report( "dequant :" );
1889
1890     ok = oks[2]; used_asm = used_asms[2];
1891     report( "optimize chroma dc :" );
1892
1893     ok = 1; used_asm = 0;
1894     if( qf_a.denoise_dct != qf_ref.denoise_dct )
1895     {
1896         used_asm = 1;
1897         for( int size = 16; size <= 64; size += 48 )
1898         {
1899             set_func_name( "denoise_dct" );
1900             memcpy( dct1, buf1, size*sizeof(dctcoef) );
1901             memcpy( dct2, buf1, size*sizeof(dctcoef) );
1902             memcpy( buf3+256, buf3, 256 );
1903             call_c1( qf_c.denoise_dct, dct1, (uint32_t*)buf3, (udctcoef*)buf2, size );
1904             call_a1( qf_a.denoise_dct, dct2, (uint32_t*)(buf3+256), (udctcoef*)buf2, size );
1905             if( memcmp( dct1, dct2, size*sizeof(dctcoef) ) || memcmp( buf3+4, buf3+256+4, (size-1)*sizeof(uint32_t) ) )
1906                 ok = 0;
1907             call_c2( qf_c.denoise_dct, dct1, (uint32_t*)buf3, (udctcoef*)buf2, size );
1908             call_a2( qf_a.denoise_dct, dct2, (uint32_t*)(buf3+256), (udctcoef*)buf2, size );
1909         }
1910     }
1911     report( "denoise dct :" );
1912
1913 #define TEST_DECIMATE( decname, w, ac, thresh ) \
1914     if( qf_a.decname != qf_ref.decname ) \
1915     { \
1916         set_func_name( #decname ); \
1917         used_asm = 1; \
1918         for( int i = 0; i < 100; i++ ) \
1919         { \
1920             static const int distrib[16] = {1,1,1,1,1,1,1,1,1,1,1,1,2,3,4};\
1921             static const int zerorate_lut[4] = {3,7,15,31};\
1922             int zero_rate = zerorate_lut[i&3];\
1923             for( int idx = 0; idx < w*w; idx++ ) \
1924             { \
1925                 int sign = (rand()&1) ? -1 : 1; \
1926                 int abs_level = distrib[rand()&15]; \
1927                 if( abs_level == 4 ) abs_level = rand()&0x3fff; \
1928                 int zero = !(rand()&zero_rate); \
1929                 dct1[idx] = zero * abs_level * sign; \
1930             } \
1931             if( ac ) \
1932                 dct1[0] = 0; \
1933             int result_c = call_c( qf_c.decname, dct1 ); \
1934             int result_a = call_a( qf_a.decname, dct1 ); \
1935             if( X264_MIN(result_c,thresh) != X264_MIN(result_a,thresh) ) \
1936             { \
1937                 ok = 0; \
1938                 fprintf( stderr, #decname ": [FAILED]\n" ); \
1939                 break; \
1940             } \
1941         } \
1942     }
1943
1944     ok = 1; used_asm = 0;
1945     TEST_DECIMATE( decimate_score64, 8, 0, 6 );
1946     TEST_DECIMATE( decimate_score16, 4, 0, 6 );
1947     TEST_DECIMATE( decimate_score15, 4, 1, 7 );
1948     report( "decimate_score :" );
1949
1950 #define TEST_LAST( last, lastname, size, ac ) \
1951     if( qf_a.last != qf_ref.last ) \
1952     { \
1953         set_func_name( #lastname ); \
1954         used_asm = 1; \
1955         for( int i = 0; i < 100; i++ ) \
1956         { \
1957             int nnz = 0; \
1958             int max = rand() & (size-1); \
1959             memset( dct1, 0, size*sizeof(dctcoef) ); \
1960             for( int idx = ac; idx < max; idx++ ) \
1961                 nnz |= dct1[idx] = !(rand()&3) + (!(rand()&15))*rand(); \
1962             if( !nnz ) \
1963                 dct1[ac] = 1; \
1964             int result_c = call_c( qf_c.last, dct1+ac ); \
1965             int result_a = call_a( qf_a.last, dct1+ac ); \
1966             if( result_c != result_a ) \
1967             { \
1968                 ok = 0; \
1969                 fprintf( stderr, #lastname ": [FAILED]\n" ); \
1970                 break; \
1971             } \
1972         } \
1973     }
1974
1975     ok = 1; used_asm = 0;
1976     TEST_LAST( coeff_last4              , coeff_last4,   4, 0 );
1977     TEST_LAST( coeff_last8              , coeff_last8,   8, 0 );
1978     TEST_LAST( coeff_last[  DCT_LUMA_AC], coeff_last15, 16, 1 );
1979     TEST_LAST( coeff_last[ DCT_LUMA_4x4], coeff_last16, 16, 0 );
1980     TEST_LAST( coeff_last[ DCT_LUMA_8x8], coeff_last64, 64, 0 );
1981     report( "coeff_last :" );
1982
1983 #define TEST_LEVELRUN( lastname, name, size, ac ) \
1984     if( qf_a.lastname != qf_ref.lastname ) \
1985     { \
1986         set_func_name( #name ); \
1987         used_asm = 1; \
1988         for( int i = 0; i < 100; i++ ) \
1989         { \
1990             x264_run_level_t runlevel_c, runlevel_a; \
1991             int nnz = 0; \
1992             int max = rand() & (size-1); \
1993             memset( dct1, 0, size*sizeof(dctcoef) ); \
1994             memcpy( &runlevel_a, buf1+i, sizeof(x264_run_level_t) ); \
1995             memcpy( &runlevel_c, buf1+i, sizeof(x264_run_level_t) ); \
1996             for( int idx = ac; idx < max; idx++ ) \
1997                 nnz |= dct1[idx] = !(rand()&3) + (!(rand()&15))*rand(); \
1998             if( !nnz ) \
1999                 dct1[ac] = 1; \
2000             int result_c = call_c( qf_c.lastname, dct1+ac, &runlevel_c ); \
2001             int result_a = call_a( qf_a.lastname, dct1+ac, &runlevel_a ); \
2002             if( result_c != result_a || runlevel_c.last != runlevel_a.last || \
2003                 memcmp(runlevel_c.level, runlevel_a.level, sizeof(dctcoef)*result_c) || \
2004                 memcmp(runlevel_c.run, runlevel_a.run, sizeof(uint8_t)*(result_c-1)) ) \
2005             { \
2006                 ok = 0; \
2007                 fprintf( stderr, #name ": [FAILED]\n" ); \
2008                 break; \
2009             } \
2010         } \
2011     }
2012
2013     ok = 1; used_asm = 0;
2014     TEST_LEVELRUN( coeff_level_run4              , coeff_level_run4,   4, 0 );
2015     TEST_LEVELRUN( coeff_level_run8              , coeff_level_run8,   8, 0 );
2016     TEST_LEVELRUN( coeff_level_run[  DCT_LUMA_AC], coeff_level_run15, 16, 1 );
2017     TEST_LEVELRUN( coeff_level_run[ DCT_LUMA_4x4], coeff_level_run16, 16, 0 );
2018     report( "coeff_level_run :" );
2019
2020     return ret;
2021 }
2022
2023 static int check_intra( int cpu_ref, int cpu_new )
2024 {
2025     int ret = 0, ok = 1, used_asm = 0;
2026     ALIGNED_ARRAY_32( pixel, edge,[36] );
2027     ALIGNED_ARRAY_32( pixel, edge2,[36] );
2028     ALIGNED_16( pixel fdec[FDEC_STRIDE*20] );
2029     struct
2030     {
2031         x264_predict_t      predict_16x16[4+3];
2032         x264_predict_t      predict_8x8c[4+3];
2033         x264_predict_t      predict_8x16c[4+3];
2034         x264_predict8x8_t   predict_8x8[9+3];
2035         x264_predict_t      predict_4x4[9+3];
2036         x264_predict_8x8_filter_t predict_8x8_filter;
2037     } ip_c, ip_ref, ip_a;
2038
2039     x264_predict_16x16_init( 0, ip_c.predict_16x16 );
2040     x264_predict_8x8c_init( 0, ip_c.predict_8x8c );
2041     x264_predict_8x16c_init( 0, ip_c.predict_8x16c );
2042     x264_predict_8x8_init( 0, ip_c.predict_8x8, &ip_c.predict_8x8_filter );
2043     x264_predict_4x4_init( 0, ip_c.predict_4x4 );
2044
2045     x264_predict_16x16_init( cpu_ref, ip_ref.predict_16x16 );
2046     x264_predict_8x8c_init( cpu_ref, ip_ref.predict_8x8c );
2047     x264_predict_8x16c_init( cpu_ref, ip_ref.predict_8x16c );
2048     x264_predict_8x8_init( cpu_ref, ip_ref.predict_8x8, &ip_ref.predict_8x8_filter );
2049     x264_predict_4x4_init( cpu_ref, ip_ref.predict_4x4 );
2050
2051     x264_predict_16x16_init( cpu_new, ip_a.predict_16x16 );
2052     x264_predict_8x8c_init( cpu_new, ip_a.predict_8x8c );
2053     x264_predict_8x16c_init( cpu_new, ip_a.predict_8x16c );
2054     x264_predict_8x8_init( cpu_new, ip_a.predict_8x8, &ip_a.predict_8x8_filter );
2055     x264_predict_4x4_init( cpu_new, ip_a.predict_4x4 );
2056
2057     memcpy( fdec, pbuf1, 32*20 * sizeof(pixel) );\
2058
2059     ip_c.predict_8x8_filter( fdec+48, edge, ALL_NEIGHBORS, ALL_NEIGHBORS );
2060
2061 #define INTRA_TEST( name, dir, w, h, align, bench, ... )\
2062     if( ip_a.name[dir] != ip_ref.name[dir] )\
2063     {\
2064         set_func_name( "intra_%s_%s", #name, intra_##name##_names[dir] );\
2065         used_asm = 1;\
2066         memcpy( pbuf3, fdec, FDEC_STRIDE*20 * sizeof(pixel) );\
2067         memcpy( pbuf4, fdec, FDEC_STRIDE*20 * sizeof(pixel) );\
2068         for( int a = 0; a < (do_bench ? 64/sizeof(pixel) : 1); a += align )\
2069         {\
2070             call_c##bench( ip_c.name[dir], pbuf3+48+a, ##__VA_ARGS__ );\
2071             call_a##bench( ip_a.name[dir], pbuf4+48+a, ##__VA_ARGS__ );\
2072             if( memcmp( pbuf3, pbuf4, FDEC_STRIDE*20 * sizeof(pixel) ) )\
2073             {\
2074                 fprintf( stderr, #name "[%d] :  [FAILED]\n", dir );\
2075                 ok = 0;\
2076                 for( int k = -1; k < 16; k++ )\
2077                     printf( "%2x ", edge[16+k] );\
2078                 printf( "\n" );\
2079                 for( int j = 0; j < h; j++ )\
2080                 {\
2081                     printf( "%2x ", edge[14-j] );\
2082                     for( int k = 0; k < w; k++ )\
2083                         printf( "%2x ", pbuf4[48+k+j*FDEC_STRIDE] );\
2084                     printf( "\n" );\
2085                 }\
2086                 printf( "\n" );\
2087                 for( int j = 0; j < h; j++ )\
2088                 {\
2089                     printf( "   " );\
2090                     for( int k = 0; k < w; k++ )\
2091                         printf( "%2x ", pbuf3[48+k+j*FDEC_STRIDE] );\
2092                     printf( "\n" );\
2093                 }\
2094                 break;\
2095             }\
2096         }\
2097     }
2098
2099     for( int i = 0; i < 12; i++ )
2100         INTRA_TEST(   predict_4x4, i,  4,  4,  4, );
2101     for( int i = 0; i < 7; i++ )
2102         INTRA_TEST(  predict_8x8c, i,  8,  8, 16, );
2103     for( int i = 0; i < 7; i++ )
2104         INTRA_TEST( predict_8x16c, i,  8, 16, 16, );
2105     for( int i = 0; i < 7; i++ )
2106         INTRA_TEST( predict_16x16, i, 16, 16, 16, );
2107     for( int i = 0; i < 12; i++ )
2108         INTRA_TEST(   predict_8x8, i,  8,  8,  8, , edge );
2109
2110     set_func_name("intra_predict_8x8_filter");
2111     if( ip_a.predict_8x8_filter != ip_ref.predict_8x8_filter )
2112     {
2113         used_asm = 1;
2114         for( int i = 0; i < 32; i++ )
2115         {
2116             if( !(i&7) || ((i&MB_TOPRIGHT) && !(i&MB_TOP)) )
2117                 continue;
2118             int neighbor = (i&24)>>1;
2119             memset( edge,  0, 36*sizeof(pixel) );
2120             memset( edge2, 0, 36*sizeof(pixel) );
2121             call_c( ip_c.predict_8x8_filter, pbuf1+48, edge,  neighbor, i&7 );
2122             call_a( ip_a.predict_8x8_filter, pbuf1+48, edge2, neighbor, i&7 );
2123             if( !(neighbor&MB_TOPLEFT) )
2124                 edge[15] = edge2[15] = 0;
2125             if( memcmp( edge+7, edge2+7, (i&MB_TOPRIGHT ? 26 : i&MB_TOP ? 17 : 8) * sizeof(pixel) ) )
2126             {
2127                 fprintf( stderr, "predict_8x8_filter :  [FAILED] %d %d\n", (i&24)>>1, i&7);
2128                 ok = 0;
2129             }
2130         }
2131     }
2132
2133 #define EXTREMAL_PLANE( w, h ) \
2134     { \
2135         int max[7]; \
2136         for( int j = 0; j < 7; j++ ) \
2137             max[j] = test ? rand()&PIXEL_MAX : PIXEL_MAX; \
2138         fdec[48-1-FDEC_STRIDE] = (i&1)*max[0]; \
2139         for( int j = 0; j < w/2; j++ ) \
2140             fdec[48+j-FDEC_STRIDE] = (!!(i&2))*max[1]; \
2141         for( int j = w/2; j < w-1; j++ ) \
2142             fdec[48+j-FDEC_STRIDE] = (!!(i&4))*max[2]; \
2143         fdec[48+(w-1)-FDEC_STRIDE] = (!!(i&8))*max[3]; \
2144         for( int j = 0; j < h/2; j++ ) \
2145             fdec[48+j*FDEC_STRIDE-1] = (!!(i&16))*max[4]; \
2146         for( int j = h/2; j < h-1; j++ ) \
2147             fdec[48+j*FDEC_STRIDE-1] = (!!(i&32))*max[5]; \
2148         fdec[48+(h-1)*FDEC_STRIDE-1] = (!!(i&64))*max[6]; \
2149     }
2150     /* Extremal test case for planar prediction. */
2151     for( int test = 0; test < 100 && ok; test++ )
2152         for( int i = 0; i < 128 && ok; i++ )
2153         {
2154             EXTREMAL_PLANE(  8,  8 );
2155             INTRA_TEST(  predict_8x8c, I_PRED_CHROMA_P,  8,  8, 64, 1 );
2156             EXTREMAL_PLANE(  8, 16 );
2157             INTRA_TEST( predict_8x16c, I_PRED_CHROMA_P,  8, 16, 64, 1 );
2158             EXTREMAL_PLANE( 16, 16 );
2159             INTRA_TEST( predict_16x16,  I_PRED_16x16_P, 16, 16, 64, 1 );
2160         }
2161     report( "intra pred :" );
2162     return ret;
2163 }
2164
2165 #define DECL_CABAC(cpu) \
2166 static void run_cabac_decision_##cpu( x264_t *h, uint8_t *dst )\
2167 {\
2168     x264_cabac_t cb;\
2169     x264_cabac_context_init( h, &cb, SLICE_TYPE_P, 26, 0 );\
2170     x264_cabac_encode_init( &cb, dst, dst+0xff0 );\
2171     for( int i = 0; i < 0x1000; i++ )\
2172         x264_cabac_encode_decision_##cpu( &cb, buf1[i]>>1, buf1[i]&1 );\
2173 }\
2174 static void run_cabac_bypass_##cpu( x264_t *h, uint8_t *dst )\
2175 {\
2176     x264_cabac_t cb;\
2177     x264_cabac_context_init( h, &cb, SLICE_TYPE_P, 26, 0 );\
2178     x264_cabac_encode_init( &cb, dst, dst+0xff0 );\
2179     for( int i = 0; i < 0x1000; i++ )\
2180         x264_cabac_encode_bypass_##cpu( &cb, buf1[i]&1 );\
2181 }\
2182 static void run_cabac_terminal_##cpu( x264_t *h, uint8_t *dst )\
2183 {\
2184     x264_cabac_t cb;\
2185     x264_cabac_context_init( h, &cb, SLICE_TYPE_P, 26, 0 );\
2186     x264_cabac_encode_init( &cb, dst, dst+0xff0 );\
2187     for( int i = 0; i < 0x1000; i++ )\
2188         x264_cabac_encode_terminal_##cpu( &cb );\
2189 }
2190 DECL_CABAC(c)
2191 #if HAVE_MMX
2192 DECL_CABAC(asm)
2193 #else
2194 #define run_cabac_decision_asm run_cabac_decision_c
2195 #define run_cabac_bypass_asm run_cabac_bypass_c
2196 #define run_cabac_terminal_asm run_cabac_terminal_c
2197 #endif
2198
2199 static int check_cabac( int cpu_ref, int cpu_new )
2200 {
2201     int ret = 0, ok, used_asm = 1;
2202     x264_t h;
2203     h.sps->i_chroma_format_idc = 3;
2204     if( cpu_ref || run_cabac_decision_c == run_cabac_decision_asm )
2205         return 0;
2206     x264_cabac_init( &h );
2207
2208     set_func_name( "cabac_encode_decision" );
2209     memcpy( buf4, buf3, 0x1000 );
2210     call_c( run_cabac_decision_c, &h, buf3 );
2211     call_a( run_cabac_decision_asm, &h, buf4 );
2212     ok = !memcmp( buf3, buf4, 0x1000 );
2213     report( "cabac decision:" );
2214
2215     set_func_name( "cabac_encode_bypass" );
2216     memcpy( buf4, buf3, 0x1000 );
2217     call_c( run_cabac_bypass_c, &h, buf3 );
2218     call_a( run_cabac_bypass_asm, &h, buf4 );
2219     ok = !memcmp( buf3, buf4, 0x1000 );
2220     report( "cabac bypass:" );
2221
2222     set_func_name( "cabac_encode_terminal" );
2223     memcpy( buf4, buf3, 0x1000 );
2224     call_c( run_cabac_terminal_c, &h, buf3 );
2225     call_a( run_cabac_terminal_asm, &h, buf4 );
2226     ok = !memcmp( buf3, buf4, 0x1000 );
2227     report( "cabac terminal:" );
2228
2229     return ret;
2230 }
2231
2232 static int check_bitstream( int cpu_ref, int cpu_new )
2233 {
2234     x264_bitstream_function_t bs_c;
2235     x264_bitstream_function_t bs_ref;
2236     x264_bitstream_function_t bs_a;
2237
2238     int ret = 0, ok = 1, used_asm = 0;
2239
2240     x264_bitstream_init( 0, &bs_c );
2241     x264_bitstream_init( cpu_ref, &bs_ref );
2242     x264_bitstream_init( cpu_new, &bs_a );
2243     if( bs_a.nal_escape != bs_ref.nal_escape )
2244     {
2245         int size = 0x4000;
2246         uint8_t *input = malloc(size+100);
2247         uint8_t *output1 = malloc(size*2);
2248         uint8_t *output2 = malloc(size*2);
2249         used_asm = 1;
2250         set_func_name( "nal_escape" );
2251         for( int i = 0; i < 100; i++ )
2252         {
2253             /* Test corner-case sizes */
2254             int test_size = i < 10 ? i+1 : rand() & 0x3fff;
2255             /* Test 8 different probability distributions of zeros */
2256             for( int j = 0; j < test_size+32; j++ )
2257                 input[j] = (rand()&((1 << ((i&7)+1)) - 1)) * rand();
2258             uint8_t *end_c = (uint8_t*)call_c1( bs_c.nal_escape, output1, input, input+test_size );
2259             uint8_t *end_a = (uint8_t*)call_a1( bs_a.nal_escape, output2, input, input+test_size );
2260             int size_c = end_c-output1;
2261             int size_a = end_a-output2;
2262             if( size_c != size_a || memcmp( output1, output2, size_c ) )
2263             {
2264                 fprintf( stderr, "nal_escape :  [FAILED] %d %d\n", size_c, size_a );
2265                 ok = 0;
2266                 break;
2267             }
2268         }
2269         for( int j = 0; j < size+32; j++ )
2270             input[j] = rand();
2271         call_c2( bs_c.nal_escape, output1, input, input+size );
2272         call_a2( bs_a.nal_escape, output2, input, input+size );
2273         free(input);
2274         free(output1);
2275         free(output2);
2276     }
2277     report( "nal escape:" );
2278
2279     return ret;
2280 }
2281
2282 static int check_all_funcs( int cpu_ref, int cpu_new )
2283 {
2284     return check_pixel( cpu_ref, cpu_new )
2285          + check_dct( cpu_ref, cpu_new )
2286          + check_mc( cpu_ref, cpu_new )
2287          + check_intra( cpu_ref, cpu_new )
2288          + check_deblock( cpu_ref, cpu_new )
2289          + check_quant( cpu_ref, cpu_new )
2290          + check_cabac( cpu_ref, cpu_new )
2291          + check_bitstream( cpu_ref, cpu_new );
2292 }
2293
2294 static int add_flags( int *cpu_ref, int *cpu_new, int flags, const char *name )
2295 {
2296     *cpu_ref = *cpu_new;
2297     *cpu_new |= flags;
2298     if( *cpu_new & X264_CPU_SSE2_IS_FAST )
2299         *cpu_new &= ~X264_CPU_SSE2_IS_SLOW;
2300     if( !quiet )
2301         fprintf( stderr, "x264: %s\n", name );
2302     return check_all_funcs( *cpu_ref, *cpu_new );
2303 }
2304
2305 static int check_all_flags( void )
2306 {
2307     int ret = 0;
2308     int cpu0 = 0, cpu1 = 0;
2309 #if HAVE_MMX
2310     if( x264_cpu_detect() & X264_CPU_MMX2 )
2311     {
2312         ret |= add_flags( &cpu0, &cpu1, X264_CPU_MMX | X264_CPU_MMX2, "MMX" );
2313         ret |= add_flags( &cpu0, &cpu1, X264_CPU_CACHELINE_64, "MMX Cache64" );
2314         cpu1 &= ~X264_CPU_CACHELINE_64;
2315 #if ARCH_X86
2316         ret |= add_flags( &cpu0, &cpu1, X264_CPU_CACHELINE_32, "MMX Cache32" );
2317         cpu1 &= ~X264_CPU_CACHELINE_32;
2318 #endif
2319         if( x264_cpu_detect() & X264_CPU_LZCNT )
2320         {
2321             ret |= add_flags( &cpu0, &cpu1, X264_CPU_LZCNT, "MMX_LZCNT" );
2322             cpu1 &= ~X264_CPU_LZCNT;
2323         }
2324         ret |= add_flags( &cpu0, &cpu1, X264_CPU_SLOW_CTZ, "MMX SlowCTZ" );
2325         cpu1 &= ~X264_CPU_SLOW_CTZ;
2326     }
2327     if( x264_cpu_detect() & X264_CPU_SSE2 )
2328     {
2329         ret |= add_flags( &cpu0, &cpu1, X264_CPU_SSE | X264_CPU_SSE2 | X264_CPU_SSE2_IS_SLOW, "SSE2Slow" );
2330         ret |= add_flags( &cpu0, &cpu1, X264_CPU_SSE2_IS_FAST, "SSE2Fast" );
2331         ret |= add_flags( &cpu0, &cpu1, X264_CPU_CACHELINE_64, "SSE2Fast Cache64" );
2332         ret |= add_flags( &cpu0, &cpu1, X264_CPU_SHUFFLE_IS_FAST, "SSE2 FastShuffle" );
2333         cpu1 &= ~X264_CPU_SHUFFLE_IS_FAST;
2334         ret |= add_flags( &cpu0, &cpu1, X264_CPU_SLOW_CTZ, "SSE2 SlowCTZ" );
2335         cpu1 &= ~X264_CPU_SLOW_CTZ;
2336         ret |= add_flags( &cpu0, &cpu1, X264_CPU_SLOW_ATOM, "SSE2 SlowAtom" );
2337         cpu1 &= ~X264_CPU_SLOW_ATOM;
2338     }
2339     if( x264_cpu_detect() & X264_CPU_SSE_MISALIGN )
2340     {
2341         cpu1 &= ~X264_CPU_CACHELINE_64;
2342         ret |= add_flags( &cpu0, &cpu1, X264_CPU_SSE_MISALIGN, "SSE_Misalign" );
2343         cpu1 &= ~X264_CPU_SSE_MISALIGN;
2344     }
2345     if( x264_cpu_detect() & X264_CPU_LZCNT )
2346     {
2347         cpu1 &= ~X264_CPU_CACHELINE_64;
2348         ret |= add_flags( &cpu0, &cpu1, X264_CPU_LZCNT, "SSE_LZCNT" );
2349         cpu1 &= ~X264_CPU_LZCNT;
2350     }
2351     if( x264_cpu_detect() & X264_CPU_SSE3 )
2352         ret |= add_flags( &cpu0, &cpu1, X264_CPU_SSE3 | X264_CPU_CACHELINE_64, "SSE3" );
2353     if( x264_cpu_detect() & X264_CPU_SSSE3 )
2354     {
2355         cpu1 &= ~X264_CPU_CACHELINE_64;
2356         ret |= add_flags( &cpu0, &cpu1, X264_CPU_SSSE3, "SSSE3" );
2357         ret |= add_flags( &cpu0, &cpu1, X264_CPU_CACHELINE_64, "SSSE3 Cache64" );
2358         ret |= add_flags( &cpu0, &cpu1, X264_CPU_SHUFFLE_IS_FAST, "SSSE3 FastShuffle" );
2359         cpu1 &= ~X264_CPU_SHUFFLE_IS_FAST;
2360         ret |= add_flags( &cpu0, &cpu1, X264_CPU_SLOW_CTZ, "SSSE3 SlowCTZ" );
2361         cpu1 &= ~X264_CPU_SLOW_CTZ;
2362         ret |= add_flags( &cpu0, &cpu1, X264_CPU_SLOW_ATOM, "SSSE3 SlowAtom" );
2363         cpu1 &= ~X264_CPU_SLOW_ATOM;
2364     }
2365     if( x264_cpu_detect() & X264_CPU_SSE4 )
2366     {
2367         cpu1 &= ~X264_CPU_CACHELINE_64;
2368         ret |= add_flags( &cpu0, &cpu1, X264_CPU_SSE4, "SSE4" );
2369     }
2370     if( x264_cpu_detect() & X264_CPU_AVX )
2371         ret |= add_flags( &cpu0, &cpu1, X264_CPU_AVX, "AVX" );
2372     if( x264_cpu_detect() & X264_CPU_XOP )
2373         ret |= add_flags( &cpu0, &cpu1, X264_CPU_XOP, "XOP" );
2374     if( x264_cpu_detect() & X264_CPU_FMA4 )
2375         ret |= add_flags( &cpu0, &cpu1, X264_CPU_FMA4, "FMA4" );
2376 #elif ARCH_PPC
2377     if( x264_cpu_detect() & X264_CPU_ALTIVEC )
2378     {
2379         fprintf( stderr, "x264: ALTIVEC against C\n" );
2380         ret = check_all_funcs( 0, X264_CPU_ALTIVEC );
2381     }
2382 #elif ARCH_ARM
2383     if( x264_cpu_detect() & X264_CPU_ARMV6 )
2384         ret |= add_flags( &cpu0, &cpu1, X264_CPU_ARMV6, "ARMv6" );
2385     if( x264_cpu_detect() & X264_CPU_NEON )
2386         ret |= add_flags( &cpu0, &cpu1, X264_CPU_NEON, "NEON" );
2387     if( x264_cpu_detect() & X264_CPU_FAST_NEON_MRC )
2388         ret |= add_flags( &cpu0, &cpu1, X264_CPU_FAST_NEON_MRC, "Fast NEON MRC" );
2389 #endif
2390     return ret;
2391 }
2392
2393 int main(int argc, char *argv[])
2394 {
2395     int ret = 0;
2396
2397     if( argc > 1 && !strncmp( argv[1], "--bench", 7 ) )
2398     {
2399 #if !ARCH_X86 && !ARCH_X86_64 && !ARCH_PPC && !ARCH_ARM
2400         fprintf( stderr, "no --bench for your cpu until you port rdtsc\n" );
2401         return 1;
2402 #endif
2403         do_bench = 1;
2404         if( argv[1][7] == '=' )
2405         {
2406             bench_pattern = argv[1]+8;
2407             bench_pattern_len = strlen(bench_pattern);
2408         }
2409         argc--;
2410         argv++;
2411     }
2412
2413     int seed = ( argc > 1 ) ? atoi(argv[1]) : x264_mdate();
2414     fprintf( stderr, "x264: using random seed %u\n", seed );
2415     srand( seed );
2416
2417     buf1 = x264_malloc( 0x1e00 + 0x2000*sizeof(pixel) + 16*BENCH_ALIGNS );
2418     pbuf1 = x264_malloc( 0x1e00*sizeof(pixel) + 16*BENCH_ALIGNS );
2419     if( !buf1 || !pbuf1 )
2420     {
2421         fprintf( stderr, "malloc failed, unable to initiate tests!\n" );
2422         return -1;
2423     }
2424 #define INIT_POINTER_OFFSETS\
2425     buf2 = buf1 + 0xf00;\
2426     buf3 = buf2 + 0xf00;\
2427     buf4 = buf3 + 0x1000*sizeof(pixel);\
2428     pbuf2 = pbuf1 + 0xf00;\
2429     pbuf3 = (pixel*)buf3;\
2430     pbuf4 = (pixel*)buf4;
2431     INIT_POINTER_OFFSETS;
2432     for( int i = 0; i < 0x1e00; i++ )
2433     {
2434         buf1[i] = rand() & 0xFF;
2435         pbuf1[i] = rand() & PIXEL_MAX;
2436     }
2437     memset( buf1+0x1e00, 0, 0x2000*sizeof(pixel) );
2438
2439     /* 16-byte alignment is guaranteed whenever it's useful, but some functions also vary in speed depending on %64 */
2440     if( do_bench )
2441         for( int i = 0; i < BENCH_ALIGNS && !ret; i++ )
2442         {
2443             INIT_POINTER_OFFSETS;
2444             ret |= x264_stack_pagealign( check_all_flags, i*16 );
2445             buf1 += 16;
2446             pbuf1 += 16;
2447             quiet = 1;
2448             fprintf( stderr, "%d/%d\r", i+1, BENCH_ALIGNS );
2449         }
2450     else
2451         ret = check_all_flags();
2452
2453     if( ret )
2454     {
2455         fprintf( stderr, "x264: at least one test has failed. Go and fix that Right Now!\n" );
2456         return -1;
2457     }
2458     fprintf( stderr, "x264: All tests passed Yeah :)\n" );
2459     if( do_bench )
2460         print_bench();
2461     return 0;
2462 }
2463