Fix (Cexpr?struct1:struct2).member
[tinycc.git] / tests / tests2 / 99_fastcall.c
blobee4b67d20d31ec06fe340d4d6a2b1128920e0d92
1 #include <stdio.h>
2 #include <assert.h>
4 #ifndef _WIN32
5 #define __fastcall __attribute((fastcall))
6 #endif
8 #if 1
9 #define SYMBOL(x) _##x
10 #else
11 #define SYMBOL(x) x
12 #endif
14 /////////////////////////////////////////////////////////////////////////
15 ////////// TRAP FRAMEWORK
16 /////////////////////////////////////////////////////////////////////////
17 // if you cast 'TRAP' to a function pointer and call it,
18 // it will save all 8 registers,
19 // and jump into C-code (previously set using 'SET_TRAP_HANDLER(x)'),
20 // in C-code you can pop DWORDs from stack and modify registers
23 void *SYMBOL(trap_handler);
25 extern unsigned char SYMBOL(trap)[];
26 asm (
27 ".text;"
28 "_trap:;"
29 "pushl %esp;"
30 "pusha;"
31 "addl $0x4, 0xc(%esp);"
32 "pushl %esp;"
33 "call *_trap_handler;"
34 "addl $0x4, %esp;"
35 "movl 0xc(%esp), %eax;"
36 "movl %eax, 0x20(%esp);"
37 "popa;"
38 "popl %esp;"
39 "ret;"
42 struct trapframe {
43 unsigned edi, esi, ebp, esp, ebx, edx, ecx, eax;
47 #define M_FLOAT(addr) (*(float *)(addr))
48 #define M_DWORD(addr) (*(unsigned *)(addr))
49 #define M_WORD(addr) (*(unsigned short *)(addr))
50 #define M_BYTE(addr) (*(unsigned char *)(addr))
51 #define R_EAX ((tf)->eax)
52 #define R_ECX ((tf)->ecx)
53 #define R_EDX ((tf)->edx)
54 #define R_EBX ((tf)->ebx)
55 #define R_ESP ((tf)->esp)
56 #define R_EBP ((tf)->ebp)
57 #define R_ESI ((tf)->esi)
58 #define R_EDI ((tf)->edi)
60 #define ARG(x) (M_DWORD(R_ESP + (x) * 4))
62 #define RETN(x) do { \
63 M_DWORD(R_ESP + (x)) = M_DWORD(R_ESP); \
64 R_ESP += (x); \
65 } while (0)
67 #define DUMP() do { \
68 unsigned i; \
69 printf("EAX: %08X\n", R_EAX); \
70 printf("ECX: %08X\n", R_ECX); \
71 printf("EDX: %08X\n", R_EDX); \
72 printf("EBX: %08X\n", R_EBX); \
73 printf("ESP: %08X\n", R_ESP); \
74 printf("EBP: %08X\n", R_EBP); \
75 printf("ESI: %08X\n", R_ESI); \
76 printf("EDI: %08X\n", R_EDI); \
77 printf("\n"); \
78 printf("[RETADDR]: %08X\n", M_DWORD(R_ESP)); \
79 for (i = 1; i <= 8; i++) { \
80 printf("[ARG%4d]: %08X\n", i, ARG(i)); \
81 } \
82 } while (0)
84 #define SET_TRAP_HANDLER(x) ((SYMBOL(trap_handler)) = (x))
85 #define TRAP ((void *) &SYMBOL(trap))
89 /////////////////////////////////////////////////////////////////////////
90 ////////// SAFECALL FRAMEWORK
91 /////////////////////////////////////////////////////////////////////////
92 // this framework will convert any calling convention to cdecl
93 // usage: first set call target with 'SET_SAFECALL_TARGET(x)'
94 // then cast 'SAFECALL' to target function pointer type and invoke it
95 // after calling, 'ESPDIFF' is the difference of old and new esp
97 void *SYMBOL(sc_call_target);
98 unsigned SYMBOL(sc_retn_addr);
99 unsigned SYMBOL(sc_old_esp);
100 unsigned SYMBOL(sc_new_esp);
102 extern unsigned char SYMBOL(safecall)[];
103 asm (
104 ".text;"
105 "_safecall:;"
106 "popl _sc_retn_addr;"
107 "movl %esp, _sc_old_esp;"
108 "call *_sc_call_target;"
109 "movl %esp, _sc_new_esp;"
110 "movl _sc_old_esp, %esp;"
111 "jmp *_sc_retn_addr;"
114 #define SET_SAFECALL_TARGET(x) ((SYMBOL(sc_call_target)) = (x))
115 #define SAFECALL ((void *) &SYMBOL(safecall))
116 #define ESPDIFF (SYMBOL(sc_new_esp) - SYMBOL(sc_old_esp))
119 /////////////////////////////////////////////////////////////////////////
120 ////////// TEST FASTCALL INVOKE
121 /////////////////////////////////////////////////////////////////////////
123 void check_fastcall_invoke_0(struct trapframe *tf)
125 //DUMP();
126 RETN(0);
129 void check_fastcall_invoke_1(struct trapframe *tf)
131 //DUMP();
132 assert(R_ECX == 0x11111111);
133 RETN(0);
135 void check_fastcall_invoke_2(struct trapframe *tf)
137 //DUMP();
138 assert(R_ECX == 0x11111111);
139 assert(R_EDX == 0x22222222);
140 RETN(0);
142 void check_fastcall_invoke_3(struct trapframe *tf)
144 //DUMP();
145 assert(R_ECX == 0x11111111);
146 assert(R_EDX == 0x22222222);
147 assert(ARG(1) == 0x33333333);
148 RETN(1*4);
150 void check_fastcall_invoke_4(struct trapframe *tf)
152 //DUMP();
153 assert(R_ECX == 0x11111111);
154 assert(R_EDX == 0x22222222);
155 assert(ARG(1) == 0x33333333);
156 assert(ARG(2) == 0x44444444);
157 RETN(2*4);
160 void check_fastcall_invoke_5(struct trapframe *tf)
162 //DUMP();
163 assert(R_ECX == 0x11111111);
164 assert(R_EDX == 0x22222222);
165 assert(ARG(1) == 0x33333333);
166 assert(ARG(2) == 0x44444444);
167 assert(ARG(3) == 0x55555555);
168 RETN(3*4);
171 void test_fastcall_invoke()
173 SET_TRAP_HANDLER(check_fastcall_invoke_0);
174 ((void __fastcall (*)(void)) TRAP)();
176 SET_TRAP_HANDLER(check_fastcall_invoke_1);
177 ((void __fastcall (*)(unsigned)) TRAP)(0x11111111);
179 SET_TRAP_HANDLER(check_fastcall_invoke_2);
180 ((void __fastcall (*)(unsigned, unsigned)) TRAP)(0x11111111, 0x22222222);
182 SET_TRAP_HANDLER(check_fastcall_invoke_3);
183 ((void __fastcall (*)(unsigned, unsigned, unsigned)) TRAP)(0x11111111, 0x22222222, 0x33333333);
185 SET_TRAP_HANDLER(check_fastcall_invoke_4);
186 ((void __fastcall (*)(unsigned, unsigned, unsigned, unsigned)) TRAP)(0x11111111, 0x22222222, 0x33333333, 0x44444444);
188 SET_TRAP_HANDLER(check_fastcall_invoke_5);
189 ((void __fastcall (*)(unsigned, unsigned, unsigned, unsigned, unsigned)) TRAP)(0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555);
193 /////////////////////////////////////////////////////////////////////////
194 ////////// TEST FUNCTION CODE GENERATION
195 /////////////////////////////////////////////////////////////////////////
197 int __fastcall check_fastcall_espdiff_0(void)
199 return 0;
202 int __fastcall check_fastcall_espdiff_1(int a)
204 return a;
207 int __fastcall check_fastcall_espdiff_2(int a, int b)
209 return a + b;
212 int __fastcall check_fastcall_espdiff_3(int a, int b, int c)
214 return a + b + c;
217 int __fastcall check_fastcall_espdiff_4(int a, int b, int c, int d)
219 return a + b + c + d;
222 int __fastcall check_fastcall_espdiff_5(int a, int b, int c, int d, int e)
224 return a + b + c + d + e;
227 void test_fastcall_espdiff()
229 int x;
230 SET_SAFECALL_TARGET(check_fastcall_espdiff_0);
231 x = ((typeof(&check_fastcall_espdiff_0))SAFECALL)();
232 assert(x == 0);
233 assert(ESPDIFF == 0);
235 SET_SAFECALL_TARGET(check_fastcall_espdiff_1);
236 x = ((typeof(&check_fastcall_espdiff_1))SAFECALL)(1);
237 assert(x == 1);
238 assert(ESPDIFF == 0);
240 SET_SAFECALL_TARGET(check_fastcall_espdiff_2);
241 x = ((typeof(&check_fastcall_espdiff_2))SAFECALL)(1, 2);
242 assert(x == 1 + 2);
243 assert(ESPDIFF == 0);
245 SET_SAFECALL_TARGET(check_fastcall_espdiff_3);
246 x = ((typeof(&check_fastcall_espdiff_3))SAFECALL)(1, 2, 3);
247 assert(x == 1 + 2 + 3);
248 assert(ESPDIFF == 1*4);
250 SET_SAFECALL_TARGET(check_fastcall_espdiff_4);
251 x = ((typeof(&check_fastcall_espdiff_4))SAFECALL)(1, 2, 3, 4);
252 assert(x == 1 + 2 + 3 + 4);
253 assert(ESPDIFF == 2*4);
255 SET_SAFECALL_TARGET(check_fastcall_espdiff_5);
256 x = ((typeof(&check_fastcall_espdiff_5))SAFECALL)(1, 2, 3, 4, 5);
257 assert(x == 1 + 2 + 3 + 4 + 5);
258 assert(ESPDIFF == 3*4);
261 int main()
263 #define N 10000
264 int i;
266 for (i = 1; i <= N; i++) {
267 test_fastcall_espdiff();
270 for (i = 1; i <= N; i++) {
271 test_fastcall_invoke();
274 puts("TEST OK");
275 return 0;