OSDN Git Service

2001-03-27 Jon Beniston <jon@beniston.com>
[pf3gnuchains/gcc-fork.git] / libffi / src / ffitest.c
1 /* -----------------------------------------------------------------------
2    ffitest.c - Copyright (c) 1996, 1997, 1998  Cygnus Solutions
3
4    Permission is hereby granted, free of charge, to any person obtaining
5    a copy of this software and associated documentation files (the
6    ``Software''), to deal in the Software without restriction, including
7    without limitation the rights to use, copy, modify, merge, publish,
8    distribute, sublicense, and/or sell copies of the Software, and to
9    permit persons to whom the Software is furnished to do so, subject to
10    the following conditions:
11
12    The above copyright notice and this permission notice shall be included
13    in all copies or substantial portions of the Software.
14
15    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
16    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18    IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21    OTHER DEALINGS IN THE SOFTWARE.
22    ----------------------------------------------------------------------- */
23
24 #include <ffi.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <float.h>
29
30 /* This is lame. Long double support is barely there under SunOS 4.x  */
31 #if defined(SPARC) && (SIZEOF_LONG_DOUBLE != 16)
32 #define BROKEN_LONG_DOUBLE
33 #endif
34
35 #define CHECK(x) !(x) ? fail(__FILE__, __LINE__) : 0 
36
37 static int fail(char *file, int line)
38 {
39   fprintf(stderr, "Test failure: %s line %d\n", file, line);
40   exit(EXIT_FAILURE);
41   /*@notreached@*/
42   return 0;
43 }
44
45 #define MAX_ARGS 256
46
47 static size_t my_strlen(char *s)
48 {
49   return (strlen(s));
50 }
51
52 static int promotion(signed char sc, signed short ss, 
53                      unsigned char uc, unsigned short us)
54 {
55   int r = (int) sc + (int) ss + (int) uc + (int) us;
56
57   return r;
58 }
59
60 static signed char return_sc(signed char sc)
61 {
62   return sc;
63 }
64
65 static unsigned char return_uc(unsigned char uc)
66 {
67   return uc;
68 }
69
70 static long long return_ll(long long ll)
71 {
72   return ll;
73 }
74
75 static int floating(int a, float b, double c, long double d, int e)
76 {
77   int i;
78
79 #if 0
80   /* This is ifdef'd out for now. long double support under SunOS/gcc
81      is pretty much non-existent.  You'll get the odd bus error in library
82      routines like printf().  */
83   printf("%d %f %f %Lf %d\n", a, (double)b, c, d, e);
84 #endif
85
86   i = (int) ((float)a/b + ((float)c/(float)d));
87
88   return i;
89 }
90
91 static float many(float f1,
92                   float f2,
93                   float f3,
94                   float f4,
95                   float f5,
96                   float f6,
97                   float f7,
98                   float f8,
99                   float f9,
100                   float f10,
101                   float f11,
102                   float f12,
103                   float f13)
104 {
105 #if 0
106   printf("%f %f %f %f %f %f %f %f %f %f %f %f %f\n",
107          (double) f1, (double) f2, (double) f3, (double) f4, (double) f5, 
108          (double) f6, (double) f7, (double) f8, (double) f9, (double) f10,
109          (double) f11, (double) f12, (double) f13);
110 #endif
111
112   return ((f1/f2+f3/f4+f5/f6+f7/f8+f9/f10+f11/f12) * f13);
113 }
114
115 static double dblit(float f)
116 {
117   return f/3.0;
118 }
119
120 static long double ldblit(float f)
121 {
122   return (long double) (((long double) f)/ (long double) 3.0);
123 }
124
125 typedef struct
126 {
127   unsigned char uc;
128   double d;
129   unsigned int ui;
130 } test_structure_1;
131
132 typedef struct
133 {
134   double d1;
135   double d2;
136 } test_structure_2;
137
138 typedef struct
139 {
140   int si;
141 } test_structure_3;
142
143 typedef struct
144 {
145   unsigned ui1;
146   unsigned ui2;
147   unsigned ui3;
148 } test_structure_4;
149
150 typedef struct
151 {
152   char c1;
153   char c2;
154 } test_structure_5;
155
156 static test_structure_1 struct1(test_structure_1 ts)
157 {
158   /*@-type@*/
159   ts.uc++;
160   /*@=type@*/
161   ts.d--;
162   ts.ui++;
163
164   return ts;
165 }
166
167 static test_structure_2 struct2(test_structure_2 ts)
168 {
169   ts.d1--;
170   ts.d2--;
171
172   return ts;
173 }
174
175 static test_structure_3 struct3(test_structure_3 ts)
176 {
177   ts.si = -(ts.si*2);
178
179   return ts;
180 }
181
182 static test_structure_4 struct4(test_structure_4 ts)
183 {
184   ts.ui3 = ts.ui1 * ts.ui2 * ts.ui3;
185
186   return ts;
187 }
188
189 static test_structure_5 struct5(test_structure_5 ts1, test_structure_5 ts2)
190 {
191   ts1.c1 += ts2.c1;
192   ts1.c2 -= ts2.c2;
193
194   return ts1;
195 }
196
197 /* Take an int and a float argument, together with int userdata, and    */
198 /* return the sum.                                                      */
199 static void closure_test_fn(ffi_cif* cif,void* resp,void** args, void* userdata)
200 {
201     *(int*)resp =
202          *(int *)args[0] + (int)(*(float *)args[1]) + (int)(long)userdata;
203 }
204
205 typedef int (*closure_test_type)(int, float);
206
207 int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[])
208 {
209   ffi_cif cif;
210   ffi_type *args[MAX_ARGS];
211   void *values[MAX_ARGS];
212   char *s;
213   signed char sc;
214   unsigned char uc;
215   signed short ss;
216   unsigned short us;
217   unsigned long ul;
218   long long ll;
219   float f;
220   double d;
221   long double ld;
222   signed int si1;
223   signed int si2;
224
225 #if defined(ALPHA) || defined(IA64) || defined(SPARC64) || (defined(MIPS) && (_MIPS_SIM == _ABIN32))
226   long long rint;
227 #else
228   int rint;
229 #endif
230   long long rlonglong;
231
232   ffi_type ts1_type;
233   ffi_type ts2_type;
234   ffi_type ts3_type;
235   ffi_type ts4_type;  
236   ffi_type ts5_type;
237   ffi_type *ts1_type_elements[4];
238   ffi_type *ts2_type_elements[3];
239   ffi_type *ts3_type_elements[2];
240   ffi_type *ts4_type_elements[4];
241   ffi_type *ts5_type_elements[3];
242
243   ts1_type.size = 0;
244   ts1_type.alignment = 0;
245   ts1_type.type = FFI_TYPE_STRUCT;
246
247   ts2_type.size = 0;
248   ts2_type.alignment = 0;
249   ts2_type.type = FFI_TYPE_STRUCT;
250
251   ts3_type.size = 0;
252   ts3_type.alignment = 0;
253   ts3_type.type = FFI_TYPE_STRUCT;
254
255   ts4_type.size = 0;
256   ts4_type.alignment = 0;
257   ts4_type.type = FFI_TYPE_STRUCT;
258
259   ts5_type.size = 0;
260   ts5_type.alignment = 0;
261   ts5_type.type = FFI_TYPE_STRUCT;
262
263   /*@-immediatetrans@*/
264   ts1_type.elements = ts1_type_elements;
265   ts2_type.elements = ts2_type_elements;
266   ts3_type.elements = ts3_type_elements;
267   ts4_type.elements = ts4_type_elements;
268   ts5_type.elements = ts5_type_elements;
269   /*@=immediatetrans@*/
270   
271   ts1_type_elements[0] = &ffi_type_uchar;
272   ts1_type_elements[1] = &ffi_type_double;
273   ts1_type_elements[2] = &ffi_type_uint;
274   ts1_type_elements[3] = NULL;
275   
276   ts2_type_elements[0] = &ffi_type_double;
277   ts2_type_elements[1] = &ffi_type_double;
278   ts2_type_elements[2] = NULL;
279
280   ts3_type_elements[0] = &ffi_type_sint;
281   ts3_type_elements[1] = NULL;
282
283   ts4_type_elements[0] = &ffi_type_uint;
284   ts4_type_elements[1] = &ffi_type_uint;
285   ts4_type_elements[2] = &ffi_type_uint;
286   ts4_type_elements[3] = NULL;
287
288   ts5_type_elements[0] = &ffi_type_schar;
289   ts5_type_elements[1] = &ffi_type_schar;
290   ts5_type_elements[2] = NULL;
291
292   ul = 0;
293
294   /* return value tests */
295   {
296 #if defined(MIPS) /* || defined(ARM) */
297     puts ("long long tests not run. This is a known bug on this architecture.");
298 #else
299     args[0] = &ffi_type_sint64;
300     values[0] = &ll;
301     
302     /* Initialize the cif */
303     CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, 
304                        &ffi_type_sint64, args) == FFI_OK);
305
306     for (ll = 0LL; ll < 100LL; ll++)
307       {
308         ul++;
309         ffi_call(&cif, FFI_FN(return_ll), &rlonglong, values);
310         CHECK(rlonglong == ll);
311       }
312
313     for (ll = 55555555555000LL; ll < 55555555555100LL; ll++)
314       {
315         ul++;
316         ffi_call(&cif, FFI_FN(return_ll), &rlonglong, values);
317         CHECK(rlonglong == ll);
318       }
319 #endif
320
321     args[0] = &ffi_type_schar;
322     values[0] = &sc;
323     
324     /* Initialize the cif */
325     CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, 
326                        &ffi_type_schar, args) == FFI_OK);
327
328     for (sc = (signed char) -127; 
329          sc < (signed char) 127; /*@-type@*/ sc++ /*@=type@*/)
330       {
331         ul++;
332         ffi_call(&cif, FFI_FN(return_sc), &rint, values);
333         CHECK(rint == (int) sc);
334       }
335
336     args[0] = &ffi_type_uchar;
337     values[0] = &uc;
338     
339     /* Initialize the cif */
340     CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, 
341                        &ffi_type_uchar, args) == FFI_OK);
342
343     for (uc = (unsigned char) '\x00'; 
344          uc < (unsigned char) '\xff'; /*@-type@*/ uc++ /*@=type@*/)
345       {
346         ul++;
347         ffi_call(&cif, FFI_FN(return_uc), &rint, values);
348         CHECK(rint == (signed int) uc);
349       }
350
351     printf("%lu return value tests run\n", ul);
352   }
353
354 #ifdef BROKEN_LONG_DOUBLE
355   printf ("This architecture has broken `long double' support. No floating point\ntests have been run.\n");
356 #else
357   /* float arg tests */
358   {
359     args[0] = &ffi_type_float;
360     values[0] = &f;
361
362     /* Initialize the cif */
363     CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, 
364                        &ffi_type_longdouble, args) == FFI_OK);
365
366     f = 3.14159;
367
368 #if 0
369   /* This is ifdef'd out for now. long double support under SunOS/gcc
370      is pretty much non-existent.  You'll get the odd bus error in library
371      routines like printf().  */
372     printf ("%Lf\n", ldblit(f));
373 #endif
374     ld = 666;
375     ffi_call(&cif, FFI_FN(ldblit), &ld, values);
376
377 #if 0
378   /* This is ifdef'd out for now. long double support under SunOS/gcc
379      is pretty much non-existent.  You'll get the odd bus error in library
380      routines like printf().  */
381     printf ("%Lf, %Lf, %Lf, %Lf\n", ld, ldblit(f), ld - ldblit(f), LDBL_EPSILON);
382 #endif
383
384     /* These are not always the same!! Check for a reasonable delta */
385     /*@-realcompare@*/
386     if (ld - ldblit(f) < LDBL_EPSILON)
387     /*@=realcompare@*/
388         puts("long double return value tests ok!");
389     else
390         CHECK(0);
391   }
392
393   /* float arg tests */
394   {
395     args[0] = &ffi_type_sint;
396     values[0] = &si1;
397     args[1] = &ffi_type_float;
398     values[1] = &f;
399     args[2] = &ffi_type_double;
400     values[2] = &d;
401     args[3] = &ffi_type_longdouble;
402     values[3] = &ld;
403     args[4] = &ffi_type_sint;
404     values[4] = &si2;
405     
406     /* Initialize the cif */
407     CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 5,
408                        &ffi_type_sint, args) == FFI_OK);
409
410     si1 = 6;
411     f = 3.14159;
412     d = (double)1.0/(double)3.0;
413     ld = 2.71828182846L;
414     si2 = 10;
415
416     floating (si1, f, d, ld, si2);
417
418     ffi_call(&cif, FFI_FN(floating), &rint, values);
419
420     printf ("%d vs %d\n", rint, floating (si1, f, d, ld, si2));
421
422     CHECK(rint == floating(si1, f, d, ld, si2));
423
424     printf("float arg tests ok!\n");
425   }
426 #endif
427
428   /* strlen tests */
429   {
430     args[0] = &ffi_type_pointer;
431     values[0] = (void*) &s;
432     
433     /* Initialize the cif */
434     CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, 
435                        &ffi_type_sint, args) == FFI_OK);
436
437     s = "a";
438     ffi_call(&cif, FFI_FN(my_strlen), &rint, values);
439     CHECK(rint == 1);
440
441     s = "1234567";
442     ffi_call(&cif, FFI_FN(my_strlen), &rint, values);
443     CHECK(rint == 7);
444
445     s = "1234567890123456789012345";
446     ffi_call(&cif, FFI_FN(my_strlen), &rint, values);
447     CHECK(rint == 25);
448
449     printf("strlen tests passed\n");
450   }
451
452   /* float arg tests */
453   {
454     args[0] = &ffi_type_float;
455     values[0] = &f;
456     
457     /* Initialize the cif */
458     CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, 
459                        &ffi_type_double, args) == FFI_OK);
460
461     f = 3.14159;
462
463     ffi_call(&cif, FFI_FN(dblit), &d, values);
464
465     /* These are not always the same!! Check for a reasonable delta */
466     /*@-realcompare@*/
467     CHECK(d - dblit(f) < DBL_EPSILON);
468     /*@=realcompare@*/
469
470     printf("double return value tests ok!\n");
471   }
472
473   /* many arg tests */
474   {
475     float ff;
476     float fa[13];
477     
478     for (ul = 0; ul < 13; ul++)
479       {
480         args[ul] = &ffi_type_float;
481         values[ul] = &fa[ul];
482         fa[ul] = (float) ul;
483       }
484
485     /* Initialize the cif */
486     CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 13, 
487                        &ffi_type_float, args) == FFI_OK);
488
489     /*@-usedef@*/
490     ff =  many(fa[0], fa[1],
491                fa[2], fa[3],
492                fa[4], fa[5],
493                fa[6], fa[7],
494                fa[8], fa[9],
495                fa[10],fa[11],fa[12]);
496     /*@=usedef@*/
497
498     ffi_call(&cif, FFI_FN(many), &f, values);
499
500     /*@-realcompare@*/
501     if (f - ff < FLT_EPSILON)
502     /*@=realcompare@*/
503         printf("many arg tests ok!\n");
504     else
505 #ifdef POWERPC
506         printf("many arg tests failed!  This is a gcc bug.\n");
507 #else
508         CHECK(0);
509 #endif
510   }
511
512   /* promotion tests */
513   {
514     args[0] = &ffi_type_schar;
515     args[1] = &ffi_type_sshort;
516     args[2] = &ffi_type_uchar;
517     args[3] = &ffi_type_ushort;
518     values[0] = &sc;
519     values[1] = &ss;
520     values[2] = &uc;
521     values[3] = &us;
522     
523     /* Initialize the cif */
524     CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, 
525                        &ffi_type_sint, args) == FFI_OK);
526
527     us = 0;
528     ul = 0;
529
530     for (sc = (signed char) -127; 
531          sc <= (signed char) 120; /*@-type@*/ sc += 1 /*@=type@*/)
532       for (ss = -30000; ss <= 30000; ss += 10000)
533         for (uc = (unsigned char) 0; 
534              uc <= (unsigned char) 200; /*@-type@*/ uc += 20 /*@=type@*/)
535           for (us = 0; us <= 60000; us += 10000)
536             {
537               ul++;
538               ffi_call(&cif, FFI_FN(promotion), &rint, values);
539               CHECK(rint == (int) sc + (int) ss + (int) uc + (int) us);
540             }
541     printf("%lu promotion tests run\n", ul);
542   }
543
544 #ifndef X86_WIN32 /* Structures dont work on Win32 */
545
546   /* struct tests */
547   {
548     test_structure_1 ts1_arg;
549     /* This is a hack to get a properly aligned result buffer */
550     test_structure_1 *ts1_result = 
551       (test_structure_1 *) malloc (sizeof(test_structure_1));
552
553     args[0] = &ts1_type;
554     values[0] = &ts1_arg;
555     
556     /* Initialize the cif */
557     CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, 
558                        &ts1_type, args) == FFI_OK);
559
560     ts1_arg.uc = '\x01';
561     ts1_arg.d = 3.14159;
562     ts1_arg.ui = 555;
563
564     ffi_call(&cif, FFI_FN(struct1), ts1_result, values);
565
566     CHECK(ts1_result->ui == 556);
567     CHECK(ts1_result->d == 3.14159 - 1);
568
569     puts ("structure test 1 ok!\n");
570
571     free (ts1_result);
572   }
573
574   /* struct tests */
575   {
576     test_structure_2 ts2_arg;
577
578     /* This is a hack to get a properly aligned result buffer */
579     test_structure_2 *ts2_result = 
580       (test_structure_2 *) malloc (sizeof(test_structure_2));
581
582     args[0] = &ts2_type;
583     values[0] = &ts2_arg;
584     
585     /* Initialize the cif */
586     CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, 
587                        &ts2_type, args) == FFI_OK);
588
589     ts2_arg.d1 = 5.55;
590     ts2_arg.d2 = 6.66;
591
592     printf ("%g\n", ts2_result->d1);
593     printf ("%g\n", ts2_result->d2);
594
595     ffi_call(&cif, FFI_FN(struct2), ts2_result, values);
596
597     printf ("%g\n", ts2_result->d1);
598     printf ("%g\n", ts2_result->d2);
599     
600     CHECK(ts2_result->d1 == 5.55 - 1);
601     CHECK(ts2_result->d2 == 6.66 - 1);
602
603     printf("structure test 2 ok!\n");
604
605     free (ts2_result);
606   }
607
608   /* struct tests */
609   {
610     int compare_value;
611     test_structure_3 ts3_arg;
612     test_structure_3 *ts3_result = 
613       (test_structure_3 *) malloc (sizeof(test_structure_3));
614
615     args[0] = &ts3_type;
616     values[0] = &ts3_arg;
617     
618     /* Initialize the cif */
619     CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, 
620                        &ts3_type, args) == FFI_OK);
621
622     ts3_arg.si = -123;
623     compare_value = ts3_arg.si;
624
625     ffi_call(&cif, FFI_FN(struct3), ts3_result, values);
626
627     printf ("%d %d\n", ts3_result->si, -(compare_value*2));
628
629     if (ts3_result->si == -(ts3_arg.si*2))
630         puts ("structure test 3 ok!");
631     else
632       {
633         puts ("Structure test 3 found structure passing bug.");
634         puts ("  Current versions of GCC are not 100% compliant with the");
635         puts ("  n32 ABI.  There is a known problem related to passing");
636         puts ("  small structures.  Send a bug report to the gcc maintainers.");
637       }
638
639     free (ts3_result);
640   }
641
642   /* struct tests */
643   {
644     test_structure_4 ts4_arg;
645
646     /* This is a hack to get a properly aligned result buffer */
647     test_structure_4 *ts4_result = 
648       (test_structure_4 *) malloc (sizeof(test_structure_4));
649
650     args[0] = &ts4_type;
651     values[0] = &ts4_arg;
652     
653     /* Initialize the cif */
654     CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, 
655                        &ts4_type, args) == FFI_OK);
656
657     ts4_arg.ui1 = 2;
658     ts4_arg.ui2 = 3;
659     ts4_arg.ui3 = 4;
660
661     ffi_call (&cif, FFI_FN(struct4), ts4_result, values);
662     
663     if (ts4_result->ui3 == 2U * 3U * 4U)
664       puts ("structure test 4 ok!");
665     else
666       puts ("Structure test 4 found GCC's structure passing bug.");
667
668     free (ts4_result);
669   }
670
671   /* struct tests */
672   {
673     test_structure_5 ts5_arg1, ts5_arg2;
674
675     /* This is a hack to get a properly aligned result buffer */
676     test_structure_5 *ts5_result = 
677       (test_structure_5 *) malloc (sizeof(test_structure_5));
678
679     args[0] = &ts5_type;
680     args[1] = &ts5_type;
681     values[0] = &ts5_arg1;
682     values[1] = &ts5_arg2;
683     
684     /* Initialize the cif */
685     CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, 
686                        &ts5_type, args) == FFI_OK);
687
688     ts5_arg1.c1 = 2;
689     ts5_arg1.c2 = 6;
690     ts5_arg2.c1 = 5;
691     ts5_arg2.c2 = 3;
692
693     ffi_call (&cif, FFI_FN(struct5), ts5_result, values);
694     
695     if (ts5_result->c1 == 7 
696         && ts5_result->c2 == 3)
697       puts ("structure test 5 ok!");
698     else
699       puts ("Structure test 5 found GCC's structure passing bug.");
700
701     free (ts5_result);
702   }
703
704 #else
705   printf("Structure passing doesn't work on Win32.\n");
706 #endif /* X86_WIN32 */
707
708 # if FFI_CLOSURES
709   /* A simple closure test */
710     {
711       ffi_closure cl;
712       ffi_type * cl_arg_types[3];
713
714       cl_arg_types[0] = &ffi_type_sint;
715       cl_arg_types[1] = &ffi_type_float;
716       cl_arg_types[2] = NULL;
717       
718       /* Initialize the cif */
719       CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, 
720                          &ffi_type_sint, cl_arg_types) == FFI_OK);
721
722       CHECK(ffi_prep_closure(&cl, &cif, closure_test_fn,
723                              (void *) 3 /* userdata */)
724             == FFI_OK);
725       CHECK((*((closure_test_type)(&cl)))(1, 2.0) == 6);
726     }
727 # endif
728
729   /* If we arrived here, all is good */
730   (void) puts("\nLooks good. No surprises.\n");
731
732   /*@-compdestroy@*/
733
734   return 0;
735 }
736