1 | #include <libtcc.h>
|
---|
2 | #include <stdlib.h>
|
---|
3 | #include <stdio.h>
|
---|
4 | #include <string.h>
|
---|
5 | #include <stdarg.h>
|
---|
6 |
|
---|
7 | // MinGW has 80-bit rather than 64-bit long double which isn't compatible with TCC or MSVC
|
---|
8 | #if defined(_WIN32) && defined(__GNUC__)
|
---|
9 | #define LONG_DOUBLE double
|
---|
10 | #define LONG_DOUBLE_LITERAL(x) x
|
---|
11 | #else
|
---|
12 | #define LONG_DOUBLE long double
|
---|
13 | #define LONG_DOUBLE_LITERAL(x) x ## L
|
---|
14 | #endif
|
---|
15 |
|
---|
16 | static int g_argc;
|
---|
17 | static char **g_argv;
|
---|
18 |
|
---|
19 | static void set_options(TCCState *s, int argc, char **argv)
|
---|
20 | {
|
---|
21 | int i;
|
---|
22 | for (i = 1; i < argc; ++i) {
|
---|
23 | char *a = argv[i];
|
---|
24 | if (a[0] == '-') {
|
---|
25 | if (a[1] == 'B')
|
---|
26 | tcc_set_lib_path(s, a+2);
|
---|
27 | else if (a[1] == 'I')
|
---|
28 | tcc_add_include_path(s, a+2);
|
---|
29 | else if (a[1] == 'L')
|
---|
30 | tcc_add_library_path(s, a+2);
|
---|
31 | }
|
---|
32 | }
|
---|
33 | }
|
---|
34 |
|
---|
35 | typedef int (*callback_type) (void*);
|
---|
36 |
|
---|
37 | /*
|
---|
38 | * Compile source code and call a callback with a pointer to the symbol "f".
|
---|
39 | */
|
---|
40 | static int run_callback(const char *src, callback_type callback) {
|
---|
41 | TCCState *s;
|
---|
42 | int result;
|
---|
43 | void *ptr;
|
---|
44 |
|
---|
45 | s = tcc_new();
|
---|
46 | if (!s)
|
---|
47 | return -1;
|
---|
48 |
|
---|
49 | set_options(s, g_argc, g_argv);
|
---|
50 |
|
---|
51 | if (tcc_set_output_type(s, TCC_OUTPUT_MEMORY) == -1)
|
---|
52 | return -1;
|
---|
53 | if (tcc_compile_string(s, src) == -1)
|
---|
54 | return -1;
|
---|
55 | if (tcc_relocate(s, TCC_RELOCATE_AUTO) == -1)
|
---|
56 | return -1;
|
---|
57 |
|
---|
58 | ptr = tcc_get_symbol(s, "f");
|
---|
59 | if (!ptr)
|
---|
60 | return -1;
|
---|
61 | result = callback(ptr);
|
---|
62 |
|
---|
63 | tcc_delete(s);
|
---|
64 |
|
---|
65 | return result;
|
---|
66 | }
|
---|
67 |
|
---|
68 | #define STR2(x) #x
|
---|
69 | #define STR(x) STR2(x)
|
---|
70 |
|
---|
71 | #define RET_PRIMITIVE_TEST(name, type, val) \
|
---|
72 | static int ret_ ## name ## _test_callback(void *ptr) { \
|
---|
73 | type (*callback) (type) = (type(*)(type))ptr; \
|
---|
74 | type x = val; \
|
---|
75 | type y = callback(x); \
|
---|
76 | return (y == x+x) ? 0 : -1; \
|
---|
77 | } \
|
---|
78 | \
|
---|
79 | static int ret_ ## name ## _test(void) { \
|
---|
80 | const char *src = STR(type) " f(" STR(type) " x) {return x+x;}"; \
|
---|
81 | return run_callback(src, ret_ ## name ## _test_callback); \
|
---|
82 | }
|
---|
83 |
|
---|
84 | RET_PRIMITIVE_TEST(int, int, 70000)
|
---|
85 | RET_PRIMITIVE_TEST(longlong, long long, 4333369356528LL)
|
---|
86 | RET_PRIMITIVE_TEST(float, float, 63.0)
|
---|
87 | RET_PRIMITIVE_TEST(double, double, 14789798.0)
|
---|
88 | RET_PRIMITIVE_TEST(longdouble, LONG_DOUBLE, LONG_DOUBLE_LITERAL(378943892.0))
|
---|
89 |
|
---|
90 | /*
|
---|
91 | * ret_2float_test:
|
---|
92 | *
|
---|
93 | * On x86-64, a struct with 2 floats should be packed into a single
|
---|
94 | * SSE register (VT_DOUBLE is used for this purpose).
|
---|
95 | */
|
---|
96 | typedef struct ret_2float_test_type_s {float x, y;} ret_2float_test_type;
|
---|
97 | typedef ret_2float_test_type (*ret_2float_test_function_type) (ret_2float_test_type);
|
---|
98 |
|
---|
99 | static int ret_2float_test_callback(void *ptr) {
|
---|
100 | ret_2float_test_function_type f = (ret_2float_test_function_type)ptr;
|
---|
101 | ret_2float_test_type a = {10, 35};
|
---|
102 | ret_2float_test_type r;
|
---|
103 | r = f(a);
|
---|
104 | return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
|
---|
105 | }
|
---|
106 |
|
---|
107 | static int ret_2float_test(void) {
|
---|
108 | const char *src =
|
---|
109 | "typedef struct ret_2float_test_type_s {float x, y;} ret_2float_test_type;"
|
---|
110 | "ret_2float_test_type f(ret_2float_test_type a) {\n"
|
---|
111 | " ret_2float_test_type r = {a.x*5, a.y*3};\n"
|
---|
112 | " return r;\n"
|
---|
113 | "}\n";
|
---|
114 |
|
---|
115 | return run_callback(src, ret_2float_test_callback);
|
---|
116 | }
|
---|
117 |
|
---|
118 | /*
|
---|
119 | * ret_2double_test:
|
---|
120 | *
|
---|
121 | * On x86-64, a struct with 2 doubles should be passed in two SSE
|
---|
122 | * registers.
|
---|
123 | */
|
---|
124 | typedef struct ret_2double_test_type_s {double x, y;} ret_2double_test_type;
|
---|
125 | typedef ret_2double_test_type (*ret_2double_test_function_type) (ret_2double_test_type);
|
---|
126 |
|
---|
127 | static int ret_2double_test_callback(void *ptr) {
|
---|
128 | ret_2double_test_function_type f = (ret_2double_test_function_type)ptr;
|
---|
129 | ret_2double_test_type a = {10, 35};
|
---|
130 | ret_2double_test_type r;
|
---|
131 | r = f(a);
|
---|
132 | return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
|
---|
133 | }
|
---|
134 |
|
---|
135 | static int ret_2double_test(void) {
|
---|
136 | const char *src =
|
---|
137 | "typedef struct ret_2double_test_type_s {double x, y;} ret_2double_test_type;"
|
---|
138 | "ret_2double_test_type f(ret_2double_test_type a) {\n"
|
---|
139 | " ret_2double_test_type r = {a.x*5, a.y*3};\n"
|
---|
140 | " return r;\n"
|
---|
141 | "}\n";
|
---|
142 |
|
---|
143 | return run_callback(src, ret_2double_test_callback);
|
---|
144 | }
|
---|
145 |
|
---|
146 | /*
|
---|
147 | * ret_8plus2double_test:
|
---|
148 | *
|
---|
149 | * This catches a corner case in the x86_64 ABI code: the first 7
|
---|
150 | * arguments fit into registers, the 8th doesn't, but the 9th argument
|
---|
151 | * fits into the 8th XMM register.
|
---|
152 | *
|
---|
153 | * Note that the purpose of the 10th argument is to avoid a situation
|
---|
154 | * in which gcc would accidentally put the double at the right
|
---|
155 | * address, thus causing a success message even though TCC actually
|
---|
156 | * generated incorrect code.
|
---|
157 | */
|
---|
158 | typedef ret_2double_test_type (*ret_8plus2double_test_function_type) (double, double, double, double, double, double, double, ret_2double_test_type, double, double);
|
---|
159 |
|
---|
160 | static int ret_8plus2double_test_callback(void *ptr) {
|
---|
161 | ret_8plus2double_test_function_type f = (ret_8plus2double_test_function_type)ptr;
|
---|
162 | ret_2double_test_type a = {10, 35};
|
---|
163 | ret_2double_test_type r;
|
---|
164 | r = f(0, 0, 0, 0, 0, 0, 0, a, 37, 38);
|
---|
165 | return ((r.x == 37) && (r.y == 37)) ? 0 : -1;
|
---|
166 | }
|
---|
167 |
|
---|
168 | static int ret_8plus2double_test(void) {
|
---|
169 | const char *src =
|
---|
170 | "typedef struct ret_2double_test_type_s {double x, y;} ret_2double_test_type;"
|
---|
171 | "ret_2double_test_type f(double x1, double x2, double x3, double x4, double x5, double x6, double x7, ret_2double_test_type a, double x8, double x9) {\n"
|
---|
172 | " ret_2double_test_type r = { x8, x8 };\n"
|
---|
173 | " return r;\n"
|
---|
174 | "}\n";
|
---|
175 |
|
---|
176 | return run_callback(src, ret_8plus2double_test_callback);
|
---|
177 | }
|
---|
178 |
|
---|
179 | /*
|
---|
180 | * ret_mixed_test:
|
---|
181 | *
|
---|
182 | * On x86-64, a struct with a double and a 64-bit integer should be
|
---|
183 | * passed in one SSE register and one integer register.
|
---|
184 | */
|
---|
185 | typedef struct ret_mixed_test_type_s {double x; long long y;} ret_mixed_test_type;
|
---|
186 | typedef ret_mixed_test_type (*ret_mixed_test_function_type) (ret_mixed_test_type);
|
---|
187 |
|
---|
188 | static int ret_mixed_test_callback(void *ptr) {
|
---|
189 | ret_mixed_test_function_type f = (ret_mixed_test_function_type)ptr;
|
---|
190 | ret_mixed_test_type a = {10, 35};
|
---|
191 | ret_mixed_test_type r;
|
---|
192 | r = f(a);
|
---|
193 | return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
|
---|
194 | }
|
---|
195 |
|
---|
196 | static int ret_mixed_test(void) {
|
---|
197 | const char *src =
|
---|
198 | "typedef struct ret_mixed_test_type_s {double x; long long y;} ret_mixed_test_type;"
|
---|
199 | "ret_mixed_test_type f(ret_mixed_test_type a) {\n"
|
---|
200 | " ret_mixed_test_type r = {a.x*5, a.y*3};\n"
|
---|
201 | " return r;\n"
|
---|
202 | "}\n";
|
---|
203 |
|
---|
204 | return run_callback(src, ret_mixed_test_callback);
|
---|
205 | }
|
---|
206 |
|
---|
207 | /*
|
---|
208 | * ret_mixed2_test:
|
---|
209 | *
|
---|
210 | * On x86-64, a struct with two floats and two 32-bit integers should
|
---|
211 | * be passed in one SSE register and one integer register.
|
---|
212 | */
|
---|
213 | typedef struct ret_mixed2_test_type_s {float x,x2; int y,y2;} ret_mixed2_test_type;
|
---|
214 | typedef ret_mixed2_test_type (*ret_mixed2_test_function_type) (ret_mixed2_test_type);
|
---|
215 |
|
---|
216 | static int ret_mixed2_test_callback(void *ptr) {
|
---|
217 | ret_mixed2_test_function_type f = (ret_mixed2_test_function_type)ptr;
|
---|
218 | ret_mixed2_test_type a = {10, 5, 35, 7 };
|
---|
219 | ret_mixed2_test_type r;
|
---|
220 | r = f(a);
|
---|
221 | return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
|
---|
222 | }
|
---|
223 |
|
---|
224 | static int ret_mixed2_test(void) {
|
---|
225 | const char *src =
|
---|
226 | "typedef struct ret_mixed2_test_type_s {float x, x2; int y,y2;} ret_mixed2_test_type;"
|
---|
227 | "ret_mixed2_test_type f(ret_mixed2_test_type a) {\n"
|
---|
228 | " ret_mixed2_test_type r = {a.x*5, 0, a.y*3, 0};\n"
|
---|
229 | " return r;\n"
|
---|
230 | "}\n";
|
---|
231 |
|
---|
232 | return run_callback(src, ret_mixed2_test_callback);
|
---|
233 | }
|
---|
234 |
|
---|
235 | /*
|
---|
236 | * ret_mixed3_test:
|
---|
237 | *
|
---|
238 | * On x86-64, this struct should be passed in two integer registers.
|
---|
239 | */
|
---|
240 | typedef struct ret_mixed3_test_type_s {float x; int y; float x2; int y2;} ret_mixed3_test_type;
|
---|
241 | typedef ret_mixed3_test_type (*ret_mixed3_test_function_type) (ret_mixed3_test_type);
|
---|
242 |
|
---|
243 | static int ret_mixed3_test_callback(void *ptr) {
|
---|
244 | ret_mixed3_test_function_type f = (ret_mixed3_test_function_type)ptr;
|
---|
245 | ret_mixed3_test_type a = {10, 5, 35, 7 };
|
---|
246 | ret_mixed3_test_type r;
|
---|
247 | r = f(a);
|
---|
248 | return ((r.x == a.x*5) && (r.y2 == a.y*3)) ? 0 : -1;
|
---|
249 | }
|
---|
250 |
|
---|
251 | static int ret_mixed3_test(void) {
|
---|
252 | const char *src =
|
---|
253 | "typedef struct ret_mixed3_test_type_s {float x; int y; float x2; int y2;} ret_mixed3_test_type;"
|
---|
254 | "ret_mixed3_test_type f(ret_mixed3_test_type a) {\n"
|
---|
255 | " ret_mixed3_test_type r = {a.x*5, 0, 0, a.y*3};\n"
|
---|
256 | " return r;\n"
|
---|
257 | "}\n";
|
---|
258 |
|
---|
259 | return run_callback(src, ret_mixed3_test_callback);
|
---|
260 | }
|
---|
261 |
|
---|
262 | /*
|
---|
263 | * reg_pack_test: return a small struct which should be packed into
|
---|
264 | * registers (Win32) during return.
|
---|
265 | */
|
---|
266 | typedef struct reg_pack_test_type_s {int x, y;} reg_pack_test_type;
|
---|
267 | typedef reg_pack_test_type (*reg_pack_test_function_type) (reg_pack_test_type);
|
---|
268 |
|
---|
269 | static int reg_pack_test_callback(void *ptr) {
|
---|
270 | reg_pack_test_function_type f = (reg_pack_test_function_type)ptr;
|
---|
271 | reg_pack_test_type a = {10, 35};
|
---|
272 | reg_pack_test_type r;
|
---|
273 | r = f(a);
|
---|
274 | return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
|
---|
275 | }
|
---|
276 |
|
---|
277 | static int reg_pack_test(void) {
|
---|
278 | const char *src =
|
---|
279 | "typedef struct reg_pack_test_type_s {int x, y;} reg_pack_test_type;"
|
---|
280 | "reg_pack_test_type f(reg_pack_test_type a) {\n"
|
---|
281 | " reg_pack_test_type r = {a.x*5, a.y*3};\n"
|
---|
282 | " return r;\n"
|
---|
283 | "}\n";
|
---|
284 |
|
---|
285 | return run_callback(src, reg_pack_test_callback);
|
---|
286 | }
|
---|
287 |
|
---|
288 | /*
|
---|
289 | * reg_pack_longlong_test: return a small struct which should be packed into
|
---|
290 | * registers (x86-64) during return.
|
---|
291 | */
|
---|
292 | typedef struct reg_pack_longlong_test_type_s {long long x, y;} reg_pack_longlong_test_type;
|
---|
293 | typedef reg_pack_longlong_test_type (*reg_pack_longlong_test_function_type) (reg_pack_longlong_test_type);
|
---|
294 |
|
---|
295 | static int reg_pack_longlong_test_callback(void *ptr) {
|
---|
296 | reg_pack_longlong_test_function_type f = (reg_pack_longlong_test_function_type)ptr;
|
---|
297 | reg_pack_longlong_test_type a = {10, 35};
|
---|
298 | reg_pack_longlong_test_type r;
|
---|
299 | r = f(a);
|
---|
300 | return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
|
---|
301 | }
|
---|
302 |
|
---|
303 | static int reg_pack_longlong_test(void) {
|
---|
304 | const char *src =
|
---|
305 | "typedef struct reg_pack_longlong_test_type_s {long long x, y;} reg_pack_longlong_test_type;"
|
---|
306 | "reg_pack_longlong_test_type f(reg_pack_longlong_test_type a) {\n"
|
---|
307 | " reg_pack_longlong_test_type r = {a.x*5, a.y*3};\n"
|
---|
308 | " return r;\n"
|
---|
309 | "}\n";
|
---|
310 |
|
---|
311 | return run_callback(src, reg_pack_longlong_test_callback);
|
---|
312 | }
|
---|
313 |
|
---|
314 | /*
|
---|
315 | * ret_6plus2longlong_test:
|
---|
316 | *
|
---|
317 | * This catches a corner case in the x86_64 ABI code: the first 5
|
---|
318 | * arguments fit into registers, the 6th doesn't, but the 7th argument
|
---|
319 | * fits into the 6th argument integer register, %r9.
|
---|
320 | *
|
---|
321 | * Note that the purpose of the 10th argument is to avoid a situation
|
---|
322 | * in which gcc would accidentally put the longlong at the right
|
---|
323 | * address, thus causing a success message even though TCC actually
|
---|
324 | * generated incorrect code.
|
---|
325 | */
|
---|
326 | typedef reg_pack_longlong_test_type (*ret_6plus2longlong_test_function_type) (long long, long long, long long, long long, long long, reg_pack_longlong_test_type, long long, long long);
|
---|
327 |
|
---|
328 | static int ret_6plus2longlong_test_callback(void *ptr) {
|
---|
329 | ret_6plus2longlong_test_function_type f = (ret_6plus2longlong_test_function_type)ptr;
|
---|
330 | reg_pack_longlong_test_type a = {10, 35};
|
---|
331 | reg_pack_longlong_test_type r;
|
---|
332 | r = f(0, 0, 0, 0, 0, a, 37, 38);
|
---|
333 | return ((r.x == 37) && (r.y == 37)) ? 0 : -1;
|
---|
334 | }
|
---|
335 |
|
---|
336 | static int ret_6plus2longlong_test(void) {
|
---|
337 | const char *src =
|
---|
338 | "typedef struct reg_pack_longlong_test_type_s {long long x, y;} reg_pack_longlong_test_type;"
|
---|
339 | "reg_pack_longlong_test_type f(long long x1, long long x2, long long x3, long long x4, long long x5, reg_pack_longlong_test_type a, long long x8, long long x9) {\n"
|
---|
340 | " reg_pack_longlong_test_type r = { x8, x8 };\n"
|
---|
341 | " return r;\n"
|
---|
342 | "}\n";
|
---|
343 |
|
---|
344 | return run_callback(src, ret_6plus2longlong_test_callback);
|
---|
345 | }
|
---|
346 |
|
---|
347 | /*
|
---|
348 | * sret_test: Create a struct large enough to be returned via sret
|
---|
349 | * (hidden pointer as first function argument)
|
---|
350 | */
|
---|
351 | typedef struct sret_test_type_s {long long a, b, c;} sret_test_type;
|
---|
352 | typedef sret_test_type (*sret_test_function_type) (sret_test_type);
|
---|
353 |
|
---|
354 | static int sret_test_callback(void *ptr) {
|
---|
355 | sret_test_function_type f = (sret_test_function_type)(ptr);
|
---|
356 | sret_test_type x = {5436LL, 658277698LL, 43878957LL};
|
---|
357 | sret_test_type r = f(x);
|
---|
358 | return ((r.a==x.a*35)&&(r.b==x.b*19)&&(r.c==x.c*21)) ? 0 : -1;
|
---|
359 | }
|
---|
360 |
|
---|
361 | static int sret_test(void) {
|
---|
362 | const char *src =
|
---|
363 | "typedef struct sret_test_type_s {long long a, b, c;} sret_test_type;\n"
|
---|
364 | "sret_test_type f(sret_test_type x) {\n"
|
---|
365 | " sret_test_type r = {x.a*35, x.b*19, x.c*21};\n"
|
---|
366 | " return r;\n"
|
---|
367 | "}\n";
|
---|
368 |
|
---|
369 | return run_callback(src, sret_test_callback);
|
---|
370 | }
|
---|
371 |
|
---|
372 | /*
|
---|
373 | * one_member_union_test:
|
---|
374 | *
|
---|
375 | * In the x86-64 ABI a union should always be passed on the stack. However
|
---|
376 | * it appears that a single member union is treated by GCC as its member.
|
---|
377 | */
|
---|
378 | typedef union one_member_union_test_type_u {int x;} one_member_union_test_type;
|
---|
379 | typedef one_member_union_test_type (*one_member_union_test_function_type) (one_member_union_test_type);
|
---|
380 |
|
---|
381 | static int one_member_union_test_callback(void *ptr) {
|
---|
382 | one_member_union_test_function_type f = (one_member_union_test_function_type)ptr;
|
---|
383 | one_member_union_test_type a, b;
|
---|
384 | a.x = 34;
|
---|
385 | b = f(a);
|
---|
386 | return (b.x == a.x*2) ? 0 : -1;
|
---|
387 | }
|
---|
388 |
|
---|
389 | static int one_member_union_test(void) {
|
---|
390 | const char *src =
|
---|
391 | "typedef union one_member_union_test_type_u {int x;} one_member_union_test_type;\n"
|
---|
392 | "one_member_union_test_type f(one_member_union_test_type a) {\n"
|
---|
393 | " one_member_union_test_type b;\n"
|
---|
394 | " b.x = a.x * 2;\n"
|
---|
395 | " return b;\n"
|
---|
396 | "}\n";
|
---|
397 | return run_callback(src, one_member_union_test_callback);
|
---|
398 | }
|
---|
399 |
|
---|
400 | /*
|
---|
401 | * two_member_union_test:
|
---|
402 | *
|
---|
403 | * In the x86-64 ABI a union should always be passed on the stack.
|
---|
404 | */
|
---|
405 | typedef union two_member_union_test_type_u {int x; long y;} two_member_union_test_type;
|
---|
406 | typedef two_member_union_test_type (*two_member_union_test_function_type) (two_member_union_test_type);
|
---|
407 |
|
---|
408 | static int two_member_union_test_callback(void *ptr) {
|
---|
409 | two_member_union_test_function_type f = (two_member_union_test_function_type)ptr;
|
---|
410 | two_member_union_test_type a, b;
|
---|
411 | a.x = 34;
|
---|
412 | b = f(a);
|
---|
413 | return (b.x == a.x*2) ? 0 : -1;
|
---|
414 | }
|
---|
415 |
|
---|
416 | static int two_member_union_test(void) {
|
---|
417 | const char *src =
|
---|
418 | "typedef union two_member_union_test_type_u {int x; long y;} two_member_union_test_type;\n"
|
---|
419 | "two_member_union_test_type f(two_member_union_test_type a) {\n"
|
---|
420 | " two_member_union_test_type b;\n"
|
---|
421 | " b.x = a.x * 2;\n"
|
---|
422 | " return b;\n"
|
---|
423 | "}\n";
|
---|
424 | return run_callback(src, two_member_union_test_callback);
|
---|
425 | }
|
---|
426 |
|
---|
427 | /*
|
---|
428 | * Win64 calling convention test.
|
---|
429 | */
|
---|
430 |
|
---|
431 | typedef struct many_struct_test_type_s {long long a, b, c;} many_struct_test_type;
|
---|
432 | typedef many_struct_test_type (*many_struct_test_function_type) (many_struct_test_type,many_struct_test_type,many_struct_test_type,many_struct_test_type,many_struct_test_type,many_struct_test_type);
|
---|
433 |
|
---|
434 | static int many_struct_test_callback(void *ptr) {
|
---|
435 | many_struct_test_function_type f = (many_struct_test_function_type)ptr;
|
---|
436 | many_struct_test_type v = {1, 2, 3};
|
---|
437 | many_struct_test_type r = f(v,v,v,v,v,v);
|
---|
438 | return ((r.a == 6) && (r.b == 12) && (r.c == 18))?0:-1;
|
---|
439 | }
|
---|
440 |
|
---|
441 | static int many_struct_test(void) {
|
---|
442 | const char *src =
|
---|
443 | "typedef struct many_struct_test_type_s {long long a, b, c;} many_struct_test_type;\n"
|
---|
444 | "many_struct_test_type f(many_struct_test_type x1, many_struct_test_type x2, many_struct_test_type x3, many_struct_test_type x4, many_struct_test_type x5, many_struct_test_type x6) {\n"
|
---|
445 | " many_struct_test_type y;\n"
|
---|
446 | " y.a = x1.a + x2.a + x3.a + x4.a + x5.a + x6.a;\n"
|
---|
447 | " y.b = x1.b + x2.b + x3.b + x4.b + x5.b + x6.b;\n"
|
---|
448 | " y.c = x1.c + x2.c + x3.c + x4.c + x5.c + x6.c;\n"
|
---|
449 | " return y;\n"
|
---|
450 | "}\n";
|
---|
451 | return run_callback(src, many_struct_test_callback);
|
---|
452 | }
|
---|
453 |
|
---|
454 | /*
|
---|
455 | * Win64 calling convention test.
|
---|
456 | */
|
---|
457 |
|
---|
458 | typedef struct many_struct_test_2_type_s {int a, b;} many_struct_test_2_type;
|
---|
459 | typedef many_struct_test_2_type (*many_struct_test_2_function_type) (many_struct_test_2_type,many_struct_test_2_type,many_struct_test_2_type,many_struct_test_2_type,many_struct_test_2_type,many_struct_test_2_type);
|
---|
460 |
|
---|
461 | static int many_struct_test_2_callback(void *ptr) {
|
---|
462 | many_struct_test_2_function_type f = (many_struct_test_2_function_type)ptr;
|
---|
463 | many_struct_test_2_type v = {1,2};
|
---|
464 | many_struct_test_2_type r = f(v,v,v,v,v,v);
|
---|
465 | return ((r.a == 6) && (r.b == 12))?0:-1;
|
---|
466 | }
|
---|
467 |
|
---|
468 | static int many_struct_test_2(void) {
|
---|
469 | const char *src =
|
---|
470 | "typedef struct many_struct_test_2_type_s {int a, b;} many_struct_test_2_type;\n"
|
---|
471 | "many_struct_test_2_type f(many_struct_test_2_type x1, many_struct_test_2_type x2, many_struct_test_2_type x3, many_struct_test_2_type x4, many_struct_test_2_type x5, many_struct_test_2_type x6) {\n"
|
---|
472 | " many_struct_test_2_type y;\n"
|
---|
473 | " y.a = x1.a + x2.a + x3.a + x4.a + x5.a + x6.a;\n"
|
---|
474 | " y.b = x1.b + x2.b + x3.b + x4.b + x5.b + x6.b;\n"
|
---|
475 | " return y;\n"
|
---|
476 | "}\n";
|
---|
477 | return run_callback(src, many_struct_test_2_callback);
|
---|
478 | }
|
---|
479 |
|
---|
480 | /*
|
---|
481 | * Win64 calling convention test.
|
---|
482 | */
|
---|
483 |
|
---|
484 | typedef struct many_struct_test_3_type_s {int a, b;} many_struct_test_3_type;
|
---|
485 | typedef many_struct_test_3_type (*many_struct_test_3_function_type) (many_struct_test_3_type,many_struct_test_3_type,many_struct_test_3_type,many_struct_test_3_type,many_struct_test_3_type,many_struct_test_3_type, ...);
|
---|
486 | typedef struct many_struct_test_3_struct_type { many_struct_test_3_function_type f; many_struct_test_3_function_type *f2; } many_struct_test_3_struct_type;
|
---|
487 |
|
---|
488 | static void many_struct_test_3_dummy(double d, ...)
|
---|
489 | {
|
---|
490 | volatile double x = d;
|
---|
491 | }
|
---|
492 |
|
---|
493 | static int many_struct_test_3_callback(void *ptr) {
|
---|
494 | many_struct_test_3_struct_type s = { ptr, };
|
---|
495 | many_struct_test_3_struct_type *s2 = &s;
|
---|
496 | s2->f2 = &s2->f;
|
---|
497 | many_struct_test_3_dummy(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, &s2);
|
---|
498 | many_struct_test_3_function_type f = *(s2->f2);
|
---|
499 | many_struct_test_3_type v = {1,2};
|
---|
500 | many_struct_test_3_type r = (*((s2->f2=&f)+0))(v,v,v,v,v,v,1.0);
|
---|
501 | return ((r.a == 6) && (r.b == 12))?0:-1;
|
---|
502 | }
|
---|
503 |
|
---|
504 | static int many_struct_test_3(void) {
|
---|
505 | const char *src =
|
---|
506 | "typedef struct many_struct_test_3_type_s {int a, b;} many_struct_test_3_type;\n"
|
---|
507 | "many_struct_test_3_type f(many_struct_test_3_type x1, many_struct_test_3_type x2, many_struct_test_3_type x3, many_struct_test_3_type x4, many_struct_test_3_type x5, many_struct_test_3_type x6, ...) {\n"
|
---|
508 | " many_struct_test_3_type y;\n"
|
---|
509 | " y.a = x1.a + x2.a + x3.a + x4.a + x5.a + x6.a;\n"
|
---|
510 | " y.b = x1.b + x2.b + x3.b + x4.b + x5.b + x6.b;\n"
|
---|
511 | " return y;\n"
|
---|
512 | "}\n";
|
---|
513 | return run_callback(src, many_struct_test_3_callback);
|
---|
514 | }
|
---|
515 |
|
---|
516 | /*
|
---|
517 | * stdarg_test: Test variable argument list ABI
|
---|
518 | */
|
---|
519 |
|
---|
520 | typedef struct {long long a, b, c;} stdarg_test_struct_type;
|
---|
521 | typedef void (*stdarg_test_function_type) (int,int,int,...);
|
---|
522 |
|
---|
523 | static int stdarg_test_callback(void *ptr) {
|
---|
524 | stdarg_test_function_type f = (stdarg_test_function_type)ptr;
|
---|
525 | int x;
|
---|
526 | double y;
|
---|
527 | stdarg_test_struct_type z = {1, 2, 3}, w;
|
---|
528 | f(10, 10, 5,
|
---|
529 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, &x,
|
---|
530 | 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, &y,
|
---|
531 | z, z, z, z, z, &w);
|
---|
532 | return ((x == 55) && (y == 55) && (w.a == 5) && (w.b == 10) && (w.c == 15)) ? 0 : -1;
|
---|
533 | }
|
---|
534 |
|
---|
535 | static int stdarg_test(void) {
|
---|
536 | const char *src =
|
---|
537 | "#include <stdarg.h>\n"
|
---|
538 | "typedef struct {long long a, b, c;} stdarg_test_struct_type;\n"
|
---|
539 | "void f(int n_int, int n_float, int n_struct, ...) {\n"
|
---|
540 | " int i, ti = 0;\n"
|
---|
541 | " double td = 0.0;\n"
|
---|
542 | " stdarg_test_struct_type ts = {0,0,0}, tmp;\n"
|
---|
543 | " va_list ap;\n"
|
---|
544 | " va_start(ap, n_struct);\n"
|
---|
545 | " for (i = 0, ti = 0; i < n_int; ++i)\n"
|
---|
546 | " ti += va_arg(ap, int);\n"
|
---|
547 | " *va_arg(ap, int*) = ti;\n"
|
---|
548 | " for (i = 0, td = 0; i < n_float; ++i)\n"
|
---|
549 | " td += va_arg(ap, double);\n"
|
---|
550 | " *va_arg(ap, double*) = td;\n"
|
---|
551 | " for (i = 0; i < n_struct; ++i) {\n"
|
---|
552 | " tmp = va_arg(ap, stdarg_test_struct_type);\n"
|
---|
553 | " ts.a += tmp.a; ts.b += tmp.b; ts.c += tmp.c;"
|
---|
554 | " }\n"
|
---|
555 | " *va_arg(ap, stdarg_test_struct_type*) = ts;\n"
|
---|
556 | " va_end(ap);"
|
---|
557 | "}\n";
|
---|
558 | return run_callback(src, stdarg_test_callback);
|
---|
559 | }
|
---|
560 |
|
---|
561 | typedef struct {long long a, b;} stdarg_many_test_struct_type;
|
---|
562 | typedef void (*stdarg_many_test_function_type) (int, int, int, int, int,
|
---|
563 | stdarg_many_test_struct_type,
|
---|
564 | int, int, ...);
|
---|
565 |
|
---|
566 | static int stdarg_many_test_callback(void *ptr)
|
---|
567 | {
|
---|
568 | stdarg_many_test_function_type f = (stdarg_many_test_function_type)ptr;
|
---|
569 | int x;
|
---|
570 | stdarg_many_test_struct_type l = {10, 11};
|
---|
571 | f(1, 2, 3, 4, 5, l, 6, 7, &x, 44);
|
---|
572 | return x == 44 ? 0 : -1;
|
---|
573 | }
|
---|
574 |
|
---|
575 | static int stdarg_many_test(void)
|
---|
576 | {
|
---|
577 | const char *src =
|
---|
578 | "#include <stdarg.h>\n"
|
---|
579 | "typedef struct {long long a, b;} stdarg_many_test_struct_type;\n"
|
---|
580 | "void f (int a, int b, int c, int d, int e, stdarg_many_test_struct_type l, int f, int g, ...){\n"
|
---|
581 | " va_list ap;\n"
|
---|
582 | " int *p;\n"
|
---|
583 | " va_start (ap, g);\n"
|
---|
584 | " p = va_arg(ap, int*);\n"
|
---|
585 | " *p = va_arg(ap, int);\n"
|
---|
586 | " va_end (ap);\n"
|
---|
587 | "}\n";
|
---|
588 | return run_callback(src, stdarg_many_test_callback);
|
---|
589 | }
|
---|
590 |
|
---|
591 | /*
|
---|
592 | * Test Win32 stdarg handling, since the calling convention will pass a pointer
|
---|
593 | * to the struct and the stdarg pointer must point to that pointer initially.
|
---|
594 | */
|
---|
595 |
|
---|
596 | typedef struct {long long a, b, c;} stdarg_struct_test_struct_type;
|
---|
597 | typedef int (*stdarg_struct_test_function_type) (stdarg_struct_test_struct_type a, ...);
|
---|
598 |
|
---|
599 | static int stdarg_struct_test_callback(void *ptr) {
|
---|
600 | stdarg_struct_test_function_type f = (stdarg_struct_test_function_type)ptr;
|
---|
601 | stdarg_struct_test_struct_type v = {10, 35, 99};
|
---|
602 | int x = f(v, 234);
|
---|
603 | return (x == 378) ? 0 : -1;
|
---|
604 | }
|
---|
605 |
|
---|
606 | static int stdarg_struct_test(void) {
|
---|
607 | const char *src =
|
---|
608 | "#include <stdarg.h>\n"
|
---|
609 | "typedef struct {long long a, b, c;} stdarg_struct_test_struct_type;\n"
|
---|
610 | "int f(stdarg_struct_test_struct_type a, ...) {\n"
|
---|
611 | " va_list ap;\n"
|
---|
612 | " va_start(ap, a);\n"
|
---|
613 | " int z = va_arg(ap, int);\n"
|
---|
614 | " va_end(ap);\n"
|
---|
615 | " return z + a.a + a.b + a.c;\n"
|
---|
616 | "}\n";
|
---|
617 | return run_callback(src, stdarg_struct_test_callback);
|
---|
618 | }
|
---|
619 |
|
---|
620 | /* Test that x86-64 arranges the stack correctly for arguments with alignment >8 bytes */
|
---|
621 |
|
---|
622 | typedef LONG_DOUBLE (*arg_align_test_callback_type) (LONG_DOUBLE,int,LONG_DOUBLE,int,LONG_DOUBLE);
|
---|
623 |
|
---|
624 | static int arg_align_test_callback(void *ptr) {
|
---|
625 | arg_align_test_callback_type f = (arg_align_test_callback_type)ptr;
|
---|
626 | long double x = f(12, 0, 25, 0, 37);
|
---|
627 | return (x == 74) ? 0 : -1;
|
---|
628 | }
|
---|
629 |
|
---|
630 | static int arg_align_test(void) {
|
---|
631 | const char *src =
|
---|
632 | "long double f(long double a, int b, long double c, int d, long double e) {\n"
|
---|
633 | " return a + c + e;\n"
|
---|
634 | "}\n";
|
---|
635 | return run_callback(src, arg_align_test_callback);
|
---|
636 | }
|
---|
637 |
|
---|
638 | #define RUN_TEST(t) \
|
---|
639 | if (!testname || (strcmp(#t, testname) == 0)) { \
|
---|
640 | fputs(#t "... ", stdout); \
|
---|
641 | fflush(stdout); \
|
---|
642 | if (t() == 0) { \
|
---|
643 | fputs("success\n", stdout); \
|
---|
644 | } else { \
|
---|
645 | fputs("failure\n", stdout); \
|
---|
646 | retval = EXIT_FAILURE; \
|
---|
647 | } \
|
---|
648 | }
|
---|
649 |
|
---|
650 | int main(int argc, char **argv) {
|
---|
651 | int i;
|
---|
652 | const char *testname = NULL;
|
---|
653 | int retval = EXIT_SUCCESS;
|
---|
654 |
|
---|
655 | /* if tcclib.h and libtcc1.a are not installed, where can we find them */
|
---|
656 | for (i = 1; i < argc; ++i) {
|
---|
657 | if (!memcmp(argv[i], "run_test=", 9))
|
---|
658 | testname = argv[i] + 9;
|
---|
659 | }
|
---|
660 |
|
---|
661 | g_argv = argv, g_argc = argc;
|
---|
662 |
|
---|
663 | RUN_TEST(ret_int_test);
|
---|
664 | RUN_TEST(ret_longlong_test);
|
---|
665 | RUN_TEST(ret_float_test);
|
---|
666 | RUN_TEST(ret_double_test);
|
---|
667 | RUN_TEST(ret_longdouble_test);
|
---|
668 | RUN_TEST(ret_2float_test);
|
---|
669 | RUN_TEST(ret_2double_test);
|
---|
670 | RUN_TEST(ret_8plus2double_test);
|
---|
671 | RUN_TEST(ret_6plus2longlong_test);
|
---|
672 | #if !defined __x86_64__ || defined _WIN32
|
---|
673 | /* currently broken on x86_64 linux */
|
---|
674 | RUN_TEST(ret_mixed_test);
|
---|
675 | RUN_TEST(ret_mixed2_test);
|
---|
676 | #endif
|
---|
677 | RUN_TEST(ret_mixed3_test);
|
---|
678 | RUN_TEST(reg_pack_test);
|
---|
679 | RUN_TEST(reg_pack_longlong_test);
|
---|
680 | RUN_TEST(sret_test);
|
---|
681 | RUN_TEST(one_member_union_test);
|
---|
682 | RUN_TEST(two_member_union_test);
|
---|
683 | RUN_TEST(many_struct_test);
|
---|
684 | RUN_TEST(many_struct_test_2);
|
---|
685 | RUN_TEST(many_struct_test_3);
|
---|
686 | RUN_TEST(stdarg_test);
|
---|
687 | RUN_TEST(stdarg_many_test);
|
---|
688 | RUN_TEST(stdarg_struct_test);
|
---|
689 | RUN_TEST(arg_align_test);
|
---|
690 | return retval;
|
---|
691 | }
|
---|