diff options
Diffstat (limited to 'gcc/testsuite/gcc.target/i386/iamcu/test_struct_returning.c')
-rw-r--r-- | gcc/testsuite/gcc.target/i386/iamcu/test_struct_returning.c | 362 |
1 files changed, 362 insertions, 0 deletions
diff --git a/gcc/testsuite/gcc.target/i386/iamcu/test_struct_returning.c b/gcc/testsuite/gcc.target/i386/iamcu/test_struct_returning.c new file mode 100644 index 00000000000..49a6b1f0a6e --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/iamcu/test_struct_returning.c @@ -0,0 +1,362 @@ +/* This tests returning of structures. */ + +#include "defines.h" +#include "macros.h" +#include "args.h" + +struct IntegerRegisters iregbits = { ~0, ~0, ~0, ~0, ~0, ~0 }; +struct IntegerRegisters iregs; +unsigned int num_iregs; + +int current_test; +int num_failed = 0; + +typedef enum { + EAX = 0, + EAX_EDX, + LONG_LONG, + FLOAT, + DOUBLE, + FLOAT_FLOAT, + EAX_FLOAT, + FLOAT_EDX, + MEM +} Type; + +/* Structures which should be returned in EAX/LONG_LONG/EAX_EDX. */ +#define D(I,MEMBERS,C,B) struct S_ ## I { MEMBERS ; }; Type class_ ## I = C; \ +struct S_ ## I f_ ## I (void) { struct S_ ## I s; iamcu_memset (&s, 0, sizeof(s)); B; return s; } + +D(1,char m1, EAX, s.m1=42) +D(2,short m1, EAX, s.m1=42) +D(3,int m1, EAX, s.m1=42) +D(4,char m1[3], EAX, s.m1[0]=42) +D(5,char m1[4], EAX, s.m1[0]=42) +D(6,char m1;char m2; char m3, EAX, s.m1=42) +D(7,char m1;short m2, EAX, s.m1=42) + +D(30,long long m1, LONG_LONG, s.m1=0xadadbeefadadbeefLL) + +D(50,short m1;int m2, EAX_EDX, s.m1=42; s.m2=43) +D(51,char m1;int m2, EAX_EDX, s.m1=42; s.m2=43) +D(52,char m1[5], EAX_EDX, s.m1[0]=42; s.m1[4]=43) +D(53,char m1[6], EAX_EDX, s.m1[0]=42; s.m1[4]=43) +D(54,char m1[7], EAX_EDX, s.m1[0]=42; s.m1[4]=43) +D(55,char m1[8], EAX_EDX, s.m1[0]=42; s.m1[4]=43) +D(56,char m1;short m2[2], EAX_EDX, s.m1=42; s.m2[1]=43) +D(57,short m1[4], EAX_EDX, s.m1[0]=42; s.m1[2]=43) +D(58,int m1[2], EAX_EDX, s.m1[0]=42; s.m1[1]=43) +D(59,int m1;char m2, EAX_EDX, s.m1=42; s.m2=43) +D(60,int m1;short m2, EAX_EDX, s.m1=42; s.m2=43) +D(61,int m1;short m2; char m3, EAX_EDX, s.m1=42; s.m2=43) +D(62,int m1;char m2; short m3, EAX_EDX, s.m1=42; s.m2=43) + +/* Packed members. */ +D(100,short m1[1];int m2 PACKED, EAX_EDX, s.m1[0]=42; s.m2=43) +D(101,char m1; short m2 PACKED; char m3, EAX_EDX, s.m1=42; s.m3=43) + +/* Structures which should be returned in FLOAT/DOUBLE. */ +#undef D +#define D(I,MEMBERS,C,B) struct S_ ## I { MEMBERS ; }; Type class_ ## I = C; \ +struct S_ ## I f_ ## I (void) { struct S_ ## I s; iamcu_memset (&s, 0, sizeof(s)); B; return s; } + +D(200,float f, FLOAT, s.f=42) +D(201,double d, DOUBLE, s.d=42) + +D(300,float m;char m2, FLOAT_EDX, s.m=42; s.m2=43) +D(301,float m;short m2, FLOAT_EDX, s.m=42; s.m2=43) +D(302,float m;int m2, FLOAT_EDX, s.m=42; s.m2=43) + +D(400,char m1; float m2, EAX_FLOAT, s.m1=42; s.m2=43) +D(401,short m1; float m2, EAX_FLOAT, s.m1=42; s.m2=43) +D(402,int m1; float m2, EAX_FLOAT, s.m1=42; s.m2=43) + +D(500,float m;float m2, FLOAT_FLOAT, s.m=42; s.m2=43) +D(501,float f[2], FLOAT, s.f[0]=42; s.f[1]=43) + +/* Structures which should be returned in MEM. */ +void *struct_addr; +#undef D +#define D(I,MEMBERS) struct S_ ## I { MEMBERS ; }; Type class_ ## I = MEM; \ +struct S_ ## I f_ ## I (void) { union {unsigned char c; struct S_ ## I s;} u; iamcu_memset (&u.s, 0, sizeof(u.s)); u.c = 42; return u.s; } + +/* Too large. */ +D(600,char m1[17]) +D(601,short m1[9]) +D(602,int m1[5]) +D(603,long m1[3]) +D(604,short m1[8];char c) +D(605,char m1[1];int i[4]) +D(606,float m1[5]) +D(607,double m1[3]) +D(608,char m1[1];float f[4]) +D(609,char m1[1];double d[2]) +D(610,__complex long double m1[1]) + +/* Too large due to padding. */ +D(611,char m1[1]; int i; char c2) + +/* Special tests. */ +#undef D +#define D(I,MEMBERS,B) struct S_ ## I { MEMBERS ; }; Type class_ ## I = MEM; \ +struct S_ ## I f_ ## I (void) { struct S_ ## I s; B; return s; } +D(700,float f[4], s.f[0] = s.f[1] = s.f[2] = s.f[3] = 42) + +void +check_eax (void) +{ + switch (current_test) + { + case 1: + case 4: + case 5: + case 6: + case 7: + eax &= 0xff; + break; + case 2: + eax &= 0xffff; + break; + case 3: + eax &= 0xffff; + break; + default: + abort (); + } + if (eax != 42) + num_failed++; +} + +void +check_eax_edx (void) +{ + unsigned long long ll = eax | ((unsigned long long) edx) << 32; + switch (current_test) + { + case 50: + eax &= 0xffff; + break; + case 52: + case 53: + case 54: + case 55: + edx &= 0xff; + case 51: + eax &= 0xff; + break; + case 56: + eax &= 0xff; + edx &= 0xffff; + break; + case 57: + eax &= 0xffff; + edx &= 0xffff; + break; + case 58: + break; + case 59: + case 62: + edx &= 0xff; + break; + case 60: + case 61: + edx &= 0xffff; + break; + case 100: + eax &= 0xffff; + edx = (ll >> 16) & 0xffffffff; + break; + case 101: + edx = (eax >> 24) & 0xff; + eax &= 0xff; + break; + default: + abort (); + } + if (eax != 42 || edx != 43) + num_failed++; +} + +void +check_float_edx (void) +{ + union + { + unsigned long l; + float f; + } ueax; + switch (current_test) + { + case 300: + edx &= 0xff; + break; + case 301: + edx &= 0xffff; + break; + case 302: + edx &= 0xffff; + break; + default: + abort (); + } + ueax.l = eax; + if (ueax.f != 42 || edx != 43) + num_failed++; +} + +void +check_eax_float (void) +{ + union + { + unsigned long l; + float f; + } uedx; + switch (current_test) + { + case 400: + eax &= 0xff; + break; + case 401: + eax &= 0xffff; + break; + case 402: + eax &= 0xffff; + break; + default: + abort (); + } + uedx.l = edx; + if (eax != 42 || uedx.f != 43) + num_failed++; +} + +void +check_float_float (void) +{ + union + { + unsigned long l; + float f; + } ueax, uedx; + switch (current_test) + { + case 500: + case 501: + break; + default: + abort (); + } + ueax.l = eax; + uedx.l = edx; + if (ueax.f != 42 || uedx.f != 43) + num_failed++; +} + +void +check_all (Type class, unsigned long size) +{ + union + { + struct + { + unsigned long eax; + unsigned long edx; + } eax_edx; + unsigned long long ll; + float f; + double d; + } u; + + switch (class) + { + case EAX: + check_eax (); + break; + case LONG_LONG: + if (0xadadbeefL != eax || 0xadadbeefL != edx) + num_failed++; + break; + case EAX_EDX: + check_eax_edx (); + break; + case FLOAT: + u.eax_edx.eax = eax; + if (u.f != 42) + num_failed++; + break; + case DOUBLE: + u.eax_edx.eax = eax; + u.eax_edx.edx = edx; + if (u.d != 42) + num_failed++; + break; + case FLOAT_EDX: + check_float_edx (); + break; + case FLOAT_FLOAT: + check_float_float (); + break; + case EAX_FLOAT: + check_eax_float (); + break; + case MEM: + /* sret_eax contains a slot whose address is given to the f_* + functions. The slot may be a temporary one on stack. When + this function is called, hopefully this slot hasn't be + overriden. */ + if (sret_eax != eax) + num_failed++; + else if (current_test < 700) + { + if (*(unsigned char*)sret_eax != 42 + || *(unsigned char*)struct_addr != 42) + num_failed++; + } + else + { + if (*(float *)sret_eax != 42 + || *(float *)struct_addr != 42) + num_failed++; + } + break; + } +} + +#undef D +#define D(I) { static struct S_ ## I s; current_test = I; struct_addr = (void*)&s; \ + clear_non_sret_int_registers; \ + s = WRAP_RET(f_ ## I) (); \ + check_all(class_ ## I, sizeof(s)); \ +} + +int +main (void) +{ + D(1) D(2) D(3) D(4) D(5) D(6) D(7) + + D(30) + + D(50) D(51) D(52) D(53) D(54) D(55) D(56) D(57) D(58) D(59) + D(60) D(61) D(62) + + D(100) D(101) + + D(200) D(201) + + D(300) D(301) D(302) + + D(400) D(401) D(402) + + D(500) D(501) + + D(600) D(601) D(602) D(603) D(604) D(605) D(606) D(607) D(608) D(609) + D(610) D(611) + + D(700) + + if (num_failed) + abort (); + + return 0; +} |