tcctest1-3 fail, but this appears to be due to bugs in GCC rather than TCC (from manual inspection of the output).
Unified · Split
| @@ -46,32 +46,36 @@ set(I386_SOURCES i386-gen.c i386-asm.c i386-asm.h i386-tok.h) · 45 unmodified lines | |||
| 46 | set(X86_64_SOURCES x86_64-gen.c i386-asm.c x86_64-asm.h) | 46 | set(X86_64_SOURCES x86_64-gen.c i386-asm.c x86_64-asm.h) |
| 47 | 47 | ||
| 48 | if(TCC_TARGET STREQUAL "Win32") | 48 | if(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) |
| 52 | elseif(TCC_TARGET STREQUAL "Win64") | 51 | elseif(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) |
| 56 | elseif(TCC_TARGET STREQUAL "WinCE") | 54 | elseif(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) |
| 59 | elseif(TCC_TARGET STREQUAL "i386") | 58 | elseif(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}) |
| 62 | elseif(TCC_TARGET STREQUAL "x86-64") | 61 | elseif(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}) |
| 65 | elseif(TCC_TARGET STREQUAL "ARM") | 64 | elseif(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) |
| 68 | elseif(TCC_TARGET STREQUAL "C67") | 71 | elseif(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) |
| 71 | else() | 74 | else() |
| 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}") |
| 73 | endif() | 76 | endif() |
| 74 | 77 | ||
| 78 | add_definitions(${TCC_TARGET_FLAGS}) | ||
| 75 | file(STRINGS "VERSION" TCC_VERSION) | 79 | file(STRINGS "VERSION" TCC_VERSION) |
| 76 | list(GET TCC_VERSION 0 TCC_VERSION) | 80 | list(GET TCC_VERSION 0 TCC_VERSION) |
| 77 | include_directories(${CMAKE_BINARY_DIR}) | 81 | include_directories(${CMAKE_BINARY_DIR}) |
| @@ -86,7 +90,7 @@ set_target_properties(libtcc PROPERTIES PREFIX "") · 8 unmodified lines | |||
| 86 | 90 | ||
| 87 | add_executable(tcc tcc.c) | 91 | add_executable(tcc tcc.c) |
| 88 | target_link_libraries(tcc libtcc) | 92 | target_link_libraries(tcc libtcc) |
| 89 | set(TCC_CFLAGS -I${CMAKE_SOURCE_DIR}/include) | 93 | set(TCC_CFLAGS -I${CMAKE_SOURCE_DIR}/include ${CMAKE_C_FLAGS}) |
| 90 | if(TCC_TARGET MATCHES "^Win") | 94 | if(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) |
| 92 | endif() | 96 | endif() |
| @@ -108,7 +112,7 @@ elseif(TCC_TARGET STREQUAL "x86-64") · 15 unmodified lines | |||
| 108 | endif() | 112 | endif() |
| 109 | 113 | ||
| 110 | if (TCC_TARGET MATCHES "^Win") | 114 | if (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) |
| 114 | endif() | 118 | endif() |
| @@ -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}) |
| @@ -3,14 +3,3 @@ · 2 unmodified lines | |||
| 3 | 3 | ||
| 4 | #cmakedefine CONFIG_WIN32 | 4 | #cmakedefine CONFIG_WIN32 |
| 5 | #cmakedefine CONFIG_WIN64 | 5 | #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 | ||
| @@ -19,9 +19,9 @@ void __va_end(va_list ap); · 18 unmodified lines | |||
| 19 | 19 | ||
| 20 | #else /* _WIN64 */ | 20 | #else /* _WIN64 */ |
| 21 | typedef char *va_list; | 21 | typedef 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 | #endif | 26 | #endif |
| 27 | 27 | ||
| @@ -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 | #endif | 3751 | #endif |
| 3728 | case TOK_INC: | 3752 | case TOK_INC: |
| 3729 | case TOK_DEC: | 3753 | case TOK_DEC: |
| @@ -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_64 | 127 | #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 | #endif | 133 | #endif |
| 130 | DEF(TOK_REGPARM1, "regparm") | 134 | DEF(TOK_REGPARM1, "regparm") |
| 131 | DEF(TOK_REGPARM2, "__regparm__") | 135 | DEF(TOK_REGPARM2, "__regparm__") |
| @@ -6,7 +6,7 @@ add_test(NAME abitest-cc WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND abitest-c · 5 unmodified lines | |||
| 6 | 6 | ||
| 7 | set(ABITEST_TCC abitest-tcc${CMAKE_EXECUTABLE_SUFFIX}) | 7 | set(ABITEST_TCC abitest-tcc${CMAKE_EXECUTABLE_SUFFIX}) |
| 8 | get_property(LIBTCC_LIB TARGET libtcc PROPERTY LOCATION) | 8 | get_property(LIBTCC_LIB TARGET libtcc PROPERTY LOCATION) |
| 9 | add_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) | 9 | add_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) |
| 10 | add_custom_target(abitest-tcc-exe ALL DEPENDS ${ABITEST_TCC}) | 10 | add_custom_target(abitest-tcc-exe ALL DEPENDS ${ABITEST_TCC}) |
| 11 | 11 | ||
| 12 | add_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) | 12 | add_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) |
| 21 | endif() | 21 | endif() |
| 22 | set(TCC_TEST_SOURCE ${TCC_TEST_CFLAGS} -run ${CMAKE_CURRENT_SOURCE_DIR}/tcctest.c) | 22 | set(TCC_TEST_SOURCE ${TCC_TEST_CFLAGS} -run ${CMAKE_CURRENT_SOURCE_DIR}/tcctest.c) |
| 23 | set(TCC_TEST_RUN ${TCC_TEST_CFLAGS} -DONE_SOURCE -run ${CMAKE_SOURCE_DIR}/tcc.c) | 23 | set(TCC_TEST_RUN ${TCC_TEST_CFLAGS} ${TCC_TARGET_FLAGS} -DONE_SOURCE -run ${CMAKE_SOURCE_DIR}/tcc.c) |
| 24 | 24 | ||
| 25 | add_custom_command(OUTPUT tcctest.ref COMMAND tcctest-cc > tcctest.ref) | 25 | add_custom_command(OUTPUT tcctest.ref COMMAND tcctest-cc > tcctest.ref) |
| 26 | add_custom_command(OUTPUT tcctest.1 COMMAND tcc ${TCC_TEST_SOURCE} > tcctest.1) | 26 | add_custom_command(OUTPUT tcctest.1 COMMAND tcc ${TCC_TEST_SOURCE} > tcctest.1) |
| @@ -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 | |||
| 269 | typedef struct many_struct_test_type_s {long long a, b, c;} many_struct_test_type; | ||
| 270 | 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); | ||
| 271 | |||
| 272 | static 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 | |||
| 279 | static 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 | |||
| 296 | typedef struct many_struct_test_2_type_s {int a, b;} many_struct_test_2_type; | ||
| 297 | 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); | ||
| 298 | |||
| 299 | static 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 | |||
| 306 | static 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 ABI | 319 | * stdarg_test: Test variable argument list ABI |
| 267 | */ | 320 | */ |
| 268 | 321 | ||
| 269 | typedef void (*stdarg_test_function_type) (int,int,...); | 322 | typedef struct {long long a, b, c;} stdarg_test_struct_type; |
| 323 | typedef void (*stdarg_test_function_type) (int,int,int,...); | ||
| 270 | 324 | ||
| 271 | static int stdarg_test_callback(void *ptr) { | 325 | static 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 | ||
| 281 | static int stdarg_test(void) { | 337 | static 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 | |||
| 368 | typedef struct {long long a, b, c;} stdarg_struct_test_struct_type; | ||
| 369 | typedef int (*stdarg_struct_test_function_type) (stdarg_struct_test_struct_type a, ...); | ||
| 370 | |||
| 371 | static 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 | |||
| 378 | static 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 | } |
| @@ -23,7 +23,7 @@ · 22 unmodified lines | |||
| 23 | #ifdef TARGET_DEFS_ONLY | 23 | #ifdef TARGET_DEFS_ONLY |
| 24 | 24 | ||
| 25 | /* number of available registers */ | 25 | /* number of available registers */ |
| 26 | #define NB_REGS 24 | 26 | #define NB_REGS 22 |
| 27 | #define NB_ASM_REGS 8 | 27 | #define NB_ASM_REGS 8 |
| 28 | 28 | ||
| 29 | /* a register can belong to several classes. The classes must be | 29 | /* a register can belong to several classes. The classes must be |
| @@ -45,8 +45,6 @@ · 15 unmodified lines | |||
| 45 | #define RC_XMM3 0x8000 | 45 | #define RC_XMM3 0x8000 |
| 46 | #define RC_XMM4 0x10000 | 46 | #define RC_XMM4 0x10000 |
| 47 | #define RC_XMM5 0x20000 | 47 | #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 | ||
| 150 | static unsigned long func_sub_sp_offset; | 146 | static 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_PE | 622 | #ifdef TCC_TARGET_PE |
| 627 | 623 | ||
| 628 | #define REGN 4 | 624 | #define REGN 4 |
| 629 | static const uint8_t arg_regs[] = { | 625 | static const uint8_t arg_regs[REGN] = { |
| 630 | TREG_RCX, TREG_RDX, TREG_R8, TREG_R9 | 626 | 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 */ | ||
| 631 | static 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 | |||
| 633 | static int func_scratch; | 639 | static int func_scratch; |
| 634 | 640 | ||
| 635 | /* Generate function call. The function address is pushed first, then | 641 | /* 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 */ |
| 652 | ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) { | 658 | ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) { |
| 653 | *ret_align = 1; // Never have to re-align return values for x86-64 | 659 | *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 | |||
| 680 | int 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 | ||
| 657 | void gfunc_call(int nb_args) | 687 | void 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 function | 695 | /* 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 1 | 731 | |
| 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' */ |
| 773 | void gfunc_prolog(CType *func_type) | 805 | void 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 an | 822 | /* 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 keep | 1120 | 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 position | 1121 | 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, ®_count); | 1127 | mode = classify_x86_64_arg(&vtop->type, NULL, &size, ®_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, ®_count); | 1379 | mode = classify_x86_64_arg(&func_vt, NULL, &size, ®_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 | ||