Update tizen 2.0 beta source
[profile/ivi/liboil.git] / testsuite / stack_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 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include <stdio.h>
33 #include <liboil/liboil.h>
34 #include <ctype.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <math.h>
38 #ifdef HAVE_INTTYPES_H
39 #include <inttypes.h>
40 #endif
41
42 #include <liboil/liboilprototype.h>
43 #include <liboil/liboiltest.h>
44 #include <liboil/liboilcpu.h>
45
46 int verbose = 1;
47
48 /* Amount by which results of different types are allowed to deviate from the
49  * reference.
50  */
51 #define INT_EPSILON 1
52 #define FLOAT_EPSILON 0.0001
53
54 void
55 dump_array (void *data, void *ref_data, OilType type, int pre_n, int stride,
56     int post_n)
57 {
58   int i, j;
59   int s2 = oil_type_sizeof (type);
60   double x;
61
62 #define DUMP(type, format, int) do { \
63   for(i=0;i<post_n;i++){ \
64     float epsilon = (int) ? INT_EPSILON : FLOAT_EPSILON; \
65     printf("    "); \
66     for(j=0;j<pre_n;j++){ \
67       x = fabs(OIL_GET(data, i*stride + j*s2, type) - \
68           OIL_GET(ref_data, i*stride + j*s2, type)); \
69       if (x > epsilon) { \
70         printf("*" format "* (" format ") ", \
71             OIL_GET(data, i*stride + j*s2, type), \
72             OIL_GET(ref_data, i*stride + j*s2, type)); \
73       } else { \
74         printf(" " format " ", OIL_GET(data, i*stride + j*s2, type)); \
75       } \
76     } \
77     printf("\n"); \
78   } \
79 } while(0)
80
81   switch(type) {
82     case OIL_TYPE_s8p:
83     case OIL_TYPE_u8p:
84       DUMP(int8_t, "0x%02" PRIx8, 1);
85       break;
86     case OIL_TYPE_s16p:
87     case OIL_TYPE_u16p:
88       DUMP(uint16_t, "0x%04" PRIx16, 1);
89       break;
90     case OIL_TYPE_s32p:
91     case OIL_TYPE_u32p:
92       DUMP(uint32_t, "0x%08" PRIx32, 1);
93       break;
94     case OIL_TYPE_f32p:
95       DUMP(float, "%g", 0);
96       break;
97     case OIL_TYPE_s64p:
98     case OIL_TYPE_u64p:
99       DUMP(uint64_t, "0x%016" PRIx64, 1);
100       break;
101     case OIL_TYPE_f64p:
102       DUMP(double, "%g", 0);
103       break;
104     default:
105       break;
106   }
107 }
108
109 void
110 dump_source (OilTest *test)
111 {
112   int i;
113   for(i=0;i<OIL_ARG_LAST;i++){
114     OilParameter *p = &test->params[i];
115     if (p->is_pointer) {
116       if (p->direction == 'i' || p->direction == 's') {
117         printf ("  %s:\n", p->parameter_name);
118         dump_array (p->src_data + p->test_header,
119             p->src_data + p->test_header,
120             p->type, p->pre_n, p->stride, p->post_n);
121       }
122     }
123   }
124 }
125
126 void
127 dump_dest_ref (OilTest *test)
128 {
129   int i;
130   for(i=0;i<OIL_ARG_LAST;i++){
131     OilParameter *p = &test->params[i];
132     if (p->is_pointer) {
133       if (p->direction == 'd') {
134         printf ("  %s:\n", p->parameter_name);
135         dump_array (p->ref_data + p->test_header,
136             p->ref_data + p->test_header,
137             p->type, p->pre_n, p->stride, p->post_n);
138       }
139     }
140   }
141 }
142
143 int
144 test_difference (void *data, void *ref_data, OilType type, int pre_n, int stride,
145     int post_n)
146 {
147   int i, j;
148   int s2 = oil_type_sizeof (type);
149   double x;
150
151 #define CHECK(type, is_int) do { \
152   float epsilon = (is_int) ? INT_EPSILON : FLOAT_EPSILON; \
153   for(i=0;i<post_n;i++){ \
154     for(j=0;j<pre_n;j++){ \
155       x = fabs(OIL_GET(data, i*stride + j*s2, type) - \
156           OIL_GET(ref_data, i*stride + j*s2, type)); \
157       if (x > epsilon) { \
158         return 1; \
159       } \
160     } \
161   } \
162   return 0; \
163 } while(0)
164
165   switch(type) {
166     case OIL_TYPE_s8p:
167       CHECK(int8_t, 1);
168       break;
169     case OIL_TYPE_u8p:
170       CHECK(uint8_t, 1);
171       break;
172     case OIL_TYPE_s16p:
173       CHECK(int16_t, 1);
174       break;
175     case OIL_TYPE_u16p:
176       CHECK(uint16_t, 1);
177       break;
178     case OIL_TYPE_s32p:
179       CHECK(int32_t, 1);
180       break;
181     case OIL_TYPE_u32p:
182       CHECK(uint32_t, 1);
183       break;
184     case OIL_TYPE_s64p:
185       CHECK(int64_t, 1);
186       break;
187     case OIL_TYPE_u64p:
188       CHECK(uint64_t, 1);
189       break;
190     case OIL_TYPE_f32p:
191       CHECK(float, 0);
192       break;
193     case OIL_TYPE_f64p:
194       CHECK(double, 0);
195       break;
196     default:
197       return 1;
198   }
199 }
200
201 int
202 check_test (OilTest *test)
203 {
204   int i, failed = 0;
205   for(i=0;i<OIL_ARG_LAST;i++){
206     OilParameter *p = &test->params[i];
207     if (p->is_pointer) {
208       if (p->direction == 'i' || p->direction == 'd') {
209         if (!test_difference(p->test_data + p->test_header,
210             p->ref_data + p->test_header,
211             p->type, p->pre_n, p->stride, p->post_n))
212           continue;
213         printf (" Failure in %s (marked by *, ref in ()):\n",
214             p->parameter_name);
215         dump_array (p->test_data + p->test_header,
216             p->ref_data + p->test_header,
217             p->type, p->pre_n, p->stride, p->post_n);
218         failed = 1;
219       }
220     }
221   }
222   return failed;
223 }
224
225 void print_align(void *ptr)
226 {
227   int i[4];
228
229   if (verbose)printf("stack addr %p\n", &i);
230 }
231
232 OilFunctionClass *realign_klass;
233 int realign_align;
234 int realign_return;
235
236 void realign(int align)
237 {
238 #ifdef HAVE_GCC_ASM
239 #ifdef HAVE_I386
240   __asm__ __volatile__ (
241       "  sub %%edi, %%esp\n"
242 #ifdef HAVE_SYMBOL_UNDERSCORE
243       "  call _check_class_with_alignment\n"
244 #else
245       "  call check_class_with_alignment\n"
246 #endif
247       "  add %%edi, %%esp\n"
248       :: "D" (align)
249   );
250 #endif
251 #ifdef HAVE_AMD64
252   __asm__ __volatile__ (
253       "  sub %%rbx, %%rsp\n"
254 #ifdef HAVE_SYMBOL_UNDERSCORE
255       "  call _check_class_with_alignment\n"
256 #else
257       "  call check_class_with_alignment\n"
258 #endif
259       "  add %%rbx, %%rsp\n"
260       :: "b" (align)
261   );
262 #endif
263 #endif
264 }
265
266 void check_class_with_alignment (void)
267 {
268   OilFunctionClass *klass = realign_klass;
269   int align = realign_align;
270   int test_failed = 0;
271   OilTest *test;
272   OilFunctionImpl *impl;
273
274   test = oil_test_new(klass);
275
276   oil_test_set_iterations(test, 1);
277   test->n = 100;
278
279   impl = klass->reference_impl;
280   oil_test_check_impl (test, impl);
281
282   for (impl = klass->first_impl; impl; impl = impl->next) {
283     if (impl == klass->reference_impl)
284       continue;
285     if (oil_impl_is_runnable (impl)) {
286       if (!oil_test_check_impl (test, impl)) {
287         printf ("impl %s with align %d\n", impl->name, align);
288         printf("dests for %s:\n", klass->name);
289         dump_dest_ref(test);
290         printf("sources for %s:\n", klass->name);
291         dump_source(test);
292       }
293     }
294   }
295   oil_test_free(test);
296
297   realign_return = test_failed;
298 }
299
300 int check_class(OilFunctionClass *klass)
301 {
302   OilTest *test;
303   int failed = 0;
304   int align;
305   int step = 4;
306
307   oil_class_optimize (klass);
308
309   if(verbose) printf("checking class %s\n", klass->name);
310   
311   test = oil_test_new(klass);
312
313 #ifdef HAVE_AMD64
314   step = 16;
315 #endif
316
317   for (align = 0; align <= 32; align += step) {
318     printf("  alignment %d\n", align);
319     realign_klass = klass;
320     realign_align = align;
321     realign(align);
322     failed |= realign_return;
323   }
324   oil_test_free (test);
325
326   return failed;
327 }
328
329 int main (int argc, char *argv[])
330 {
331   int failed = 0;
332   int i, n;
333
334   oil_init ();
335
336 #ifdef __APPLE__
337   /* the dynamic loader on MacOS/X crashes if someone unaligns the stack, so it's
338      unlikely that any code gets away with doing it.  Our test code doesn't get
339      away with it either, so we'll just bail out. */
340   return 0;
341 #endif
342
343   n = oil_class_get_n_classes ();
344   for (i = 0; i < n; i++) {
345     OilFunctionClass *klass = oil_class_get_by_index(i);
346     failed |= check_class(klass);
347   }
348
349   return failed;
350 }