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
dump_array(void * data,void * ref_data,OilType type,int pre_n,int stride,int post_n)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
dump_source(OilTest * test)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
dump_dest_ref(OilTest * test)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
test_difference(void * data,void * ref_data,OilType type,int pre_n,int stride,int post_n)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
check_test(OilTest * test)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
check_class_with_alignment(OilFunctionClass * klass,OilArgType arg,int n,int align)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 */
check_class(OilFunctionClass * klass)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
main(int argc,char * argv[])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 }
318