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 | 46 | set(X86_64_SOURCES x86_64-gen.c i386-asm.c x86_64-asm.h) |
| 47 | 47 | |
| 48 | 48 | if(TCC_TARGET STREQUAL "Win32") |
| 49 | − set(TCC_TARGET_I386 ON) | |
| 50 | − set(TCC_TARGET_PE ON) | |
| 49 | + set(TCC_TARGET_FLAGS -DTCC_TARGET_I386 -DTCC_TARGET_PE) | |
| 51 | 50 | set(LIBTCC_TARGET_SOURCES ${I386_SOURCES} tccpe.c) |
| 52 | 51 | elseif(TCC_TARGET STREQUAL "Win64") |
| 53 | − set(TCC_TARGET_PE ON) | |
| 54 | − set(TCC_TARGET_X86_64 ON) | |
| 52 | + set(TCC_TARGET_FLAGS -DTCC_TARGET_X86_64 -DTCC_TARGET_PE) | |
| 55 | 53 | set(LIBTCC_TARGET_SOURCES ${X86_64_SOURCES} tccpe.c) |
| 56 | 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 | 57 | set(LIBTCC_TARGET_SOURCES arm-gen.c tccpe.c) |
| 59 | 58 | elseif(TCC_TARGET STREQUAL "i386") |
| 60 | − set(TCC_TARGET_I386 ON) | |
| 59 | + set(TCC_TARGET_FLAGS -DTCC_TARGET_I386) | |
| 61 | 60 | set(LIBTCC_TARGET_SOURCES ${I386_SOURCES}) |
| 62 | 61 | elseif(TCC_TARGET STREQUAL "x86-64") |
| 63 | − set(TCC_TARGET_X86_64 ON) | |
| 62 | + set(TCC_TARGET_FLAGS -DTCC_TARGET_X86_64) | |
| 64 | 63 | set(LIBTCC_TARGET_SOURCES ${X86_64_SOURCES}) |
| 65 | 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 | 70 | set(LIBTCC_TARGET_SOURCES arm-gen.c) |
| 68 | 71 | elseif(TCC_TARGET STREQUAL "C67") |
| 69 | − set(TCC_TARGET_C67 ON) | |
| 72 | + set(TCC_TARGET_FLAGS -DTCC_TARGET_C67) | |
| 70 | 73 | set(LIBTCC_TARGET_SOURCES c67-gen.c tcccoff.c) |
| 71 | 74 | else() |
| 72 | 75 | message(FATAL_ERROR "Unrecognised target in TCC_TARGET, must be one of ${TCC_TARGET_LIST}") |
| 73 | 76 | endif() |
| 74 | 77 | |
| 78 | +add_definitions(${TCC_TARGET_FLAGS}) | |
| 75 | 79 | file(STRINGS "VERSION" TCC_VERSION) |
| 76 | 80 | list(GET TCC_VERSION 0 TCC_VERSION) |
| 77 | 81 | include_directories(${CMAKE_BINARY_DIR}) |
| @@ -86,7 +90,7 @@ set_target_properties(libtcc PROPERTIES PREFIX "") · 8 unmodified lines | ||
| 86 | 90 | |
| 87 | 91 | add_executable(tcc tcc.c) |
| 88 | 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 | 94 | if(TCC_TARGET MATCHES "^Win") |
| 91 | 95 | set(TCC_CFLAGS ${TCC_CFLAGS} -I${CMAKE_SOURCE_DIR}/win32/include) |
| 92 | 96 | endif() |
| @@ -108,7 +112,7 @@ elseif(TCC_TARGET STREQUAL "x86-64") · 15 unmodified lines | ||
| 108 | 112 | endif() |
| 109 | 113 | |
| 110 | 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 | 116 | set(XAR tiny_libmaker${CMAKE_EXECUTABLE_SUFFIX}) |
| 113 | 117 | set(XDEPENDS tiny_libmaker) |
| 114 | 118 | endif() |
| @@ -119,7 +123,7 @@ if(LIBTCC1_SOURCES) · 4 unmodified lines | ||
| 119 | 123 | string(REGEX MATCH "[^/]+$" LIBTCC1_O ${LIBTCC1_C}) |
| 120 | 124 | string(REGEX MATCH "^[^.]+" LIBTCC1_O ${LIBTCC1_O}) |
| 121 | 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 | 127 | list(APPEND LIBTCC1_OBJECTS ${LIBTCC1_O}) |
| 124 | 128 | endforeach() |
| 125 | 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 | 4 | #cmakedefine CONFIG_WIN32 |
| 5 | 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 | 20 | #else /* _WIN64 */ |
| 21 | 21 | typedef char *va_list; |
| 22 | −#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+7)&~7) | |
| 23 | −#define va_arg(ap,type) (ap += (sizeof(type)+7)&~7, *(type *)(ap - ((sizeof(type)+7)&~7))) | |
| 24 | −#define va_copy(dest, src) (dest) = (src) | |
| 22 | +#define va_start(ap,last) __builtin_va_start(ap,last) | |
| 23 | +#define va_arg(ap,type) (ap += 8, sizeof(type)<=8 ? *(type*)ap : **(type**)ap) | |
| 24 | +#define va_copy(dest, src) ((dest) = (src)) | |
| 25 | 25 | #define va_end(ap) |
| 26 | 26 | #endif |
| 27 | 27 | |
| @@ -851,7 +851,13 @@ ST_FUNC int gv(int rc) · 850 unmodified lines | ||
| 851 | 851 | t = vtop->type.t; |
| 852 | 852 | t1 = t; |
| 853 | 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 | 861 | t = VT_BYTE; |
| 856 | 862 | else if (vtop->r & VT_LVAL_SHORT) |
| 857 | 863 | t = VT_SHORT; |
| @@ -3712,7 +3718,24 @@ ST_FUNC void unary(void) · 2854 unmodified lines | ||
| 3712 | 3718 | } |
| 3713 | 3719 | } |
| 3714 | 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 | 3739 | case TOK_builtin_va_arg_types: |
| 3717 | 3740 | { |
| 3718 | 3741 | CType type; |
| @@ -3724,6 +3747,7 @@ ST_FUNC void unary(void) · 5 unmodified lines | ||
| 3724 | 3747 | vpushi(classify_x86_64_va_arg(&type)); |
| 3725 | 3748 | } |
| 3726 | 3749 | break; |
| 3750 | +#endif | |
| 3727 | 3751 | #endif |
| 3728 | 3752 | case TOK_INC: |
| 3729 | 3753 | case TOK_DEC: |
| @@ -125,7 +125,11 @@ · 124 unmodified lines | ||
| 125 | 125 | DEF(TOK_builtin_constant_p, "__builtin_constant_p") |
| 126 | 126 | DEF(TOK_builtin_frame_address, "__builtin_frame_address") |
| 127 | 127 | #ifdef TCC_TARGET_X86_64 |
| 128 | +#ifdef TCC_TARGET_PE | |
| 129 | + DEF(TOK_builtin_va_start, "__builtin_va_start") | |
| 130 | +#else | |
| 128 | 131 | DEF(TOK_builtin_va_arg_types, "__builtin_va_arg_types") |
| 132 | +#endif | |
| 129 | 133 | #endif |
| 130 | 134 | DEF(TOK_REGPARM1, "regparm") |
| 131 | 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 | 7 | set(ABITEST_TCC abitest-tcc${CMAKE_EXECUTABLE_SUFFIX}) |
| 8 | 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 | 10 | add_custom_target(abitest-tcc-exe ALL DEPENDS ${ABITEST_TCC}) |
| 11 | 11 | |
| 12 | 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 | 20 | set(TCC_TEST_CFLAGS ${TCC_TEST_CFLAGS} -I${CMAKE_SOURCE_DIR}/win32/include/winapi) |
| 21 | 21 | endif() |
| 22 | 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 | 25 | add_custom_command(OUTPUT tcctest.ref COMMAND tcctest-cc > tcctest.ref) |
| 26 | 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 | 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 | 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 | 325 | static int stdarg_test_callback(void *ptr) { |
| 272 | 326 | stdarg_test_function_type f = (stdarg_test_function_type)ptr; |
| 273 | 327 | int x; |
| 274 | 328 | double y; |
| 275 | − f(10, 10, | |
| 329 | + stdarg_test_struct_type z = {1, 2, 3}, w; | |
| 330 | + f(10, 10, 5, | |
| 276 | 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); | |
| 278 | − return ((x == 55) && (y == 55)) ? 0 : -1; | |
| 332 | + 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, &y, | |
| 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 | 337 | static int stdarg_test(void) { |
| 282 | 338 | const char *src = |
| 283 | 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 | 342 | " int i, ti;\n" |
| 286 | 343 | " double td;\n" |
| 344 | + " stdarg_test_struct_type ts = {0,0,0}, tmp;\n" | |
| 287 | 345 | " va_list ap;\n" |
| 288 | − " va_start(ap, n_float);\n" | |
| 346 | + " va_start(ap, n_struct);\n" | |
| 289 | 347 | " for (i = 0, ti = 0; i < n_int; ++i)\n" |
| 290 | 348 | " ti += va_arg(ap, int);\n" |
| 291 | 349 | " *va_arg(ap, int*) = ti;\n" |
| 292 | 350 | " for (i = 0, td = 0; i < n_float; ++i)\n" |
| 293 | 351 | " td += va_arg(ap, double);\n" |
| 294 | 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 | 358 | " va_end(ap);" |
| 296 | 359 | "}\n"; |
| 297 | 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 | 392 | #define RUN_TEST(t) \ |
| 301 | 393 | if (!testname || (strcmp(#t, testname) == 0)) { \ |
| 302 | 394 | fputs(#t "... ", stdout); \ |
| @@ -336,6 +428,9 @@ int main(int argc, char **argv) { · 33 unmodified lines | ||
| 336 | 428 | RUN_TEST(sret_test); |
| 337 | 429 | RUN_TEST(one_member_union_test); |
| 338 | 430 | RUN_TEST(two_member_union_test); |
| 431 | + RUN_TEST(many_struct_test); | |
| 432 | + RUN_TEST(many_struct_test_2); | |
| 339 | 433 | RUN_TEST(stdarg_test); |
| 434 | + RUN_TEST(stdarg_struct_test); | |
| 340 | 435 | return retval; |
| 341 | 436 | } |
| @@ -23,7 +23,7 @@ · 22 unmodified lines | ||
| 23 | 23 | #ifdef TARGET_DEFS_ONLY |
| 24 | 24 | |
| 25 | 25 | /* number of available registers */ |
| 26 | −#define NB_REGS 24 | |
| 26 | +#define NB_REGS 22 | |
| 27 | 27 | #define NB_ASM_REGS 8 |
| 28 | 28 | |
| 29 | 29 | /* a register can belong to several classes. The classes must be |
| @@ -45,8 +45,6 @@ · 15 unmodified lines | ||
| 45 | 45 | #define RC_XMM3 0x8000 |
| 46 | 46 | #define RC_XMM4 0x10000 |
| 47 | 47 | #define RC_XMM5 0x20000 |
| 48 | −#define RC_XMM6 0x40000 | |
| 49 | −#define RC_XMM7 0x80000 | |
| 50 | 48 | #define RC_IRET RC_RAX /* function return: integer register */ |
| 51 | 49 | #define RC_LRET RC_RDX /* function return: second integer register */ |
| 52 | 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 | 140 | /* xmm2 */ RC_FLOAT | RC_XMM2, |
| 143 | 141 | /* xmm3 */ RC_FLOAT | RC_XMM3, |
| 144 | 142 | /* xmm4 */ RC_FLOAT | RC_XMM4, |
| 145 | − /* xmm5 */ RC_FLOAT | RC_XMM5, | |
| 146 | − /* xmm6 */ RC_FLOAT | RC_XMM6, | |
| 147 | − /* xmm7 */ RC_FLOAT | RC_XMM7, | |
| 143 | + /* xmm5 */ RC_FLOAT | RC_XMM5 /* only up to xmm5: xmm6-15 must be callee saved on Win64 */ | |
| 148 | 144 | }; |
| 149 | 145 | |
| 150 | 146 | static unsigned long func_sub_sp_offset; |
| @@ -484,7 +480,7 @@ void load(int r, SValue *sv) · 333 unmodified lines | ||
| 484 | 480 | orex(0,r,0,0); |
| 485 | 481 | oad(0xb8 + REG_VALUE(r), t ^ 1); /* mov $0, r */ |
| 486 | 482 | } else if (v != r) { |
| 487 | − if ((r == TREG_XMM0) || (r == TREG_XMM1)) { | |
| 483 | + if ((r >= TREG_XMM0) && (r <= TREG_XMM7)) { | |
| 488 | 484 | if (v == TREG_ST0) { |
| 489 | 485 | /* gen_cvt_ftof(VT_DOUBLE); */ |
| 490 | 486 | o(0xf0245cdd); /* fstpl -0x10(%rsp) */ |
| @@ -493,7 +489,7 @@ void load(int r, SValue *sv) · 2 unmodified lines | ||
| 493 | 489 | o(0x44 + REG_VALUE(r)*8); /* %xmmN */ |
| 494 | 490 | o(0xf024); |
| 495 | 491 | } else { |
| 496 | − assert((v == TREG_XMM0) || (v == TREG_XMM1)); | |
| 492 | + assert((v >= TREG_XMM0) && (v <= TREG_XMM7)); | |
| 497 | 493 | if ((ft & VT_BTYPE) == VT_FLOAT) { |
| 498 | 494 | o(0x100ff3); |
| 499 | 495 | } else { |
| @@ -626,10 +622,20 @@ static void gcall_or_jmp(int is_jmp) · 126 unmodified lines | ||
| 626 | 622 | #ifdef TCC_TARGET_PE |
| 627 | 623 | |
| 628 | 624 | #define REGN 4 |
| 629 | −static const uint8_t arg_regs[] = { | |
| 625 | +static const uint8_t arg_regs[REGN] = { | |
| 630 | 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 | 639 | static int func_scratch; |
| 634 | 640 | |
| 635 | 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 | 657 | /* Return 1 if this function returns via an sret pointer, 0 otherwise */ |
| 652 | 658 | ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) { |
| 653 | 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 | 687 | void gfunc_call(int nb_args) |
| 658 | 688 | { |
| 659 | − int size, align, r, args_size, i, d, j, bt, struct_size; | |
| 660 | − int nb_reg_args, gen_reg; | |
| 689 | + int size, r, args_size, i, d, bt, struct_size; | |
| 690 | + int arg; | |
| 661 | 691 | |
| 662 | − nb_reg_args = nb_args; | |
| 663 | − args_size = (nb_reg_args < REGN ? REGN : nb_reg_args) * PTR_SIZE; | |
| 692 | + args_size = (nb_args < REGN ? REGN : nb_args) * PTR_SIZE; | |
| 693 | + arg = nb_args; | |
| 664 | 694 | |
| 665 | 695 | /* for struct arguments, we need to call memcpy and the function |
| 666 | 696 | call breaks register passing arguments we are preparing. |
| 667 | 697 | So, we process arguments which will be passed by stack first. */ |
| 668 | 698 | struct_size = args_size; |
| 669 | 699 | for(i = 0; i < nb_args; i++) { |
| 700 | + --arg; | |
| 701 | + | |
| 670 | 702 | SValue *sv = &vtop[-i]; |
| 671 | 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 | 709 | if (bt == VT_STRUCT) { |
| 673 | − size = type_size(&sv->type, &align); | |
| 674 | 710 | /* align to stack align size */ |
| 675 | 711 | size = (size + 15) & ~15; |
| 676 | 712 | /* generate structure store */ |
| @@ -683,85 +719,81 @@ void gfunc_call(int nb_args) · 6 unmodified lines | ||
| 683 | 719 | vpushv(sv); |
| 684 | 720 | vstore(); |
| 685 | 721 | --vtop; |
| 686 | − | |
| 687 | 722 | } else if (bt == VT_LDOUBLE) { |
| 688 | − | |
| 689 | 723 | gv(RC_ST0); |
| 690 | 724 | gen_offs_sp(0xdb, 0x107, struct_size); |
| 691 | 725 | struct_size += 16; |
| 692 | − | |
| 693 | 726 | } |
| 694 | 727 | } |
| 695 | 728 | |
| 696 | 729 | if (func_scratch < struct_size) |
| 697 | 730 | func_scratch = struct_size; |
| 698 | −#if 1 | |
| 699 | − for (i = 0; i < REGN; ++i) | |
| 700 | − save_reg(arg_regs[i]); | |
| 701 | − save_reg(TREG_RAX); | |
| 702 | −#endif | |
| 703 | − gen_reg = nb_reg_args; | |
| 731 | + | |
| 732 | + arg = nb_args; | |
| 704 | 733 | struct_size = args_size; |
| 705 | 734 | |
| 706 | 735 | for(i = 0; i < nb_args; i++) { |
| 736 | + --arg; | |
| 707 | 737 | bt = (vtop->type.t & VT_BTYPE); |
| 708 | 738 | |
| 709 | − if (bt == VT_STRUCT || bt == VT_LDOUBLE) { | |
| 710 | − if (bt == VT_LDOUBLE) | |
| 711 | − size = 16; | |
| 712 | − else | |
| 713 | − size = type_size(&vtop->type, &align); | |
| 739 | + size = gfunc_arg_size(&vtop->type); | |
| 740 | + if (size > 8) { | |
| 714 | 741 | /* align to stack align size */ |
| 715 | 742 | size = (size + 15) & ~15; |
| 716 | − j = --gen_reg; | |
| 717 | − if (j >= REGN) { | |
| 718 | − d = TREG_RAX; | |
| 743 | + if (arg >= REGN) { | |
| 744 | + d = get_reg(RC_INT); | |
| 719 | 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 | 747 | } else { |
| 722 | − d = arg_regs[j]; | |
| 748 | + d = arg_prepare_reg(arg); | |
| 723 | 749 | gen_offs_sp(0x8d, d, struct_size); |
| 724 | 750 | } |
| 725 | 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 | 752 | } else { |
| 744 | − j = --gen_reg; | |
| 745 | − if (j >= REGN) { | |
| 746 | − r = gv(RC_INT); | |
| 747 | − gen_offs_sp(0x89, r, j*8); | |
| 753 | + if (is_sse_float(vtop->type.t)) { | |
| 754 | + gv(RC_XMM0); /* only use one float register */ | |
| 755 | + if (arg >= REGN) { | |
| 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 | 768 | } else { |
| 749 | − d = arg_regs[j]; | |
| 750 | − if (d < NB_REGS) { | |
| 751 | − gv(reg_classes[d] & ~RC_INT); | |
| 769 | + if (bt == VT_STRUCT) { | |
| 770 | + vtop->type.ref = NULL; | |
| 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 | 778 | } else { |
| 753 | − r = gv(RC_INT); | |
| 754 | − if (d != r) { | |
| 755 | − orex(1,d,r, 0x89); | |
| 756 | − o(0xc0 + REG_VALUE(d) + REG_VALUE(r) * 8); | |
| 757 | − } | |
| 779 | + d = arg_prepare_reg(arg); | |
| 780 | + orex(1,d,r,0x89); /* mov */ | |
| 781 | + o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d)); | |
| 758 | 782 | } |
| 759 | − | |
| 760 | 783 | } |
| 761 | 784 | } |
| 762 | 785 | vtop--; |
| 763 | 786 | } |
| 764 | 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 | 797 | gcall_or_jmp(0); |
| 766 | 798 | vtop--; |
| 767 | 799 | } |
| @@ -772,7 +804,7 @@ void gfunc_call(int nb_args) · 4 unmodified lines | ||
| 772 | 804 | /* generate function prolog of type 't' */ |
| 773 | 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 | 808 | Sym *sym; |
| 777 | 809 | CType *type; |
| 778 | 810 | |
| @@ -790,34 +822,46 @@ void gfunc_prolog(CType *func_type) · 11 unmodified lines | ||
| 790 | 822 | /* if the function returns a structure, then add an |
| 791 | 823 | implicit pointer parameter */ |
| 792 | 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 | 827 | gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); |
| 828 | + func_vc = addr; | |
| 795 | 829 | reg_param_index++; |
| 796 | − addr += PTR_SIZE; | |
| 830 | + addr += 8; | |
| 797 | 831 | } |
| 798 | 832 | |
| 799 | 833 | /* define parameters */ |
| 800 | 834 | while ((sym = sym->next) != NULL) { |
| 801 | 835 | type = &sym->type; |
| 802 | 836 | bt = type->t & VT_BTYPE; |
| 803 | − if (reg_param_index < REGN) { | |
| 804 | − /* save arguments passed by register */ | |
| 805 | − gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); | |
| 806 | − } | |
| 807 | − if (bt == VT_STRUCT || bt == VT_LDOUBLE) { | |
| 837 | + size = gfunc_arg_size(type); | |
| 838 | + if (size > 8) { | |
| 839 | + if (reg_param_index < REGN) { | |
| 840 | + gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); | |
| 841 | + } | |
| 808 | 842 | sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL | VT_REF, addr); |
| 809 | 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 | 853 | sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr); |
| 811 | 854 | } |
| 855 | + addr += 8; | |
| 812 | 856 | reg_param_index++; |
| 813 | − addr += PTR_SIZE; | |
| 814 | 857 | } |
| 815 | 858 | |
| 816 | 859 | while (reg_param_index < REGN) { |
| 817 | − if (func_type->ref->c == FUNC_ELLIPSIS) | |
| 860 | + if (func_type->ref->c == FUNC_ELLIPSIS) { | |
| 818 | 861 | gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); |
| 862 | + addr += 8; | |
| 863 | + } | |
| 819 | 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 | 1118 | for(i = 0; i < nb_args;) { |
| 1075 | − /* Swap argument to top, it will possibly be changed here, | |
| 1076 | − 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 | |
| 1078 | − if it is a register. */ | |
| 1119 | + /* Swap argument to top, it will possibly be changed here, | |
| 1120 | + and might use more temps. At the end of the loop we keep | |
| 1121 | + in on the stack and swap it back to its original position | |
| 1122 | + if it is a register. */ | |
| 1079 | 1123 | SValue tmp = vtop[0]; |
| 1080 | − vtop[0] = vtop[-i]; | |
| 1081 | − vtop[-i] = tmp; | |
| 1124 | + vtop[0] = vtop[-i]; | |
| 1125 | + vtop[-i] = tmp; | |
| 1082 | 1126 | |
| 1083 | 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 | 1227 | /* Alter stack entry type so that gv() knows how to treat it */ |
| 1184 | 1228 | vtop->type = type; |
| 1185 | 1229 | if (mode == x86_64_mode_sse) { |
| 1186 | − if (reg_count == 2) { | |
| 1187 | − sse_reg -= 2; | |
| 1188 | − gv(RC_FRET); /* Use pair load into xmm0 & xmm1 */ | |
| 1189 | − if (sse_reg) { /* avoid redundant movaps %xmm0, %xmm0 */ | |
| 1190 | − /* movaps %xmm0, %xmmN */ | |
| 1191 | − o(0x280f); | |
| 1192 | − o(0xc0 + (sse_reg << 3)); | |
| 1193 | − /* movaps %xmm1, %xmmN */ | |
| 1194 | − o(0x280f); | |
| 1195 | − o(0xc1 + ((sse_reg+1) << 3)); | |
| 1196 | − } | |
| 1197 | − } else { | |
| 1198 | − assert(reg_count == 1); | |
| 1199 | − --sse_reg; | |
| 1200 | − /* Load directly to register */ | |
| 1201 | − gv(RC_XMM0 << sse_reg); | |
| 1202 | − } | |
| 1230 | + if (reg_count == 2) { | |
| 1231 | + sse_reg -= 2; | |
| 1232 | + gv(RC_FRET); /* Use pair load into xmm0 & xmm1 */ | |
| 1233 | + if (sse_reg) { /* avoid redundant movaps %xmm0, %xmm0 */ | |
| 1234 | + /* movaps %xmm0, %xmmN */ | |
| 1235 | + o(0x280f); | |
| 1236 | + o(0xc0 + (sse_reg << 3)); | |
| 1237 | + /* movaps %xmm1, %xmmN */ | |
| 1238 | + o(0x280f); | |
| 1239 | + o(0xc1 + ((sse_reg+1) << 3)); | |
| 1240 | + } | |
| 1241 | + } else { | |
| 1242 | + assert(reg_count == 1); | |
| 1243 | + --sse_reg; | |
| 1244 | + /* Load directly to register */ | |
| 1245 | + gv(RC_XMM0 << sse_reg); | |
| 1246 | + } | |
| 1203 | 1247 | } else if (mode == x86_64_mode_integer) { |
| 1204 | 1248 | /* simple type */ |
| 1205 | 1249 | /* XXX: implicit cast ? */ |
| @@ -1209,8 +1253,6 @@ void gfunc_call(int nb_args) · 3 unmodified lines | ||
| 1209 | 1253 | orex(1,d,r,0x89); /* mov */ |
| 1210 | 1254 | o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d)); |
| 1211 | 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 | 1256 | d = arg_prepare_reg(gen_reg+1); |
| 1215 | 1257 | orex(1,d,vtop->r2,0x89); /* mov */ |
| 1216 | 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 | 1298 | X86_64_Mode mode; |
| 1257 | 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 | 1301 | Sym *sym; |
| 1260 | 1302 | CType *type; |
| 1261 | 1303 | |
| @@ -1328,7 +1370,6 @@ void gfunc_prolog(CType *func_type) · 66 unmodified lines | ||
| 1328 | 1370 | } |
| 1329 | 1371 | |
| 1330 | 1372 | sym = func_type->ref; |
| 1331 | − param_index = 0; | |
| 1332 | 1373 | reg_param_index = 0; |
| 1333 | 1374 | sse_param_index = 0; |
| 1334 | 1375 | |
| @@ -1338,10 +1379,7 @@ void gfunc_prolog(CType *func_type) · 3 unmodified lines | ||
| 1338 | 1379 | mode = classify_x86_64_arg(&func_vt, NULL, &size, ®_count); |
| 1339 | 1380 | if (mode == x86_64_mode_memory) { |
| 1340 | 1381 | push_arg_reg(reg_param_index); |
| 1341 | − param_addr = loc; | |
| 1342 | − | |
| 1343 | 1382 | func_vc = loc; |
| 1344 | − param_index++; | |
| 1345 | 1383 | reg_param_index++; |
| 1346 | 1384 | } |
| 1347 | 1385 | /* define parameters */ |
| @@ -1391,7 +1429,6 @@ void gfunc_prolog(CType *func_type) · 43 unmodified lines | ||
| 1391 | 1429 | } |
| 1392 | 1430 | sym_push(sym->v & ~SYM_FIELD, type, |
| 1393 | 1431 | VT_LOCAL | VT_LVAL, param_addr); |
| 1394 | − param_index++; | |
| 1395 | 1432 | } |
| 1396 | 1433 | } |
| 1397 | 1434 | |