Git init
[external/liboil.git] / testsuite / align.c
1 /*
2  * Copyright (c) 2004 David A. Schleef <ds@schleef.org>
3  * Copyright (c) 2005 Eric Anholt <anholt@FreeBSD.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
24  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 /* Tests math functions against the reference, failing if they differ by more
29  * than some epsilon, and printing the difference.
30  */
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include <stdio.h>
36 #include <liboil/liboil.h>
37 #include <ctype.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <math.h>
41 #ifdef HAVE_INTTYPES_H
42 #include <inttypes.h>
43 #endif
44
45 #include <liboil/liboilprototype.h>
46 #include <liboil/liboiltest.h>
47 #include <liboil/liboilcpu.h>
48
49 /* Amount by which results of different types are allowed to deviate from the
50  * reference.
51  */
52 #define INT_EPSILON 1
53 #define FLOAT_EPSILON 0.0001
54
55 void
56 dump_array (void *data, void *ref_data, OilType type, int pre_n, int stride,
57     int post_n)
58 {
59   int i, j;
60   int s2 = oil_type_sizeof (type);
61   double x;
62
63 #define DUMP(type, format, int) do { \
64   for(i=0;i<post_n;i++){ \
65     float epsilon = (int) ? INT_EPSILON : FLOAT_EPSILON; \
66     printf("    "); \
67     for(j=0;j<pre_n;j++){ \
68       x = fabs(OIL_GET(data, i*stride + j*s2, type) - \
69           OIL_GET(ref_data, i*stride + j*s2, type)); \
70       if (x > epsilon) { \
71         printf("*" format "* (" format ") ", \
72             OIL_GET(data, i*stride + j*s2, type), \
73             OIL_GET(ref_data, i*stride + j*s2, type)); \
74       } else { \
75         printf(" " format " ", OIL_GET(data, i*stride + j*s2, type)); \
76       } \
77     } \
78     printf("\n"); \
79   } \
80 } while(0)
81
82   switch(type) {
83     case OIL_TYPE_s8p:
84     case OIL_TYPE_u8p:
85       DUMP(int8_t, "0x%02" PRIx8, 1);
86       break;
87     case OIL_TYPE_s16p:
88     case OIL_TYPE_u16p:
89       DUMP(uint16_t, "0x%04" PRIx16, 1);
90       break;
91     case OIL_TYPE_s32p:
92     case OIL_TYPE_u32p:
93       DUMP(uint32_t, "0x%08" PRIx32, 1);
94       break;
95     case OIL_TYPE_f32p:
96       DUMP(float, "%g", 0);
97       break;
98     case OIL_TYPE_s64p:
99     case OIL_TYPE_u64p:
100       DUMP(uint64_t, "0x%016" PRIx64, 1);
101       break;
102     case OIL_TYPE_f64p:
103       DUMP(double, "%g", 0);
104       break;
105     default:
106       break;
107   }
108 }
109
110 void
111 dump_source (OilTest *test)
112 {
113   int i;
114   for(i=0;i<OIL_ARG_LAST;i++){
115     OilParameter *p = &test->params[i];
116     if (p->is_pointer) {
117       if (p->direction == 'i' || p->direction == 's') {
118         printf ("  %s:\n", p->parameter_name);
119         dump_array (p->src_data + p->test_header,
120             p->src_data + p->test_header,
121             p->type, p->pre_n, p->stride, p->post_n);
122       }
123     }
124   }
125 }
126
127 void
128 dump_dest_ref (OilTest *test)
129 {
130   int i;
131   for(i=0;i<OIL_ARG_LAST;i++){
132     OilParameter *p = &test->params[i];
133     if (p->is_pointer) {
134       if (p->direction == 'd') {
135         printf ("  %s:\n", p->parameter_name);
136         dump_array (p->ref_data + p->test_header,
137             p->ref_data + p->test_header,
138             p->type, p->pre_n, p->stride, p->post_n);
139       }
140     }
141   }
142 }
143
144 int
145 test_difference (void *data, void *ref_data, OilType type, int pre_n, int stride,
146     int post_n)
147 {
148   int i, j;
149   int s2 = oil_type_sizeof (type);
150   double x;
151
152 #define CHECK(type, is_int) do { \
153   float epsilon = (is_int) ? INT_EPSILON : FLOAT_EPSILON; \
154   for(i=0;i<post_n;i++){ \
155     for(j=0;j<pre_n;j++){ \
156       x = fabs(OIL_GET(data, i*stride + j*s2, type) - \
157           OIL_GET(ref_data, i*stride + j*s2, type)); \
158       if (x > epsilon) { \
159         return 1; \
160       } \
161     } \
162   } \
163   return 0; \
164 } while(0)
165
166   switch(type) {
167     case OIL_TYPE_s8p:
168       CHECK(int8_t, 1);
169       break;
170     case OIL_TYPE_u8p:
171       CHECK(uint8_t, 1);
172       break;
173     case OIL_TYPE_s16p:
174       CHECK(int16_t, 1);
175       break;
176     case OIL_TYPE_u16p:
177       CHECK(uint16_t, 1);
178       break;
179     case OIL_TYPE_s32p:
180       CHECK(int32_t, 1);
181       break;
182     case OIL_TYPE_u32p:
183       CHECK(uint32_t, 1);
184       break;
185     case OIL_TYPE_s64p:
186       CHECK(int64_t, 1);
187       break;
188     case OIL_TYPE_u64p:
189       CHECK(uint64_t, 1);
190       break;
191     case OIL_TYPE_f32p:
192       CHECK(float, 0);
193       break;
194     case OIL_TYPE_f64p:
195       CHECK(double, 0);
196       break;
197     default:
198       return 1;
199   }
200 }
201
202 int
203 check_test (OilTest *test)
204 {
205   int i, failed = 0;
206   for(i=0;i<OIL_ARG_LAST;i++){
207     OilParameter *p = &test->params[i];
208     if (p->is_pointer) {
209       if (p->direction == 'i' || p->direction == 'd') {
210         if (!test_difference(p->test_data + p->test_header,
211             p->ref_data + p->test_header,
212             p->type, p->pre_n, p->stride, p->post_n))
213           continue;
214         printf (" Failure in %s (marked by *, ref in ()):\n",
215             p->parameter_name);
216         dump_array (p->test_data + p->test_header,
217             p->ref_data + p->test_header,
218             p->type, p->pre_n, p->stride, p->post_n);
219         failed = 1;
220       }
221     }
222   }
223   return failed;
224 }
225
226 int check_class_with_alignment (OilFunctionClass *klass,
227     OilArgType arg, int n, int align)
228 {
229   OilParameter *p;
230   int align_offset;
231   int test_failed = 0;
232   OilTest *test;
233   OilFunctionImpl *impl;
234
235   test = oil_test_new(klass);
236
237   p = &test->params[arg];
238   align_offset = align * oil_type_sizeof(p->type);
239   oil_test_set_test_header(test, p, OIL_TEST_HEADER + align_offset);
240
241   oil_test_set_iterations(test, 1);
242   test->n = n;
243   test->m = n;
244
245   impl = klass->reference_impl;
246   oil_test_check_impl (test, impl);
247
248   for (impl = klass->first_impl; impl; impl = impl->next) {
249     if (impl == klass->reference_impl)
250       continue;
251     if (oil_impl_is_runnable (impl)) {
252       if (!oil_test_check_impl (test, impl)) {
253         printf ("impl %s with arg %d offset %d, n=%d\n", impl->name, arg,
254             align_offset, n);
255         printf("dests for %s:\n", klass->name);
256         dump_dest_ref(test);
257         printf("sources for %s:\n", klass->name);
258         dump_source(test);
259       }
260     }
261   }
262   oil_test_free(test);
263
264   return test_failed;
265 }
266
267 /* Check a function class for all implementations matching the reference when
268  * each parameter is varied in its offset from malloc's alignment by 0 - 3 units
269  * times size of the type, and with the number of elements varying between 8 and
270  * 11.
271  */
272 int check_class(OilFunctionClass *klass)
273 {
274   OilTest *test;
275   int failed = 0;
276   int i, n;
277
278   oil_class_optimize (klass);
279
280   printf("checking class %s\n", klass->name);
281   
282   test = oil_test_new(klass);
283   for (i=0; i < OIL_ARG_LAST; i++) {
284     OilParameter *p;
285     int align;
286
287     p = &test->params[i];
288     if (!p->is_pointer) {
289       continue;
290     }
291
292     for (n = 8; n <= 11; n++) {
293       for (align = 0; align <= 3; align++) {
294         failed |= check_class_with_alignment (klass, i, n, align);
295       }
296     }
297   }
298   oil_test_free (test);
299
300   return failed;
301 }
302
303 int main (int argc, char *argv[])
304 {
305   int failed = 0;
306   int i, n;
307
308   oil_init ();
309
310   n = oil_class_get_n_classes ();
311   for (i = 0; i < n; i++) {
312     OilFunctionClass *klass = oil_class_get_by_index(i);
313     failed |= check_class(klass);
314   }
315
316   return failed;
317 }