From 5c35ba66c5ade4713bbd9c005e66889f6d7db293 Mon Sep 17 00:00:00 2001 From: James Lyon Date: Wed, 24 Apr 2013 02:19:15 +0100 Subject: [PATCH] 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). --- CMakeLists.txt | 28 +++--- config.h.in | 21 ++--- include/stdarg.h | 6 +- tccgen.c | 28 +++++- tcctok.h | 4 + tests/CMakeLists.txt | 4 +- tests/abitest.c | 107 ++++++++++++++++++++-- x86_64-gen.c | 249 +++++++++++++++++++++++++++++---------------------- 8 files changed, 300 insertions(+), 147 deletions(-) rewrite config.h.in (66%) diff --git a/CMakeLists.txt b/CMakeLists.txt index c055ab6a..12fda70d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,32 +46,36 @@ set(I386_SOURCES i386-gen.c i386-asm.c i386-asm.h i386-tok.h) set(X86_64_SOURCES x86_64-gen.c i386-asm.c x86_64-asm.h) if(TCC_TARGET STREQUAL "Win32") - set(TCC_TARGET_I386 ON) - set(TCC_TARGET_PE ON) + set(TCC_TARGET_FLAGS -DTCC_TARGET_I386 -DTCC_TARGET_PE) set(LIBTCC_TARGET_SOURCES ${I386_SOURCES} tccpe.c) elseif(TCC_TARGET STREQUAL "Win64") - set(TCC_TARGET_PE ON) - set(TCC_TARGET_X86_64 ON) + set(TCC_TARGET_FLAGS -DTCC_TARGET_X86_64 -DTCC_TARGET_PE) set(LIBTCC_TARGET_SOURCES ${X86_64_SOURCES} tccpe.c) elseif(TCC_TARGET STREQUAL "WinCE") - set(TCC_TARGET_ARM ON) + set(TCC_TARGET_FLAGS -DTCC_TARGET_ARM + -DTCC_ARM_VERSION=${TCC_ARM_VERSION}) set(LIBTCC_TARGET_SOURCES arm-gen.c tccpe.c) elseif(TCC_TARGET STREQUAL "i386") - set(TCC_TARGET_I386 ON) + set(TCC_TARGET_FLAGS -DTCC_TARGET_I386) set(LIBTCC_TARGET_SOURCES ${I386_SOURCES}) elseif(TCC_TARGET STREQUAL "x86-64") - set(TCC_TARGET_X86_64 ON) + set(TCC_TARGET_FLAGS -DTCC_TARGET_X86_64) set(LIBTCC_TARGET_SOURCES ${X86_64_SOURCES}) elseif(TCC_TARGET STREQUAL "ARM") - set(TCC_TARGET_ARM ON) + set(TCC_TARGET_FLAGS -DTCC_TARGET_ARM + -DTCC_ARM_VERSION=${TCC_ARM_VERSION} + -DTCC_ARM_EABI=${TCC_ARM_EABI} + -DTCC_ARM_VFP=${TCC_ARM_VFP} + -DTCC_ARM_HARDFLOAT=${TCC_ARM_HARDFLOAT}) set(LIBTCC_TARGET_SOURCES arm-gen.c) elseif(TCC_TARGET STREQUAL "C67") - set(TCC_TARGET_C67 ON) + set(TCC_TARGET_FLAGS -DTCC_TARGET_C67) set(LIBTCC_TARGET_SOURCES c67-gen.c tcccoff.c) else() message(FATAL_ERROR "Unrecognised target in TCC_TARGET, must be one of ${TCC_TARGET_LIST}") endif() +add_definitions(${TCC_TARGET_FLAGS}) file(STRINGS "VERSION" TCC_VERSION) list(GET TCC_VERSION 0 TCC_VERSION) include_directories(${CMAKE_BINARY_DIR}) @@ -86,7 +90,7 @@ set_target_properties(libtcc PROPERTIES PREFIX "") add_executable(tcc tcc.c) target_link_libraries(tcc libtcc) -set(TCC_CFLAGS -I${CMAKE_SOURCE_DIR}/include) +set(TCC_CFLAGS -I${CMAKE_SOURCE_DIR}/include ${CMAKE_C_FLAGS}) if(TCC_TARGET MATCHES "^Win") set(TCC_CFLAGS ${TCC_CFLAGS} -I${CMAKE_SOURCE_DIR}/win32/include) endif() @@ -108,7 +112,7 @@ elseif(TCC_TARGET STREQUAL "x86-64") endif() if (TCC_TARGET MATCHES "^Win") - set(XCC tcc ${TCC_CFLAGS} -B${CMAKE_SOURCE_DIR}/win32) + set(XCC tcc ${TCC_CFLAGS} ${TCC_TARGET_FLAGS} -B${CMAKE_SOURCE_DIR}/win32) set(XAR tiny_libmaker${CMAKE_EXECUTABLE_SUFFIX}) set(XDEPENDS tiny_libmaker) endif() @@ -119,7 +123,7 @@ if(LIBTCC1_SOURCES) string(REGEX MATCH "[^/]+$" LIBTCC1_O ${LIBTCC1_C}) string(REGEX MATCH "^[^.]+" LIBTCC1_O ${LIBTCC1_O}) set(LIBTCC1_O ${LIBTCC1_O}.o) - add_custom_command(OUTPUT ${LIBTCC1_O} COMMAND ${XCC} -c ${CMAKE_SOURCE_DIR}/${LIBTCC1_C} -o ${LIBTCC1_O}) + add_custom_command(OUTPUT ${LIBTCC1_O} COMMAND ${XCC} -c ${CMAKE_SOURCE_DIR}/${LIBTCC1_C} -o ${LIBTCC1_O} DEPENDS ${CMAKE_SOURCE_DIR}/${LIBTCC1_C}) list(APPEND LIBTCC1_OBJECTS ${LIBTCC1_O}) endforeach() add_custom_command(OUTPUT libtcc1.a COMMAND ${XAR} libtcc1.a ${LIBTCC1_OBJECTS} DEPENDS ${LIBTCC1_OBJECTS} ${XDEPENDS}) diff --git a/config.h.in b/config.h.in dissimilarity index 66% index 63b8151a..588408db 100644 --- a/config.h.in +++ b/config.h.in @@ -1,16 +1,5 @@ -#define CONFIG_TCCDIR "${CMAKE_INSTALL_PREFIX}" -#define TCC_VERSION "${TCC_VERSION}" - -#cmakedefine CONFIG_WIN32 -#cmakedefine CONFIG_WIN64 - -#cmakedefine TCC_TARGET_I386 -#cmakedefine TCC_TARGET_X86_64 -#cmakedefine TCC_TARGET_ARM -#cmakedefine TCC_TARGET_C67 - -#cmakedefine TCC_TARGET_PE -#define TCC_ARM_VERSION ${TCC_ARM_VERSION} -#cmakedefine TCC_ARM_VFP -#cmakedefine TCC_ARM_EABI -#cmakedefine TCC_ARM_HARDFLOAT +#define CONFIG_TCCDIR "${CMAKE_INSTALL_PREFIX}" +#define TCC_VERSION "${TCC_VERSION}" + +#cmakedefine CONFIG_WIN32 +#cmakedefine CONFIG_WIN64 diff --git a/include/stdarg.h b/include/stdarg.h index 666adf76..154030ff 100644 --- a/include/stdarg.h +++ b/include/stdarg.h @@ -19,9 +19,9 @@ void __va_end(va_list ap); #else /* _WIN64 */ typedef char *va_list; -#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+7)&~7) -#define va_arg(ap,type) (ap += (sizeof(type)+7)&~7, *(type *)(ap - ((sizeof(type)+7)&~7))) -#define va_copy(dest, src) (dest) = (src) +#define va_start(ap,last) __builtin_va_start(ap,last) +#define va_arg(ap,type) (ap += 8, sizeof(type)<=8 ? *(type*)ap : **(type**)ap) +#define va_copy(dest, src) ((dest) = (src)) #define va_end(ap) #endif diff --git a/tccgen.c b/tccgen.c index d8972960..0d1e21b4 100644 --- a/tccgen.c +++ b/tccgen.c @@ -851,7 +851,13 @@ ST_FUNC int gv(int rc) t = vtop->type.t; t1 = t; /* compute memory access type */ - if (vtop->r & VT_LVAL_BYTE) + if (vtop->r & VT_REF) +#ifdef TCC_TARGET_X86_64 + t = VT_PTR; +#else + t = VT_INT; +#endif + else if (vtop->r & VT_LVAL_BYTE) t = VT_BYTE; else if (vtop->r & VT_LVAL_SHORT) t = VT_SHORT; @@ -3712,7 +3718,24 @@ ST_FUNC void unary(void) } } break; -#if defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_PE) +#ifdef TCC_TARGET_X86_64 +#ifdef TCC_TARGET_PE + case TOK_builtin_va_start: + { + next(); + skip('('); + expr_eq(); + skip(','); + expr_eq(); + skip(')'); + if ((vtop->r & VT_VALMASK) != VT_LOCAL) + tcc_error("__builtin_va_start expects a local variable"); + vtop->r &= ~(VT_LVAL | VT_REF); + vtop->type = char_pointer_type; + vstore(); + } + break; +#else case TOK_builtin_va_arg_types: { CType type; @@ -3725,6 +3748,7 @@ ST_FUNC void unary(void) } break; #endif +#endif case TOK_INC: case TOK_DEC: t = tok; diff --git a/tcctok.h b/tcctok.h index f754af57..fde13dd5 100644 --- a/tcctok.h +++ b/tcctok.h @@ -125,8 +125,12 @@ DEF(TOK_builtin_constant_p, "__builtin_constant_p") DEF(TOK_builtin_frame_address, "__builtin_frame_address") #ifdef TCC_TARGET_X86_64 +#ifdef TCC_TARGET_PE + DEF(TOK_builtin_va_start, "__builtin_va_start") +#else DEF(TOK_builtin_va_arg_types, "__builtin_va_arg_types") #endif +#endif DEF(TOK_REGPARM1, "regparm") DEF(TOK_REGPARM2, "__regparm__") diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 22a35521..684e809a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -6,7 +6,7 @@ add_test(NAME abitest-cc WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND abitest-c set(ABITEST_TCC abitest-tcc${CMAKE_EXECUTABLE_SUFFIX}) get_property(LIBTCC_LIB TARGET libtcc PROPERTY LOCATION) -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) +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) add_custom_target(abitest-tcc-exe ALL DEPENDS ${ABITEST_TCC}) 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) set(TCC_TEST_CFLAGS ${TCC_TEST_CFLAGS} -I${CMAKE_SOURCE_DIR}/win32/include/winapi) endif() set(TCC_TEST_SOURCE ${TCC_TEST_CFLAGS} -run ${CMAKE_CURRENT_SOURCE_DIR}/tcctest.c) -set(TCC_TEST_RUN ${TCC_TEST_CFLAGS} -DONE_SOURCE -run ${CMAKE_SOURCE_DIR}/tcc.c) +set(TCC_TEST_RUN ${TCC_TEST_CFLAGS} ${TCC_TARGET_FLAGS} -DONE_SOURCE -run ${CMAKE_SOURCE_DIR}/tcc.c) add_custom_command(OUTPUT tcctest.ref COMMAND tcctest-cc > tcctest.ref) add_custom_command(OUTPUT tcctest.1 COMMAND tcc ${TCC_TEST_SOURCE} > tcctest.1) diff --git a/tests/abitest.c b/tests/abitest.c index 3064fa5a..a51eb9b5 100644 --- a/tests/abitest.c +++ b/tests/abitest.c @@ -263,40 +263,132 @@ static int two_member_union_test(void) { } /* + * Win64 calling convetntion test. + */ + +typedef struct many_struct_test_type_s {long long a, b, c;} many_struct_test_type; +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); + +static int many_struct_test_callback(void *ptr) { + many_struct_test_function_type f = (many_struct_test_function_type)ptr; + many_struct_test_type v = {1, 2, 3}; + many_struct_test_type r = f(v,v,v,v,v,v); + return ((r.a == 6) && (r.b == 12) && (r.c == 18))?0:-1; +} + +static int many_struct_test(void) { + const char *src = + "typedef struct many_struct_test_type_s {long long a, b, c;} many_struct_test_type;\n" + "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" + " many_struct_test_type y;\n" + " y.a = x1.a + x2.a + x3.a + x4.a + x5.a + x6.a;\n" + " y.b = x1.b + x2.b + x3.b + x4.b + x5.b + x6.b;\n" + " y.c = x1.c + x2.c + x3.c + x4.c + x5.c + x6.c;\n" + " return y;\n" + "}\n"; + return run_callback(src, many_struct_test_callback); +} + +/* + * Win64 calling convention test. + */ + +typedef struct many_struct_test_2_type_s {int a, b;} many_struct_test_2_type; +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); + +static int many_struct_test_2_callback(void *ptr) { + many_struct_test_2_function_type f = (many_struct_test_2_function_type)ptr; + many_struct_test_2_type v = {1,2}; + many_struct_test_2_type r = f(v,v,v,v,v,v); + return ((r.a == 6) && (r.b == 12))?0:-1; +} + +static int many_struct_test_2(void) { + const char *src = + "typedef struct many_struct_test_2_type_s {int a, b;} many_struct_test_2_type;\n" + "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" + " many_struct_test_2_type y;\n" + " y.a = x1.a + x2.a + x3.a + x4.a + x5.a + x6.a;\n" + " y.b = x1.b + x2.b + x3.b + x4.b + x5.b + x6.b;\n" + " return y;\n" + "}\n"; + return run_callback(src, many_struct_test_2_callback); +} + +/* * stdarg_test: Test variable argument list ABI */ -typedef void (*stdarg_test_function_type) (int,int,...); +typedef struct {long long a, b, c;} stdarg_test_struct_type; +typedef void (*stdarg_test_function_type) (int,int,int,...); static int stdarg_test_callback(void *ptr) { stdarg_test_function_type f = (stdarg_test_function_type)ptr; int x; double y; - f(10, 10, + stdarg_test_struct_type z = {1, 2, 3}, w; + f(10, 10, 5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, &x, - 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, &y); - return ((x == 55) && (y == 55)) ? 0 : -1; + 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, &y, + z, z, z, z, z, &w); + return ((x == 55) && (y == 55) && (w.a == 5) && (w.b == 10) && (w.c == 15)) ? 0 : -1; } static int stdarg_test(void) { const char *src = "#include \n" - "void f(int n_int, int n_float, ...) {\n" + "typedef struct {long long a, b, c;} stdarg_test_struct_type;\n" + "void f(int n_int, int n_float, int n_struct, ...) {\n" " int i, ti;\n" " double td;\n" + " stdarg_test_struct_type ts = {0,0,0}, tmp;\n" " va_list ap;\n" - " va_start(ap, n_float);\n" + " va_start(ap, n_struct);\n" " for (i = 0, ti = 0; i < n_int; ++i)\n" " ti += va_arg(ap, int);\n" " *va_arg(ap, int*) = ti;\n" " for (i = 0, td = 0; i < n_float; ++i)\n" " td += va_arg(ap, double);\n" " *va_arg(ap, double*) = td;\n" + " for (i = 0; i < n_struct; ++i) {\n" + " tmp = va_arg(ap, stdarg_test_struct_type);\n" + " ts.a += tmp.a; ts.b += tmp.b; ts.c += tmp.c;" + " }\n" + " *va_arg(ap, stdarg_test_struct_type*) = ts;\n" " va_end(ap);" "}\n"; return run_callback(src, stdarg_test_callback); } +/* + * Test Win32 stdarg handling, since the calling convention will pass a pointer + * to the struct and the stdarg pointer must point to that pointer initially. + */ + +typedef struct {long long a, b, c;} stdarg_struct_test_struct_type; +typedef int (*stdarg_struct_test_function_type) (stdarg_struct_test_struct_type a, ...); + +static int stdarg_struct_test_callback(void *ptr) { + stdarg_struct_test_function_type f = (stdarg_struct_test_function_type)ptr; + stdarg_struct_test_struct_type v = {10, 35, 99}; + int x = f(v, 234); + return (x == 378) ? 0 : -1; +} + +static int stdarg_struct_test(void) { + const char *src = + "#include \n" + "typedef struct {long long a, b, c;} stdarg_struct_test_struct_type;\n" + "int f(stdarg_struct_test_struct_type a, ...) {\n" + " va_list ap;\n" + " va_start(ap, a);\n" + " int z = va_arg(ap, int);\n" + " va_end(ap);\n" + " return z + a.a + a.b + a.c;\n" + "}\n"; + return run_callback(src, stdarg_struct_test_callback); +} + #define RUN_TEST(t) \ if (!testname || (strcmp(#t, testname) == 0)) { \ fputs(#t "... ", stdout); \ @@ -336,6 +428,9 @@ int main(int argc, char **argv) { RUN_TEST(sret_test); RUN_TEST(one_member_union_test); RUN_TEST(two_member_union_test); + RUN_TEST(many_struct_test); + RUN_TEST(many_struct_test_2); RUN_TEST(stdarg_test); + RUN_TEST(stdarg_struct_test); return retval; } diff --git a/x86_64-gen.c b/x86_64-gen.c index 4b9d28d7..1cf3bbca 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -23,7 +23,7 @@ #ifdef TARGET_DEFS_ONLY /* number of available registers */ -#define NB_REGS 24 +#define NB_REGS 22 #define NB_ASM_REGS 8 /* a register can belong to several classes. The classes must be @@ -45,8 +45,6 @@ #define RC_XMM3 0x8000 #define RC_XMM4 0x10000 #define RC_XMM5 0x20000 -#define RC_XMM6 0x40000 -#define RC_XMM7 0x80000 #define RC_IRET RC_RAX /* function return: integer register */ #define RC_LRET RC_RDX /* function return: second integer register */ #define RC_FRET RC_XMM0 /* function return: float register */ @@ -142,9 +140,7 @@ ST_DATA const int reg_classes[NB_REGS] = { /* xmm2 */ RC_FLOAT | RC_XMM2, /* xmm3 */ RC_FLOAT | RC_XMM3, /* xmm4 */ RC_FLOAT | RC_XMM4, - /* xmm5 */ RC_FLOAT | RC_XMM5, - /* xmm6 */ RC_FLOAT | RC_XMM6, - /* xmm7 */ RC_FLOAT | RC_XMM7, + /* xmm5 */ RC_FLOAT | RC_XMM5 /* only up to xmm5: xmm6-15 must be callee saved on Win64 */ }; static unsigned long func_sub_sp_offset; @@ -484,7 +480,7 @@ void load(int r, SValue *sv) orex(0,r,0,0); oad(0xb8 + REG_VALUE(r), t ^ 1); /* mov $0, r */ } else if (v != r) { - if ((r == TREG_XMM0) || (r == TREG_XMM1)) { + if ((r >= TREG_XMM0) && (r <= TREG_XMM7)) { if (v == TREG_ST0) { /* gen_cvt_ftof(VT_DOUBLE); */ o(0xf0245cdd); /* fstpl -0x10(%rsp) */ @@ -493,7 +489,7 @@ void load(int r, SValue *sv) o(0x44 + REG_VALUE(r)*8); /* %xmmN */ o(0xf024); } else { - assert((v == TREG_XMM0) || (v == TREG_XMM1)); + assert((v >= TREG_XMM0) && (v <= TREG_XMM7)); if ((ft & VT_BTYPE) == VT_FLOAT) { o(0x100ff3); } else { @@ -626,10 +622,20 @@ static void gcall_or_jmp(int is_jmp) #ifdef TCC_TARGET_PE #define REGN 4 -static const uint8_t arg_regs[] = { +static const uint8_t arg_regs[REGN] = { TREG_RCX, TREG_RDX, TREG_R8, TREG_R9 }; +/* Prepare arguments in R10 and R11 rather than RCX and RDX + because gv() will not ever use these */ +static int arg_prepare_reg(int idx) { + if (idx == 0 || idx == 1) + /* idx=0: r10, idx=1: r11 */ + return idx + 10; + else + return arg_regs[idx]; +} + static int func_scratch; /* Generate function call. The function address is pushed first, then @@ -651,26 +657,56 @@ void gen_offs_sp(int b, int r, int d) /* Return 1 if this function returns via an sret pointer, 0 otherwise */ ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) { *ret_align = 1; // Never have to re-align return values for x86-64 - return 1; + int size, align; + size = type_size(vt, &align); + ret->ref = NULL; + if (size > 8) { + return 1; + } else if (size > 4) { + ret->t = VT_LLONG; + return 0; + } else if (size > 2) { + ret->t = VT_INT; + return 0; + } else if (size > 1) { + ret->t = VT_SHORT; + return 0; + } else { + ret->t = VT_BYTE; + return 0; + } +} + +int gfunc_arg_size(CType *type) { + if (type->t & (VT_ARRAY|VT_BITFIELD)) + return 8; + int align; + return type_size(type, &align); } void gfunc_call(int nb_args) { - int size, align, r, args_size, i, d, j, bt, struct_size; - int nb_reg_args, gen_reg; + int size, r, args_size, i, d, bt, struct_size; + int arg; - nb_reg_args = nb_args; - args_size = (nb_reg_args < REGN ? REGN : nb_reg_args) * PTR_SIZE; + args_size = (nb_args < REGN ? REGN : nb_args) * PTR_SIZE; + arg = nb_args; /* for struct arguments, we need to call memcpy and the function call breaks register passing arguments we are preparing. So, we process arguments which will be passed by stack first. */ struct_size = args_size; for(i = 0; i < nb_args; i++) { + --arg; + SValue *sv = &vtop[-i]; bt = (sv->type.t & VT_BTYPE); + size = gfunc_arg_size(&sv->type); + + if (size <= 8) + continue; /* arguments smaller than 8 bytes passed in registers or on stack */ + if (bt == VT_STRUCT) { - size = type_size(&sv->type, &align); /* align to stack align size */ size = (size + 15) & ~15; /* generate structure store */ @@ -683,85 +719,81 @@ void gfunc_call(int nb_args) vpushv(sv); vstore(); --vtop; - } else if (bt == VT_LDOUBLE) { - gv(RC_ST0); gen_offs_sp(0xdb, 0x107, struct_size); struct_size += 16; - } } if (func_scratch < struct_size) func_scratch = struct_size; -#if 1 - for (i = 0; i < REGN; ++i) - save_reg(arg_regs[i]); - save_reg(TREG_RAX); -#endif - gen_reg = nb_reg_args; + + arg = nb_args; struct_size = args_size; for(i = 0; i < nb_args; i++) { + --arg; bt = (vtop->type.t & VT_BTYPE); - if (bt == VT_STRUCT || bt == VT_LDOUBLE) { - if (bt == VT_LDOUBLE) - size = 16; - else - size = type_size(&vtop->type, &align); + size = gfunc_arg_size(&vtop->type); + if (size > 8) { /* align to stack align size */ size = (size + 15) & ~15; - j = --gen_reg; - if (j >= REGN) { - d = TREG_RAX; + if (arg >= REGN) { + d = get_reg(RC_INT); gen_offs_sp(0x8d, d, struct_size); - gen_offs_sp(0x89, d, j*8); + gen_offs_sp(0x89, d, arg*8); } else { - d = arg_regs[j]; + d = arg_prepare_reg(arg); gen_offs_sp(0x8d, d, struct_size); } struct_size += size; - - } else if (is_sse_float(vtop->type.t)) { - gv(RC_XMM0); /* only one float register */ - j = --gen_reg; - if (j >= REGN) { - /* movq %xmm0, j*8(%rsp) */ - gen_offs_sp(0xd60f66, 0x100, j*8); - } else { - /* movaps %xmm0, %xmmN */ - o(0x280f); - o(0xc0 + (j << 3)); - d = arg_regs[j]; - /* mov %xmm0, %rxx */ - o(0x66); - orex(1,d,0, 0x7e0f); - o(0xc0 + REG_VALUE(d)); - } } else { - j = --gen_reg; - if (j >= REGN) { - r = gv(RC_INT); - gen_offs_sp(0x89, r, j*8); + if (is_sse_float(vtop->type.t)) { + gv(RC_XMM0); /* only use one float register */ + if (arg >= REGN) { + /* movq %xmm0, j*8(%rsp) */ + gen_offs_sp(0xd60f66, 0x100, arg*8); + } else { + /* movaps %xmm0, %xmmN */ + o(0x280f); + o(0xc0 + (arg << 3)); + d = arg_prepare_reg(arg); + /* mov %xmm0, %rxx */ + o(0x66); + orex(1,d,0, 0x7e0f); + o(0xc0 + REG_VALUE(d)); + } } else { - d = arg_regs[j]; - if (d < NB_REGS) { - gv(reg_classes[d] & ~RC_INT); + if (bt == VT_STRUCT) { + vtop->type.ref = NULL; + vtop->type.t = size > 4 ? VT_LLONG : size > 2 ? VT_INT + : size > 1 ? VT_SHORT : VT_BYTE; + } + + r = gv(RC_INT); + if (arg >= REGN) { + gen_offs_sp(0x89, r, arg*8); } else { - r = gv(RC_INT); - if (d != r) { - orex(1,d,r, 0x89); - o(0xc0 + REG_VALUE(d) + REG_VALUE(r) * 8); - } + d = arg_prepare_reg(arg); + orex(1,d,r,0x89); /* mov */ + o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d)); } - } } vtop--; } save_regs(0); + + /* Copy R10 and R11 into RCX and RDX, respectively */ + if (nb_args > 0) { + o(0xd1894c); /* mov %r10, %rcx */ + if (nb_args > 1) { + o(0xda894c); /* mov %r11, %rdx */ + } + } + gcall_or_jmp(0); vtop--; } @@ -772,7 +804,7 @@ void gfunc_call(int nb_args) /* generate function prolog of type 't' */ void gfunc_prolog(CType *func_type) { - int addr, reg_param_index, bt; + int addr, reg_param_index, bt, size; Sym *sym; CType *type; @@ -790,34 +822,46 @@ void gfunc_prolog(CType *func_type) /* if the function returns a structure, then add an implicit pointer parameter */ func_vt = sym->type; - if ((func_vt.t & VT_BTYPE) == VT_STRUCT) { + size = gfunc_arg_size(&func_vt); + if (size > 8) { gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); + func_vc = addr; reg_param_index++; - addr += PTR_SIZE; + addr += 8; } /* define parameters */ while ((sym = sym->next) != NULL) { type = &sym->type; bt = type->t & VT_BTYPE; - if (reg_param_index < REGN) { - /* save arguments passed by register */ - gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); - } - if (bt == VT_STRUCT || bt == VT_LDOUBLE) { + size = gfunc_arg_size(type); + if (size > 8) { + if (reg_param_index < REGN) { + gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); + } sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL | VT_REF, addr); } else { + if (reg_param_index < REGN) { + /* save arguments passed by register */ + if ((bt == VT_FLOAT) || (bt == VT_DOUBLE)) { + o(0xd60f66); /* movq */ + gen_modrm(reg_param_index, VT_LOCAL, NULL, addr); + } else { + gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); + } + } sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr); } + addr += 8; reg_param_index++; - addr += PTR_SIZE; } while (reg_param_index < REGN) { - if (func_type->ref->c == FUNC_ELLIPSIS) + if (func_type->ref->c == FUNC_ELLIPSIS) { gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); + addr += 8; + } reg_param_index++; - addr += PTR_SIZE; } } @@ -1072,13 +1116,13 @@ void gfunc_call(int nb_args) } for(i = 0; i < nb_args;) { - /* Swap argument to top, it will possibly be changed here, - and might use more temps. At the end of the loop we keep - in on the stack and swap it back to its original position - if it is a register. */ + /* Swap argument to top, it will possibly be changed here, + and might use more temps. At the end of the loop we keep + in on the stack and swap it back to its original position + if it is a register. */ SValue tmp = vtop[0]; - vtop[0] = vtop[-i]; - vtop[-i] = tmp; + vtop[0] = vtop[-i]; + vtop[-i] = tmp; mode = classify_x86_64_arg(&vtop->type, NULL, &size, ®_count); @@ -1183,23 +1227,23 @@ void gfunc_call(int nb_args) /* Alter stack entry type so that gv() knows how to treat it */ vtop->type = type; if (mode == x86_64_mode_sse) { - if (reg_count == 2) { - sse_reg -= 2; - gv(RC_FRET); /* Use pair load into xmm0 & xmm1 */ - if (sse_reg) { /* avoid redundant movaps %xmm0, %xmm0 */ - /* movaps %xmm0, %xmmN */ - o(0x280f); - o(0xc0 + (sse_reg << 3)); - /* movaps %xmm1, %xmmN */ - o(0x280f); - o(0xc1 + ((sse_reg+1) << 3)); - } - } else { - assert(reg_count == 1); - --sse_reg; - /* Load directly to register */ - gv(RC_XMM0 << sse_reg); - } + if (reg_count == 2) { + sse_reg -= 2; + gv(RC_FRET); /* Use pair load into xmm0 & xmm1 */ + if (sse_reg) { /* avoid redundant movaps %xmm0, %xmm0 */ + /* movaps %xmm0, %xmmN */ + o(0x280f); + o(0xc0 + (sse_reg << 3)); + /* movaps %xmm1, %xmmN */ + o(0x280f); + o(0xc1 + ((sse_reg+1) << 3)); + } + } else { + assert(reg_count == 1); + --sse_reg; + /* Load directly to register */ + gv(RC_XMM0 << sse_reg); + } } else if (mode == x86_64_mode_integer) { /* simple type */ /* XXX: implicit cast ? */ @@ -1209,8 +1253,6 @@ void gfunc_call(int nb_args) orex(1,d,r,0x89); /* mov */ o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d)); if (reg_count == 2) { - /* Second word of two-word value should always be in rdx - this case is handled via RC_IRET */ d = arg_prepare_reg(gen_reg+1); orex(1,d,vtop->r2,0x89); /* mov */ o(0xc0 + REG_VALUE(vtop->r2) * 8 + REG_VALUE(d)); @@ -1255,7 +1297,7 @@ void gfunc_prolog(CType *func_type) { X86_64_Mode mode; int i, addr, align, size, reg_count; - int param_index, param_addr, reg_param_index, sse_param_index; + int param_addr, reg_param_index, sse_param_index; Sym *sym; CType *type; @@ -1328,7 +1370,6 @@ void gfunc_prolog(CType *func_type) } sym = func_type->ref; - param_index = 0; reg_param_index = 0; sse_param_index = 0; @@ -1338,10 +1379,7 @@ void gfunc_prolog(CType *func_type) mode = classify_x86_64_arg(&func_vt, NULL, &size, ®_count); if (mode == x86_64_mode_memory) { push_arg_reg(reg_param_index); - param_addr = loc; - func_vc = loc; - param_index++; reg_param_index++; } /* define parameters */ @@ -1391,7 +1429,6 @@ void gfunc_prolog(CType *func_type) } sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, param_addr); - param_index++; } } -- 2.11.4.GIT