History

64-bit tests now pass (well, nearly).

tcctest1-3 fail, but this appears to be due to bugs in GCC rather than TCC (from manual inspection of the output).

James Lyon committed 13 years ago

Commit 5c35ba61 parent 8a81f9e8 files · +295 −142Browse files

Unified · Split

8 files
  1. CMakeLists.txt +16 −12
  2. config.h.in +0 −11
  3. include/stdarg.h +3 −3
  4. tccgen.c +26 −2
  5. tcctok.h +4 −0
  6. tests/CMakeLists.txt +2 −2
  7. tests/abitest.c +101 −6
  8. x86_64-gen.c +143 −106
CMakeLists.txt+16−12
@@ -46,32 +46,36 @@ set(I386_SOURCES i386-gen.c i386-asm.c i386-asm.h i386-tok.h) · 45 unmodified lines
46set(X86_64_SOURCES x86_64-gen.c i386-asm.c x86_64-asm.h)46set(X86_64_SOURCES x86_64-gen.c i386-asm.c x86_64-asm.h)
47 47
48if(TCC_TARGET STREQUAL "Win32")48if(TCC_TARGET STREQUAL "Win32")
49 set(TCC_TARGET_I386 ON)49 set(TCC_TARGET_FLAGS -DTCC_TARGET_I386 -DTCC_TARGET_PE)
50 set(TCC_TARGET_PE ON)
51 set(LIBTCC_TARGET_SOURCES ${I386_SOURCES} tccpe.c)50 set(LIBTCC_TARGET_SOURCES ${I386_SOURCES} tccpe.c)
52elseif(TCC_TARGET STREQUAL "Win64")51elseif(TCC_TARGET STREQUAL "Win64")
53 set(TCC_TARGET_PE ON)52 set(TCC_TARGET_FLAGS -DTCC_TARGET_X86_64 -DTCC_TARGET_PE)
54 set(TCC_TARGET_X86_64 ON)
55 set(LIBTCC_TARGET_SOURCES ${X86_64_SOURCES} tccpe.c)53 set(LIBTCC_TARGET_SOURCES ${X86_64_SOURCES} tccpe.c)
56elseif(TCC_TARGET STREQUAL "WinCE")54elseif(TCC_TARGET STREQUAL "WinCE")
57 set(TCC_TARGET_ARM ON)55 set(TCC_TARGET_FLAGS -DTCC_TARGET_ARM
56 -DTCC_ARM_VERSION=${TCC_ARM_VERSION})
58 set(LIBTCC_TARGET_SOURCES arm-gen.c tccpe.c)57 set(LIBTCC_TARGET_SOURCES arm-gen.c tccpe.c)
59elseif(TCC_TARGET STREQUAL "i386")58elseif(TCC_TARGET STREQUAL "i386")
60 set(TCC_TARGET_I386 ON)59 set(TCC_TARGET_FLAGS -DTCC_TARGET_I386)
61 set(LIBTCC_TARGET_SOURCES ${I386_SOURCES})60 set(LIBTCC_TARGET_SOURCES ${I386_SOURCES})
62elseif(TCC_TARGET STREQUAL "x86-64")61elseif(TCC_TARGET STREQUAL "x86-64")
63 set(TCC_TARGET_X86_64 ON)62 set(TCC_TARGET_FLAGS -DTCC_TARGET_X86_64)
64 set(LIBTCC_TARGET_SOURCES ${X86_64_SOURCES})63 set(LIBTCC_TARGET_SOURCES ${X86_64_SOURCES})
65elseif(TCC_TARGET STREQUAL "ARM")64elseif(TCC_TARGET STREQUAL "ARM")
66 set(TCC_TARGET_ARM ON)65 set(TCC_TARGET_FLAGS -DTCC_TARGET_ARM
66 -DTCC_ARM_VERSION=${TCC_ARM_VERSION}
67 -DTCC_ARM_EABI=${TCC_ARM_EABI}
68 -DTCC_ARM_VFP=${TCC_ARM_VFP}
69 -DTCC_ARM_HARDFLOAT=${TCC_ARM_HARDFLOAT})
67 set(LIBTCC_TARGET_SOURCES arm-gen.c)70 set(LIBTCC_TARGET_SOURCES arm-gen.c)
68elseif(TCC_TARGET STREQUAL "C67")71elseif(TCC_TARGET STREQUAL "C67")
69 set(TCC_TARGET_C67 ON)72 set(TCC_TARGET_FLAGS -DTCC_TARGET_C67)
70 set(LIBTCC_TARGET_SOURCES c67-gen.c tcccoff.c)73 set(LIBTCC_TARGET_SOURCES c67-gen.c tcccoff.c)
71else()74else()
72 message(FATAL_ERROR "Unrecognised target in TCC_TARGET, must be one of ${TCC_TARGET_LIST}")75 message(FATAL_ERROR "Unrecognised target in TCC_TARGET, must be one of ${TCC_TARGET_LIST}")
73endif()76endif()
74 77
78add_definitions(${TCC_TARGET_FLAGS})
75file(STRINGS "VERSION" TCC_VERSION)79file(STRINGS "VERSION" TCC_VERSION)
76list(GET TCC_VERSION 0 TCC_VERSION)80list(GET TCC_VERSION 0 TCC_VERSION)
77include_directories(${CMAKE_BINARY_DIR})81include_directories(${CMAKE_BINARY_DIR})
@@ -86,7 +90,7 @@ set_target_properties(libtcc PROPERTIES PREFIX "") · 8 unmodified lines
86 90
87add_executable(tcc tcc.c)91add_executable(tcc tcc.c)
88target_link_libraries(tcc libtcc)92target_link_libraries(tcc libtcc)
89set(TCC_CFLAGS -I${CMAKE_SOURCE_DIR}/include)93set(TCC_CFLAGS -I${CMAKE_SOURCE_DIR}/include ${CMAKE_C_FLAGS})
90if(TCC_TARGET MATCHES "^Win")94if(TCC_TARGET MATCHES "^Win")
91 set(TCC_CFLAGS ${TCC_CFLAGS} -I${CMAKE_SOURCE_DIR}/win32/include)95 set(TCC_CFLAGS ${TCC_CFLAGS} -I${CMAKE_SOURCE_DIR}/win32/include)
92endif()96endif()
@@ -108,7 +112,7 @@ elseif(TCC_TARGET STREQUAL "x86-64") · 15 unmodified lines
108endif()112endif()
109 113
110if (TCC_TARGET MATCHES "^Win")114if (TCC_TARGET MATCHES "^Win")
111 set(XCC tcc ${TCC_CFLAGS} -B${CMAKE_SOURCE_DIR}/win32)115 set(XCC tcc ${TCC_CFLAGS} ${TCC_TARGET_FLAGS} -B${CMAKE_SOURCE_DIR}/win32)
112 set(XAR tiny_libmaker${CMAKE_EXECUTABLE_SUFFIX})116 set(XAR tiny_libmaker${CMAKE_EXECUTABLE_SUFFIX})
113 set(XDEPENDS tiny_libmaker)117 set(XDEPENDS tiny_libmaker)
114endif()118endif()
@@ -119,7 +123,7 @@ if(LIBTCC1_SOURCES) · 4 unmodified lines
119 string(REGEX MATCH "[^/]+$" LIBTCC1_O ${LIBTCC1_C})123 string(REGEX MATCH "[^/]+$" LIBTCC1_O ${LIBTCC1_C})
120 string(REGEX MATCH "^[^.]+" LIBTCC1_O ${LIBTCC1_O})124 string(REGEX MATCH "^[^.]+" LIBTCC1_O ${LIBTCC1_O})
121 set(LIBTCC1_O ${LIBTCC1_O}.o)125 set(LIBTCC1_O ${LIBTCC1_O}.o)
122 add_custom_command(OUTPUT ${LIBTCC1_O} COMMAND ${XCC} -c ${CMAKE_SOURCE_DIR}/${LIBTCC1_C} -o ${LIBTCC1_O})126 add_custom_command(OUTPUT ${LIBTCC1_O} COMMAND ${XCC} -c ${CMAKE_SOURCE_DIR}/${LIBTCC1_C} -o ${LIBTCC1_O} DEPENDS ${CMAKE_SOURCE_DIR}/${LIBTCC1_C})
123 list(APPEND LIBTCC1_OBJECTS ${LIBTCC1_O})127 list(APPEND LIBTCC1_OBJECTS ${LIBTCC1_O})
124 endforeach()128 endforeach()
125 add_custom_command(OUTPUT libtcc1.a COMMAND ${XAR} libtcc1.a ${LIBTCC1_OBJECTS} DEPENDS ${LIBTCC1_OBJECTS} ${XDEPENDS})129 add_custom_command(OUTPUT libtcc1.a COMMAND ${XAR} libtcc1.a ${LIBTCC1_OBJECTS} DEPENDS ${LIBTCC1_OBJECTS} ${XDEPENDS})
config.h.in+0−11
@@ -3,14 +3,3 @@ · 2 unmodified lines
3 3
4#cmakedefine CONFIG_WIN324#cmakedefine CONFIG_WIN32
5#cmakedefine CONFIG_WIN645#cmakedefine CONFIG_WIN64
6
7#cmakedefine TCC_TARGET_I386
8#cmakedefine TCC_TARGET_X86_64
9#cmakedefine TCC_TARGET_ARM
10#cmakedefine TCC_TARGET_C67
11
12#cmakedefine TCC_TARGET_PE
13#define TCC_ARM_VERSION ${TCC_ARM_VERSION}
14#cmakedefine TCC_ARM_VFP
15#cmakedefine TCC_ARM_EABI
16#cmakedefine TCC_ARM_HARDFLOAT
include/stdarg.h+3−3
@@ -19,9 +19,9 @@ void __va_end(va_list ap); · 18 unmodified lines
19 19
20#else /* _WIN64 */20#else /* _WIN64 */
21typedef char *va_list;21typedef char *va_list;
22#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+7)&~7)22#define va_start(ap,last) __builtin_va_start(ap,last)
23#define va_arg(ap,type) (ap += (sizeof(type)+7)&~7, *(type *)(ap - ((sizeof(type)+7)&~7)))23#define va_arg(ap,type) (ap += 8, sizeof(type)<=8 ? *(type*)ap : **(type**)ap)
24#define va_copy(dest, src) (dest) = (src)24#define va_copy(dest, src) ((dest) = (src))
25#define va_end(ap)25#define va_end(ap)
26#endif26#endif
27 27
tccgen.c+26−2
@@ -851,7 +851,13 @@ ST_FUNC int gv(int rc) · 850 unmodified lines
851 t = vtop->type.t;851 t = vtop->type.t;
852 t1 = t;852 t1 = t;
853 /* compute memory access type */853 /* compute memory access type */
854 if (vtop->r & VT_LVAL_BYTE)854 if (vtop->r & VT_REF)
855#ifdef TCC_TARGET_X86_64
856 t = VT_PTR;
857#else
858 t = VT_INT;
859#endif
860 else if (vtop->r & VT_LVAL_BYTE)
855 t = VT_BYTE;861 t = VT_BYTE;
856 else if (vtop->r & VT_LVAL_SHORT)862 else if (vtop->r & VT_LVAL_SHORT)
857 t = VT_SHORT;863 t = VT_SHORT;
@@ -3712,7 +3718,24 @@ ST_FUNC void unary(void) · 2854 unmodified lines
3712 }3718 }
3713 }3719 }
3714 break;3720 break;
3715#if defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_PE)3721#ifdef TCC_TARGET_X86_64
3722#ifdef TCC_TARGET_PE
3723 case TOK_builtin_va_start:
3724 {
3725 next();
3726 skip('(');
3727 expr_eq();
3728 skip(',');
3729 expr_eq();
3730 skip(')');
3731 if ((vtop->r & VT_VALMASK) != VT_LOCAL)
3732 tcc_error("__builtin_va_start expects a local variable");
3733 vtop->r &= ~(VT_LVAL | VT_REF);
3734 vtop->type = char_pointer_type;
3735 vstore();
3736 }
3737 break;
3738#else
3716 case TOK_builtin_va_arg_types:3739 case TOK_builtin_va_arg_types:
3717 {3740 {
3718 CType type;3741 CType type;
@@ -3724,6 +3747,7 @@ ST_FUNC void unary(void) · 5 unmodified lines
3724 vpushi(classify_x86_64_va_arg(&type));3747 vpushi(classify_x86_64_va_arg(&type));
3725 }3748 }
3726 break;3749 break;
3750#endif
3727#endif3751#endif
3728 case TOK_INC:3752 case TOK_INC:
3729 case TOK_DEC:3753 case TOK_DEC:
tcctok.h+4−0
@@ -125,7 +125,11 @@ · 124 unmodified lines
125 DEF(TOK_builtin_constant_p, "__builtin_constant_p")125 DEF(TOK_builtin_constant_p, "__builtin_constant_p")
126 DEF(TOK_builtin_frame_address, "__builtin_frame_address")126 DEF(TOK_builtin_frame_address, "__builtin_frame_address")
127#ifdef TCC_TARGET_X86_64127#ifdef TCC_TARGET_X86_64
128#ifdef TCC_TARGET_PE
129 DEF(TOK_builtin_va_start, "__builtin_va_start")
130#else
128 DEF(TOK_builtin_va_arg_types, "__builtin_va_arg_types")131 DEF(TOK_builtin_va_arg_types, "__builtin_va_arg_types")
132#endif
129#endif133#endif
130 DEF(TOK_REGPARM1, "regparm")134 DEF(TOK_REGPARM1, "regparm")
131 DEF(TOK_REGPARM2, "__regparm__")135 DEF(TOK_REGPARM2, "__regparm__")
tests/CMakeLists.txt+2−2
@@ -6,7 +6,7 @@ add_test(NAME abitest-cc WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND abitest-c · 5 unmodified lines
6 6
7set(ABITEST_TCC abitest-tcc${CMAKE_EXECUTABLE_SUFFIX})7set(ABITEST_TCC abitest-tcc${CMAKE_EXECUTABLE_SUFFIX})
8get_property(LIBTCC_LIB TARGET libtcc PROPERTY LOCATION)8get_property(LIBTCC_LIB TARGET libtcc PROPERTY LOCATION)
9add_custom_command(OUTPUT ${ABITEST_TCC} COMMAND tcc ${TCC_CFLAGS} -I${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/abitest.c ${LIBTCC_LIB} -o ${ABITEST_TCC} DEPENDS abitest.c)9add_custom_command(OUTPUT ${ABITEST_TCC} COMMAND tcc ${TCC_CFLAGS} -g -I${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/abitest.c ${LIBTCC_LIB} -o ${ABITEST_TCC} DEPENDS abitest.c)
10add_custom_target(abitest-tcc-exe ALL DEPENDS ${ABITEST_TCC})10add_custom_target(abitest-tcc-exe ALL DEPENDS ${ABITEST_TCC})
11 11
12add_test(NAME abitest-tcc WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${ABITEST_TCC} lib_path=${CMAKE_BINARY_DIR} include=${CMAKE_SOURCE_DIR}/include)12add_test(NAME abitest-tcc WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${ABITEST_TCC} lib_path=${CMAKE_BINARY_DIR} include=${CMAKE_SOURCE_DIR}/include)
@@ -20,7 +20,7 @@ if(WIN32) · 7 unmodified lines
20 set(TCC_TEST_CFLAGS ${TCC_TEST_CFLAGS} -I${CMAKE_SOURCE_DIR}/win32/include/winapi)20 set(TCC_TEST_CFLAGS ${TCC_TEST_CFLAGS} -I${CMAKE_SOURCE_DIR}/win32/include/winapi)
21endif()21endif()
22set(TCC_TEST_SOURCE ${TCC_TEST_CFLAGS} -run ${CMAKE_CURRENT_SOURCE_DIR}/tcctest.c)22set(TCC_TEST_SOURCE ${TCC_TEST_CFLAGS} -run ${CMAKE_CURRENT_SOURCE_DIR}/tcctest.c)
23set(TCC_TEST_RUN ${TCC_TEST_CFLAGS} -DONE_SOURCE -run ${CMAKE_SOURCE_DIR}/tcc.c)23set(TCC_TEST_RUN ${TCC_TEST_CFLAGS} ${TCC_TARGET_FLAGS} -DONE_SOURCE -run ${CMAKE_SOURCE_DIR}/tcc.c)
24 24
25add_custom_command(OUTPUT tcctest.ref COMMAND tcctest-cc > tcctest.ref)25add_custom_command(OUTPUT tcctest.ref COMMAND tcctest-cc > tcctest.ref)
26add_custom_command(OUTPUT tcctest.1 COMMAND tcc ${TCC_TEST_SOURCE} > tcctest.1)26add_custom_command(OUTPUT tcctest.1 COMMAND tcc ${TCC_TEST_SOURCE} > tcctest.1)
tests/abitest.c+101−6
@@ -262,41 +262,133 @@ static int two_member_union_test(void) { · 261 unmodified lines
262 return run_callback(src, two_member_union_test_callback);262 return run_callback(src, two_member_union_test_callback);
263}263}
264 264
265/*
266 * Win64 calling convetntion test.
267 */
268
269typedef struct many_struct_test_type_s {long long a, b, c;} many_struct_test_type;
270typedef 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);
271
272static int many_struct_test_callback(void *ptr) {
273 many_struct_test_function_type f = (many_struct_test_function_type)ptr;
274 many_struct_test_type v = {1, 2, 3};
275 many_struct_test_type r = f(v,v,v,v,v,v);
276 return ((r.a == 6) && (r.b == 12) && (r.c == 18))?0:-1;
277}
278
279static int many_struct_test(void) {
280 const char *src =
281 "typedef struct many_struct_test_type_s {long long a, b, c;} many_struct_test_type;\n"
282 "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"
283 " many_struct_test_type y;\n"
284 " y.a = x1.a + x2.a + x3.a + x4.a + x5.a + x6.a;\n"
285 " y.b = x1.b + x2.b + x3.b + x4.b + x5.b + x6.b;\n"
286 " y.c = x1.c + x2.c + x3.c + x4.c + x5.c + x6.c;\n"
287 " return y;\n"
288 "}\n";
289 return run_callback(src, many_struct_test_callback);
290}
291
292/*
293 * Win64 calling convention test.
294 */
295
296typedef struct many_struct_test_2_type_s {int a, b;} many_struct_test_2_type;
297typedef 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);
298
299static int many_struct_test_2_callback(void *ptr) {
300 many_struct_test_2_function_type f = (many_struct_test_2_function_type)ptr;
301 many_struct_test_2_type v = {1,2};
302 many_struct_test_2_type r = f(v,v,v,v,v,v);
303 return ((r.a == 6) && (r.b == 12))?0:-1;
304}
305
306static int many_struct_test_2(void) {
307 const char *src =
308 "typedef struct many_struct_test_2_type_s {int a, b;} many_struct_test_2_type;\n"
309 "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"
310 " many_struct_test_2_type y;\n"
311 " y.a = x1.a + x2.a + x3.a + x4.a + x5.a + x6.a;\n"
312 " y.b = x1.b + x2.b + x3.b + x4.b + x5.b + x6.b;\n"
313 " return y;\n"
314 "}\n";
315 return run_callback(src, many_struct_test_2_callback);
316}
317
265/*318/*
266 * stdarg_test: Test variable argument list ABI319 * stdarg_test: Test variable argument list ABI
267 */320 */
268 321
269typedef void (*stdarg_test_function_type) (int,int,...);322typedef struct {long long a, b, c;} stdarg_test_struct_type;
323typedef void (*stdarg_test_function_type) (int,int,int,...);
270 324
271static int stdarg_test_callback(void *ptr) {325static int stdarg_test_callback(void *ptr) {
272 stdarg_test_function_type f = (stdarg_test_function_type)ptr;326 stdarg_test_function_type f = (stdarg_test_function_type)ptr;
273 int x;327 int x;
274 double y;328 double y;
275 f(10, 10,329 stdarg_test_struct_type z = {1, 2, 3}, w;
330 f(10, 10, 5,
276 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, &x,331 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, &x,
277 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, &y);332 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, &y,
278 return ((x == 55) && (y == 55)) ? 0 : -1;333 z, z, z, z, z, &w);
334 return ((x == 55) && (y == 55) && (w.a == 5) && (w.b == 10) && (w.c == 15)) ? 0 : -1;
279}335}
280 336
281static int stdarg_test(void) {337static int stdarg_test(void) {
282 const char *src =338 const char *src =
283 "#include <stdarg.h>\n"339 "#include <stdarg.h>\n"
284 "void f(int n_int, int n_float, ...) {\n"340 "typedef struct {long long a, b, c;} stdarg_test_struct_type;\n"
341 "void f(int n_int, int n_float, int n_struct, ...) {\n"
285 " int i, ti;\n"342 " int i, ti;\n"
286 " double td;\n"343 " double td;\n"
344 " stdarg_test_struct_type ts = {0,0,0}, tmp;\n"
287 " va_list ap;\n"345 " va_list ap;\n"
288 " va_start(ap, n_float);\n"346 " va_start(ap, n_struct);\n"
289 " for (i = 0, ti = 0; i < n_int; ++i)\n"347 " for (i = 0, ti = 0; i < n_int; ++i)\n"
290 " ti += va_arg(ap, int);\n"348 " ti += va_arg(ap, int);\n"
291 " *va_arg(ap, int*) = ti;\n"349 " *va_arg(ap, int*) = ti;\n"
292 " for (i = 0, td = 0; i < n_float; ++i)\n"350 " for (i = 0, td = 0; i < n_float; ++i)\n"
293 " td += va_arg(ap, double);\n"351 " td += va_arg(ap, double);\n"
294 " *va_arg(ap, double*) = td;\n"352 " *va_arg(ap, double*) = td;\n"
353 " for (i = 0; i < n_struct; ++i) {\n"
354 " tmp = va_arg(ap, stdarg_test_struct_type);\n"
355 " ts.a += tmp.a; ts.b += tmp.b; ts.c += tmp.c;"
356 " }\n"
357 " *va_arg(ap, stdarg_test_struct_type*) = ts;\n"
295 " va_end(ap);"358 " va_end(ap);"
296 "}\n";359 "}\n";
297 return run_callback(src, stdarg_test_callback);360 return run_callback(src, stdarg_test_callback);
298}361}
299 362
363/*
364 * Test Win32 stdarg handling, since the calling convention will pass a pointer
365 * to the struct and the stdarg pointer must point to that pointer initially.
366 */
367
368typedef struct {long long a, b, c;} stdarg_struct_test_struct_type;
369typedef int (*stdarg_struct_test_function_type) (stdarg_struct_test_struct_type a, ...);
370
371static int stdarg_struct_test_callback(void *ptr) {
372 stdarg_struct_test_function_type f = (stdarg_struct_test_function_type)ptr;
373 stdarg_struct_test_struct_type v = {10, 35, 99};
374 int x = f(v, 234);
375 return (x == 378) ? 0 : -1;
376}
377
378static int stdarg_struct_test(void) {
379 const char *src =
380 "#include <stdarg.h>\n"
381 "typedef struct {long long a, b, c;} stdarg_struct_test_struct_type;\n"
382 "int f(stdarg_struct_test_struct_type a, ...) {\n"
383 " va_list ap;\n"
384 " va_start(ap, a);\n"
385 " int z = va_arg(ap, int);\n"
386 " va_end(ap);\n"
387 " return z + a.a + a.b + a.c;\n"
388 "}\n";
389 return run_callback(src, stdarg_struct_test_callback);
390}
391
300#define RUN_TEST(t) \392#define RUN_TEST(t) \
301 if (!testname || (strcmp(#t, testname) == 0)) { \393 if (!testname || (strcmp(#t, testname) == 0)) { \
302 fputs(#t "... ", stdout); \394 fputs(#t "... ", stdout); \
@@ -336,6 +428,9 @@ int main(int argc, char **argv) { · 33 unmodified lines
336 RUN_TEST(sret_test);428 RUN_TEST(sret_test);
337 RUN_TEST(one_member_union_test);429 RUN_TEST(one_member_union_test);
338 RUN_TEST(two_member_union_test);430 RUN_TEST(two_member_union_test);
431 RUN_TEST(many_struct_test);
432 RUN_TEST(many_struct_test_2);
339 RUN_TEST(stdarg_test);433 RUN_TEST(stdarg_test);
434 RUN_TEST(stdarg_struct_test);
340 return retval;435 return retval;
341}436}
x86_64-gen.c+143−106
@@ -23,7 +23,7 @@ · 22 unmodified lines
23#ifdef TARGET_DEFS_ONLY23#ifdef TARGET_DEFS_ONLY
24 24
25/* number of available registers */25/* number of available registers */
26#define NB_REGS 2426#define NB_REGS 22
27#define NB_ASM_REGS 827#define NB_ASM_REGS 8
28 28
29/* a register can belong to several classes. The classes must be29/* a register can belong to several classes. The classes must be
@@ -45,8 +45,6 @@ · 15 unmodified lines
45#define RC_XMM3 0x800045#define RC_XMM3 0x8000
46#define RC_XMM4 0x1000046#define RC_XMM4 0x10000
47#define RC_XMM5 0x2000047#define RC_XMM5 0x20000
48#define RC_XMM6 0x40000
49#define RC_XMM7 0x80000
50#define RC_IRET RC_RAX /* function return: integer register */48#define RC_IRET RC_RAX /* function return: integer register */
51#define RC_LRET RC_RDX /* function return: second integer register */49#define RC_LRET RC_RDX /* function return: second integer register */
52#define RC_FRET RC_XMM0 /* function return: float register */50#define RC_FRET RC_XMM0 /* function return: float register */
@@ -142,9 +140,7 @@ ST_DATA const int reg_classes[NB_REGS] = { · 89 unmodified lines
142 /* xmm2 */ RC_FLOAT | RC_XMM2,140 /* xmm2 */ RC_FLOAT | RC_XMM2,
143 /* xmm3 */ RC_FLOAT | RC_XMM3,141 /* xmm3 */ RC_FLOAT | RC_XMM3,
144 /* xmm4 */ RC_FLOAT | RC_XMM4,142 /* xmm4 */ RC_FLOAT | RC_XMM4,
145 /* xmm5 */ RC_FLOAT | RC_XMM5,143 /* xmm5 */ RC_FLOAT | RC_XMM5 /* only up to xmm5: xmm6-15 must be callee saved on Win64 */
146 /* xmm6 */ RC_FLOAT | RC_XMM6,
147 /* xmm7 */ RC_FLOAT | RC_XMM7,
148};144};
149 145
150static unsigned long func_sub_sp_offset;146static unsigned long func_sub_sp_offset;
@@ -484,7 +480,7 @@ void load(int r, SValue *sv) · 333 unmodified lines
484 orex(0,r,0,0);480 orex(0,r,0,0);
485 oad(0xb8 + REG_VALUE(r), t ^ 1); /* mov $0, r */481 oad(0xb8 + REG_VALUE(r), t ^ 1); /* mov $0, r */
486 } else if (v != r) {482 } else if (v != r) {
487 if ((r == TREG_XMM0) || (r == TREG_XMM1)) {483 if ((r >= TREG_XMM0) && (r <= TREG_XMM7)) {
488 if (v == TREG_ST0) {484 if (v == TREG_ST0) {
489 /* gen_cvt_ftof(VT_DOUBLE); */485 /* gen_cvt_ftof(VT_DOUBLE); */
490 o(0xf0245cdd); /* fstpl -0x10(%rsp) */486 o(0xf0245cdd); /* fstpl -0x10(%rsp) */
@@ -493,7 +489,7 @@ void load(int r, SValue *sv) · 2 unmodified lines
493 o(0x44 + REG_VALUE(r)*8); /* %xmmN */489 o(0x44 + REG_VALUE(r)*8); /* %xmmN */
494 o(0xf024);490 o(0xf024);
495 } else {491 } else {
496 assert((v == TREG_XMM0) || (v == TREG_XMM1));492 assert((v >= TREG_XMM0) && (v <= TREG_XMM7));
497 if ((ft & VT_BTYPE) == VT_FLOAT) {493 if ((ft & VT_BTYPE) == VT_FLOAT) {
498 o(0x100ff3);494 o(0x100ff3);
499 } else {495 } else {
@@ -626,10 +622,20 @@ static void gcall_or_jmp(int is_jmp) · 126 unmodified lines
626#ifdef TCC_TARGET_PE622#ifdef TCC_TARGET_PE
627 623
628#define REGN 4624#define REGN 4
629static const uint8_t arg_regs[] = {625static const uint8_t arg_regs[REGN] = {
630 TREG_RCX, TREG_RDX, TREG_R8, TREG_R9626 TREG_RCX, TREG_RDX, TREG_R8, TREG_R9
631};627};
632 628
629/* Prepare arguments in R10 and R11 rather than RCX and RDX
630 because gv() will not ever use these */
631static int arg_prepare_reg(int idx) {
632 if (idx == 0 || idx == 1)
633 /* idx=0: r10, idx=1: r11 */
634 return idx + 10;
635 else
636 return arg_regs[idx];
637}
638
633static int func_scratch;639static int func_scratch;
634 640
635/* Generate function call. The function address is pushed first, then641/* Generate function call. The function address is pushed first, then
@@ -651,26 +657,56 @@ void gen_offs_sp(int b, int r, int d) · 15 unmodified lines
651/* Return 1 if this function returns via an sret pointer, 0 otherwise */657/* Return 1 if this function returns via an sret pointer, 0 otherwise */
652ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) {658ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) {
653 *ret_align = 1; // Never have to re-align return values for x86-64659 *ret_align = 1; // Never have to re-align return values for x86-64
654 return 1;660 int size, align;
661 size = type_size(vt, &align);
662 ret->ref = NULL;
663 if (size > 8) {
664 return 1;
665 } else if (size > 4) {
666 ret->t = VT_LLONG;
667 return 0;
668 } else if (size > 2) {
669 ret->t = VT_INT;
670 return 0;
671 } else if (size > 1) {
672 ret->t = VT_SHORT;
673 return 0;
674 } else {
675 ret->t = VT_BYTE;
676 return 0;
677 }
678}
679
680int gfunc_arg_size(CType *type) {
681 if (type->t & (VT_ARRAY|VT_BITFIELD))
682 return 8;
683 int align;
684 return type_size(type, &align);
655}685}
656 686
657void gfunc_call(int nb_args)687void gfunc_call(int nb_args)
658{688{
659 int size, align, r, args_size, i, d, j, bt, struct_size;689 int size, r, args_size, i, d, bt, struct_size;
660 int nb_reg_args, gen_reg;690 int arg;
661 691
662 nb_reg_args = nb_args;692 args_size = (nb_args < REGN ? REGN : nb_args) * PTR_SIZE;
663 args_size = (nb_reg_args < REGN ? REGN : nb_reg_args) * PTR_SIZE;693 arg = nb_args;
664 694
665 /* for struct arguments, we need to call memcpy and the function695 /* for struct arguments, we need to call memcpy and the function
666 call breaks register passing arguments we are preparing.696 call breaks register passing arguments we are preparing.
667 So, we process arguments which will be passed by stack first. */697 So, we process arguments which will be passed by stack first. */
668 struct_size = args_size;698 struct_size = args_size;
669 for(i = 0; i < nb_args; i++) {699 for(i = 0; i < nb_args; i++) {
700 --arg;
701
670 SValue *sv = &vtop[-i];702 SValue *sv = &vtop[-i];
671 bt = (sv->type.t & VT_BTYPE);703 bt = (sv->type.t & VT_BTYPE);
704 size = gfunc_arg_size(&sv->type);
705
706 if (size <= 8)
707 continue; /* arguments smaller than 8 bytes passed in registers or on stack */
708
672 if (bt == VT_STRUCT) {709 if (bt == VT_STRUCT) {
673 size = type_size(&sv->type, &align);
674 /* align to stack align size */710 /* align to stack align size */
675 size = (size + 15) & ~15;711 size = (size + 15) & ~15;
676 /* generate structure store */712 /* generate structure store */
@@ -683,85 +719,81 @@ void gfunc_call(int nb_args) · 6 unmodified lines
683 vpushv(sv);719 vpushv(sv);
684 vstore();720 vstore();
685 --vtop;721 --vtop;
686
687 } else if (bt == VT_LDOUBLE) {722 } else if (bt == VT_LDOUBLE) {
688
689 gv(RC_ST0);723 gv(RC_ST0);
690 gen_offs_sp(0xdb, 0x107, struct_size);724 gen_offs_sp(0xdb, 0x107, struct_size);
691 struct_size += 16;725 struct_size += 16;
692
693 }726 }
694 }727 }
695 728
696 if (func_scratch < struct_size)729 if (func_scratch < struct_size)
697 func_scratch = struct_size;730 func_scratch = struct_size;
698#if 1731
699 for (i = 0; i < REGN; ++i)732 arg = nb_args;
700 save_reg(arg_regs[i]);
701 save_reg(TREG_RAX);
702#endif
703 gen_reg = nb_reg_args;
704 struct_size = args_size;733 struct_size = args_size;
705 734
706 for(i = 0; i < nb_args; i++) {735 for(i = 0; i < nb_args; i++) {
736 --arg;
707 bt = (vtop->type.t & VT_BTYPE);737 bt = (vtop->type.t & VT_BTYPE);
708 738
709 if (bt == VT_STRUCT || bt == VT_LDOUBLE) {739 size = gfunc_arg_size(&vtop->type);
710 if (bt == VT_LDOUBLE)740 if (size > 8) {
711 size = 16;
712 else
713 size = type_size(&vtop->type, &align);
714 /* align to stack align size */741 /* align to stack align size */
715 size = (size + 15) & ~15;742 size = (size + 15) & ~15;
716 j = --gen_reg;743 if (arg >= REGN) {
717 if (j >= REGN) {744 d = get_reg(RC_INT);
718 d = TREG_RAX;
719 gen_offs_sp(0x8d, d, struct_size);745 gen_offs_sp(0x8d, d, struct_size);
720 gen_offs_sp(0x89, d, j*8);746 gen_offs_sp(0x89, d, arg*8);
721 } else {747 } else {
722 d = arg_regs[j];748 d = arg_prepare_reg(arg);
723 gen_offs_sp(0x8d, d, struct_size);749 gen_offs_sp(0x8d, d, struct_size);
724 }750 }
725 struct_size += size;751 struct_size += size;
726
727 } else if (is_sse_float(vtop->type.t)) {
728 gv(RC_XMM0); /* only one float register */
729 j = --gen_reg;
730 if (j >= REGN) {
731 /* movq %xmm0, j*8(%rsp) */
732 gen_offs_sp(0xd60f66, 0x100, j*8);
733 } else {
734 /* movaps %xmm0, %xmmN */
735 o(0x280f);
736 o(0xc0 + (j << 3));
737 d = arg_regs[j];
738 /* mov %xmm0, %rxx */
739 o(0x66);
740 orex(1,d,0, 0x7e0f);
741 o(0xc0 + REG_VALUE(d));
742 }
743 } else {752 } else {
744 j = --gen_reg;753 if (is_sse_float(vtop->type.t)) {
745 if (j >= REGN) {754 gv(RC_XMM0); /* only use one float register */
746 r = gv(RC_INT);755 if (arg >= REGN) {
747 gen_offs_sp(0x89, r, j*8);756 /* movq %xmm0, j*8(%rsp) */
757 gen_offs_sp(0xd60f66, 0x100, arg*8);
758 } else {
759 /* movaps %xmm0, %xmmN */
760 o(0x280f);
761 o(0xc0 + (arg << 3));
762 d = arg_prepare_reg(arg);
763 /* mov %xmm0, %rxx */
764 o(0x66);
765 orex(1,d,0, 0x7e0f);
766 o(0xc0 + REG_VALUE(d));
767 }
748 } else {768 } else {
749 d = arg_regs[j];769 if (bt == VT_STRUCT) {
750 if (d < NB_REGS) {770 vtop->type.ref = NULL;
751 gv(reg_classes[d] & ~RC_INT);771 vtop->type.t = size > 4 ? VT_LLONG : size > 2 ? VT_INT
772 : size > 1 ? VT_SHORT : VT_BYTE;
773 }
774
775 r = gv(RC_INT);
776 if (arg >= REGN) {
777 gen_offs_sp(0x89, r, arg*8);
752 } else {778 } else {
753 r = gv(RC_INT);779 d = arg_prepare_reg(arg);
754 if (d != r) {780 orex(1,d,r,0x89); /* mov */
755 orex(1,d,r, 0x89);781 o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d));
756 o(0xc0 + REG_VALUE(d) + REG_VALUE(r) * 8);
757 }
758 }782 }
759
760 }783 }
761 }784 }
762 vtop--;785 vtop--;
763 }786 }
764 save_regs(0);787 save_regs(0);
788
789 /* Copy R10 and R11 into RCX and RDX, respectively */
790 if (nb_args > 0) {
791 o(0xd1894c); /* mov %r10, %rcx */
792 if (nb_args > 1) {
793 o(0xda894c); /* mov %r11, %rdx */
794 }
795 }
796
765 gcall_or_jmp(0);797 gcall_or_jmp(0);
766 vtop--;798 vtop--;
767}799}
@@ -772,7 +804,7 @@ void gfunc_call(int nb_args) · 4 unmodified lines
772/* generate function prolog of type 't' */804/* generate function prolog of type 't' */
773void gfunc_prolog(CType *func_type)805void gfunc_prolog(CType *func_type)
774{806{
775 int addr, reg_param_index, bt;807 int addr, reg_param_index, bt, size;
776 Sym *sym;808 Sym *sym;
777 CType *type;809 CType *type;
778 810
@@ -790,34 +822,46 @@ void gfunc_prolog(CType *func_type) · 11 unmodified lines
790 /* if the function returns a structure, then add an822 /* if the function returns a structure, then add an
791 implicit pointer parameter */823 implicit pointer parameter */
792 func_vt = sym->type;824 func_vt = sym->type;
793 if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {825 size = gfunc_arg_size(&func_vt);
826 if (size > 8) {
794 gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);827 gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);
828 func_vc = addr;
795 reg_param_index++;829 reg_param_index++;
796 addr += PTR_SIZE;830 addr += 8;
797 }831 }
798 832
799 /* define parameters */833 /* define parameters */
800 while ((sym = sym->next) != NULL) {834 while ((sym = sym->next) != NULL) {
801 type = &sym->type;835 type = &sym->type;
802 bt = type->t & VT_BTYPE;836 bt = type->t & VT_BTYPE;
803 if (reg_param_index < REGN) {837 size = gfunc_arg_size(type);
804 /* save arguments passed by register */838 if (size > 8) {
805 gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);839 if (reg_param_index < REGN) {
806 }840 gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);
807 if (bt == VT_STRUCT || bt == VT_LDOUBLE) {841 }
808 sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL | VT_REF, addr);842 sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL | VT_REF, addr);
809 } else {843 } else {
844 if (reg_param_index < REGN) {
845 /* save arguments passed by register */
846 if ((bt == VT_FLOAT) || (bt == VT_DOUBLE)) {
847 o(0xd60f66); /* movq */
848 gen_modrm(reg_param_index, VT_LOCAL, NULL, addr);
849 } else {
850 gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);
851 }
852 }
810 sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr);853 sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr);
811 }854 }
855 addr += 8;
812 reg_param_index++;856 reg_param_index++;
813 addr += PTR_SIZE;
814 }857 }
815 858
816 while (reg_param_index < REGN) {859 while (reg_param_index < REGN) {
817 if (func_type->ref->c == FUNC_ELLIPSIS)860 if (func_type->ref->c == FUNC_ELLIPSIS) {
818 gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);861 gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);
862 addr += 8;
863 }
819 reg_param_index++;864 reg_param_index++;
820 addr += PTR_SIZE;
821 }865 }
822}866}
823 867
@@ -1072,13 +1116,13 @@ void gfunc_call(int nb_args) · 248 unmodified lines
1072 }1116 }
1073 1117
1074 for(i = 0; i < nb_args;) {1118 for(i = 0; i < nb_args;) {
1075 /* Swap argument to top, it will possibly be changed here,1119 /* Swap argument to top, it will possibly be changed here,
1076 and might use more temps. At the end of the loop we keep1120 and might use more temps. At the end of the loop we keep
1077 in on the stack and swap it back to its original position1121 in on the stack and swap it back to its original position
1078 if it is a register. */1122 if it is a register. */
1079 SValue tmp = vtop[0];1123 SValue tmp = vtop[0];
1080 vtop[0] = vtop[-i];1124 vtop[0] = vtop[-i];
1081 vtop[-i] = tmp;1125 vtop[-i] = tmp;
1082 1126
1083 mode = classify_x86_64_arg(&vtop->type, NULL, &size, &reg_count);1127 mode = classify_x86_64_arg(&vtop->type, NULL, &size, &reg_count);
1084 1128
@@ -1183,23 +1227,23 @@ void gfunc_call(int nb_args) · 98 unmodified lines
1183 /* Alter stack entry type so that gv() knows how to treat it */1227 /* Alter stack entry type so that gv() knows how to treat it */
1184 vtop->type = type;1228 vtop->type = type;
1185 if (mode == x86_64_mode_sse) {1229 if (mode == x86_64_mode_sse) {
1186 if (reg_count == 2) {1230 if (reg_count == 2) {
1187 sse_reg -= 2;1231 sse_reg -= 2;
1188 gv(RC_FRET); /* Use pair load into xmm0 & xmm1 */1232 gv(RC_FRET); /* Use pair load into xmm0 & xmm1 */
1189 if (sse_reg) { /* avoid redundant movaps %xmm0, %xmm0 */1233 if (sse_reg) { /* avoid redundant movaps %xmm0, %xmm0 */
1190 /* movaps %xmm0, %xmmN */1234 /* movaps %xmm0, %xmmN */
1191 o(0x280f);1235 o(0x280f);
1192 o(0xc0 + (sse_reg << 3));1236 o(0xc0 + (sse_reg << 3));
1193 /* movaps %xmm1, %xmmN */1237 /* movaps %xmm1, %xmmN */
1194 o(0x280f);1238 o(0x280f);
1195 o(0xc1 + ((sse_reg+1) << 3));1239 o(0xc1 + ((sse_reg+1) << 3));
1196 }1240 }
1197 } else {1241 } else {
1198 assert(reg_count == 1);1242 assert(reg_count == 1);
1199 --sse_reg;1243 --sse_reg;
1200 /* Load directly to register */1244 /* Load directly to register */
1201 gv(RC_XMM0 << sse_reg);1245 gv(RC_XMM0 << sse_reg);
1202 }1246 }
1203 } else if (mode == x86_64_mode_integer) {1247 } else if (mode == x86_64_mode_integer) {
1204 /* simple type */1248 /* simple type */
1205 /* XXX: implicit cast ? */1249 /* XXX: implicit cast ? */
@@ -1209,8 +1253,6 @@ void gfunc_call(int nb_args) · 3 unmodified lines
1209 orex(1,d,r,0x89); /* mov */1253 orex(1,d,r,0x89); /* mov */
1210 o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d));1254 o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d));
1211 if (reg_count == 2) {1255 if (reg_count == 2) {
1212 /* Second word of two-word value should always be in rdx
1213 this case is handled via RC_IRET */
1214 d = arg_prepare_reg(gen_reg+1);1256 d = arg_prepare_reg(gen_reg+1);
1215 orex(1,d,vtop->r2,0x89); /* mov */1257 orex(1,d,vtop->r2,0x89); /* mov */
1216 o(0xc0 + REG_VALUE(vtop->r2) * 8 + REG_VALUE(d));1258 o(0xc0 + REG_VALUE(vtop->r2) * 8 + REG_VALUE(d));
@@ -1255,7 +1297,7 @@ void gfunc_prolog(CType *func_type) · 38 unmodified lines
1255{1297{
1256 X86_64_Mode mode;1298 X86_64_Mode mode;
1257 int i, addr, align, size, reg_count;1299 int i, addr, align, size, reg_count;
1258 int param_index, param_addr, reg_param_index, sse_param_index;1300 int param_addr, reg_param_index, sse_param_index;
1259 Sym *sym;1301 Sym *sym;
1260 CType *type;1302 CType *type;
1261 1303
@@ -1328,7 +1370,6 @@ void gfunc_prolog(CType *func_type) · 66 unmodified lines
1328 }1370 }
1329 1371
1330 sym = func_type->ref;1372 sym = func_type->ref;
1331 param_index = 0;
1332 reg_param_index = 0;1373 reg_param_index = 0;
1333 sse_param_index = 0;1374 sse_param_index = 0;
1334 1375
@@ -1338,10 +1379,7 @@ void gfunc_prolog(CType *func_type) · 3 unmodified lines
1338 mode = classify_x86_64_arg(&func_vt, NULL, &size, &reg_count);1379 mode = classify_x86_64_arg(&func_vt, NULL, &size, &reg_count);
1339 if (mode == x86_64_mode_memory) {1380 if (mode == x86_64_mode_memory) {
1340 push_arg_reg(reg_param_index);1381 push_arg_reg(reg_param_index);
1341 param_addr = loc;
1342
1343 func_vc = loc;1382 func_vc = loc;
1344 param_index++;
1345 reg_param_index++;1383 reg_param_index++;
1346 }1384 }
1347 /* define parameters */1385 /* define parameters */
@@ -1391,7 +1429,6 @@ void gfunc_prolog(CType *func_type) · 43 unmodified lines
1391 }1429 }
1392 sym_push(sym->v & ~SYM_FIELD, type,1430 sym_push(sym->v & ~SYM_FIELD, type,
1393 VT_LOCAL | VT_LVAL, param_addr);1431 VT_LOCAL | VT_LVAL, param_addr);
1394 param_index++;
1395 }1432 }
1396}1433}
1397 1434