History

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

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

James Lyon committed 13 years ago

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

Unified · Split

8 files
  1. CMakeLists.txt +16 −12
  2. config.h.in +0 −11
  3. include/stdarg.h +3 −3
  4. tccgen.c +26 −2
  5. tcctok.h +4 −0
  6. tests/CMakeLists.txt +2 −2
  7. tests/abitest.c +101 −6
  8. x86_64-gen.c +143 −106
CMakeLists.txt+16−12
@@ -46,32 +46,36 @@ set(I386_SOURCES i386-gen.c i386-asm.c i386-asm.h i386-tok.h) · 45 unmodified lines
4646 set(X86_64_SOURCES x86_64-gen.c i386-asm.c x86_64-asm.h)
4747
4848 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)
5150 set(LIBTCC_TARGET_SOURCES ${I386_SOURCES} tccpe.c)
5251 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)
5553 set(LIBTCC_TARGET_SOURCES ${X86_64_SOURCES} tccpe.c)
5654 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})
5857 set(LIBTCC_TARGET_SOURCES arm-gen.c tccpe.c)
5958 elseif(TCC_TARGET STREQUAL "i386")
60− set(TCC_TARGET_I386 ON)
59+ set(TCC_TARGET_FLAGS -DTCC_TARGET_I386)
6160 set(LIBTCC_TARGET_SOURCES ${I386_SOURCES})
6261 elseif(TCC_TARGET STREQUAL "x86-64")
63− set(TCC_TARGET_X86_64 ON)
62+ set(TCC_TARGET_FLAGS -DTCC_TARGET_X86_64)
6463 set(LIBTCC_TARGET_SOURCES ${X86_64_SOURCES})
6564 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})
6770 set(LIBTCC_TARGET_SOURCES arm-gen.c)
6871 elseif(TCC_TARGET STREQUAL "C67")
69− set(TCC_TARGET_C67 ON)
72+ set(TCC_TARGET_FLAGS -DTCC_TARGET_C67)
7073 set(LIBTCC_TARGET_SOURCES c67-gen.c tcccoff.c)
7174 else()
7275 message(FATAL_ERROR "Unrecognised target in TCC_TARGET, must be one of ${TCC_TARGET_LIST}")
7376 endif()
7477
78+add_definitions(${TCC_TARGET_FLAGS})
7579 file(STRINGS "VERSION" TCC_VERSION)
7680 list(GET TCC_VERSION 0 TCC_VERSION)
7781 include_directories(${CMAKE_BINARY_DIR})
@@ -86,7 +90,7 @@ set_target_properties(libtcc PROPERTIES PREFIX "") · 8 unmodified lines
8690
8791 add_executable(tcc tcc.c)
8892 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})
9094 if(TCC_TARGET MATCHES "^Win")
9195 set(TCC_CFLAGS ${TCC_CFLAGS} -I${CMAKE_SOURCE_DIR}/win32/include)
9296 endif()
@@ -108,7 +112,7 @@ elseif(TCC_TARGET STREQUAL "x86-64") · 15 unmodified lines
108112 endif()
109113
110114 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)
112116 set(XAR tiny_libmaker${CMAKE_EXECUTABLE_SUFFIX})
113117 set(XDEPENDS tiny_libmaker)
114118 endif()
@@ -119,7 +123,7 @@ if(LIBTCC1_SOURCES) · 4 unmodified lines
119123 string(REGEX MATCH "[^/]+$" LIBTCC1_O ${LIBTCC1_C})
120124 string(REGEX MATCH "^[^.]+" LIBTCC1_O ${LIBTCC1_O})
121125 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})
123127 list(APPEND LIBTCC1_OBJECTS ${LIBTCC1_O})
124128 endforeach()
125129 add_custom_command(OUTPUT libtcc1.a COMMAND ${XAR} libtcc1.a ${LIBTCC1_OBJECTS} DEPENDS ${LIBTCC1_OBJECTS} ${XDEPENDS})
config.h.in+0−11
@@ -3,14 +3,3 @@ · 2 unmodified lines
33
44 #cmakedefine CONFIG_WIN32
55 #cmakedefine CONFIG_WIN64
6−
7−#cmakedefine TCC_TARGET_I386
8−#cmakedefine TCC_TARGET_X86_64
9−#cmakedefine TCC_TARGET_ARM
10−#cmakedefine TCC_TARGET_C67
11−
12−#cmakedefine TCC_TARGET_PE
13−#define TCC_ARM_VERSION ${TCC_ARM_VERSION}
14−#cmakedefine TCC_ARM_VFP
15−#cmakedefine TCC_ARM_EABI
16−#cmakedefine TCC_ARM_HARDFLOAT
include/stdarg.h+3−3
@@ -19,9 +19,9 @@ void __va_end(va_list ap); · 18 unmodified lines
1919
2020 #else /* _WIN64 */
2121 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))
2525 #define va_end(ap)
2626 #endif
2727
tccgen.c+26−2
@@ -851,7 +851,13 @@ ST_FUNC int gv(int rc) · 850 unmodified lines
851851 t = vtop->type.t;
852852 t1 = t;
853853 /* 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)
855861 t = VT_BYTE;
856862 else if (vtop->r & VT_LVAL_SHORT)
857863 t = VT_SHORT;
@@ -3712,7 +3718,24 @@ ST_FUNC void unary(void) · 2854 unmodified lines
37123718 }
37133719 }
37143720 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
37163739 case TOK_builtin_va_arg_types:
37173740 {
37183741 CType type;
@@ -3724,6 +3747,7 @@ ST_FUNC void unary(void) · 5 unmodified lines
37243747 vpushi(classify_x86_64_va_arg(&type));
37253748 }
37263749 break;
3750+#endif
37273751 #endif
37283752 case TOK_INC:
37293753 case TOK_DEC:
tcctok.h+4−0
@@ -125,7 +125,11 @@ · 124 unmodified lines
125125 DEF(TOK_builtin_constant_p, "__builtin_constant_p")
126126 DEF(TOK_builtin_frame_address, "__builtin_frame_address")
127127 #ifdef TCC_TARGET_X86_64
128+#ifdef TCC_TARGET_PE
129+ DEF(TOK_builtin_va_start, "__builtin_va_start")
130+#else
128131 DEF(TOK_builtin_va_arg_types, "__builtin_va_arg_types")
132+#endif
129133 #endif
130134 DEF(TOK_REGPARM1, "regparm")
131135 DEF(TOK_REGPARM2, "__regparm__")
tests/CMakeLists.txt+2−2
@@ -6,7 +6,7 @@ add_test(NAME abitest-cc WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND abitest-c · 5 unmodified lines
66
77 set(ABITEST_TCC abitest-tcc${CMAKE_EXECUTABLE_SUFFIX})
88 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)
1010 add_custom_target(abitest-tcc-exe ALL DEPENDS ${ABITEST_TCC})
1111
1212 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
2020 set(TCC_TEST_CFLAGS ${TCC_TEST_CFLAGS} -I${CMAKE_SOURCE_DIR}/win32/include/winapi)
2121 endif()
2222 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)
2424
2525 add_custom_command(OUTPUT tcctest.ref COMMAND tcctest-cc > tcctest.ref)
2626 add_custom_command(OUTPUT tcctest.1 COMMAND tcc ${TCC_TEST_SOURCE} > tcctest.1)
tests/abitest.c+101−6
@@ -262,41 +262,133 @@ static int two_member_union_test(void) { · 261 unmodified lines
262262 return run_callback(src, two_member_union_test_callback);
263263 }
264264
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+
265318 /*
266319 * stdarg_test: Test variable argument list ABI
267320 */
268321
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,...);
270324
271325 static int stdarg_test_callback(void *ptr) {
272326 stdarg_test_function_type f = (stdarg_test_function_type)ptr;
273327 int x;
274328 double y;
275− f(10, 10,
329+ stdarg_test_struct_type z = {1, 2, 3}, w;
330+ f(10, 10, 5,
276331 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;
279335 }
280336
281337 static int stdarg_test(void) {
282338 const char *src =
283339 "#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"
285342 " int i, ti;\n"
286343 " double td;\n"
344+ " stdarg_test_struct_type ts = {0,0,0}, tmp;\n"
287345 " va_list ap;\n"
288− " va_start(ap, n_float);\n"
346+ " va_start(ap, n_struct);\n"
289347 " for (i = 0, ti = 0; i < n_int; ++i)\n"
290348 " ti += va_arg(ap, int);\n"
291349 " *va_arg(ap, int*) = ti;\n"
292350 " for (i = 0, td = 0; i < n_float; ++i)\n"
293351 " td += va_arg(ap, double);\n"
294352 " *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"
295358 " va_end(ap);"
296359 "}\n";
297360 return run_callback(src, stdarg_test_callback);
298361 }
299362
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+
300392 #define RUN_TEST(t) \
301393 if (!testname || (strcmp(#t, testname) == 0)) { \
302394 fputs(#t "... ", stdout); \
@@ -336,6 +428,9 @@ int main(int argc, char **argv) { · 33 unmodified lines
336428 RUN_TEST(sret_test);
337429 RUN_TEST(one_member_union_test);
338430 RUN_TEST(two_member_union_test);
431+ RUN_TEST(many_struct_test);
432+ RUN_TEST(many_struct_test_2);
339433 RUN_TEST(stdarg_test);
434+ RUN_TEST(stdarg_struct_test);
340435 return retval;
341436 }
x86_64-gen.c+143−106
@@ -23,7 +23,7 @@ · 22 unmodified lines
2323 #ifdef TARGET_DEFS_ONLY
2424
2525 /* number of available registers */
26−#define NB_REGS 24
26+#define NB_REGS 22
2727 #define NB_ASM_REGS 8
2828
2929 /* a register can belong to several classes. The classes must be
@@ -45,8 +45,6 @@ · 15 unmodified lines
4545 #define RC_XMM3 0x8000
4646 #define RC_XMM4 0x10000
4747 #define RC_XMM5 0x20000
48−#define RC_XMM6 0x40000
49−#define RC_XMM7 0x80000
5048 #define RC_IRET RC_RAX /* function return: integer register */
5149 #define RC_LRET RC_RDX /* function return: second integer register */
5250 #define RC_FRET RC_XMM0 /* function return: float register */
@@ -142,9 +140,7 @@ ST_DATA const int reg_classes[NB_REGS] = { · 89 unmodified lines
142140 /* xmm2 */ RC_FLOAT | RC_XMM2,
143141 /* xmm3 */ RC_FLOAT | RC_XMM3,
144142 /* 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 */
148144 };
149145
150146 static unsigned long func_sub_sp_offset;
@@ -484,7 +480,7 @@ void load(int r, SValue *sv) · 333 unmodified lines
484480 orex(0,r,0,0);
485481 oad(0xb8 + REG_VALUE(r), t ^ 1); /* mov $0, r */
486482 } else if (v != r) {
487− if ((r == TREG_XMM0) || (r == TREG_XMM1)) {
483+ if ((r >= TREG_XMM0) && (r <= TREG_XMM7)) {
488484 if (v == TREG_ST0) {
489485 /* gen_cvt_ftof(VT_DOUBLE); */
490486 o(0xf0245cdd); /* fstpl -0x10(%rsp) */
@@ -493,7 +489,7 @@ void load(int r, SValue *sv) · 2 unmodified lines
493489 o(0x44 + REG_VALUE(r)*8); /* %xmmN */
494490 o(0xf024);
495491 } else {
496− assert((v == TREG_XMM0) || (v == TREG_XMM1));
492+ assert((v >= TREG_XMM0) && (v <= TREG_XMM7));
497493 if ((ft & VT_BTYPE) == VT_FLOAT) {
498494 o(0x100ff3);
499495 } else {
@@ -626,10 +622,20 @@ static void gcall_or_jmp(int is_jmp) · 126 unmodified lines
626622 #ifdef TCC_TARGET_PE
627623
628624 #define REGN 4
629−static const uint8_t arg_regs[] = {
625+static const uint8_t arg_regs[REGN] = {
630626 TREG_RCX, TREG_RDX, TREG_R8, TREG_R9
631627 };
632628
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+
633639 static int func_scratch;
634640
635641 /* 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
651657 /* Return 1 if this function returns via an sret pointer, 0 otherwise */
652658 ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) {
653659 *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);
655685 }
656686
657687 void gfunc_call(int nb_args)
658688 {
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;
661691
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;
664694
665695 /* for struct arguments, we need to call memcpy and the function
666696 call breaks register passing arguments we are preparing.
667697 So, we process arguments which will be passed by stack first. */
668698 struct_size = args_size;
669699 for(i = 0; i < nb_args; i++) {
700+ --arg;
701+
670702 SValue *sv = &vtop[-i];
671703 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+
672709 if (bt == VT_STRUCT) {
673− size = type_size(&sv->type, &align);
674710 /* align to stack align size */
675711 size = (size + 15) & ~15;
676712 /* generate structure store */
@@ -683,85 +719,81 @@ void gfunc_call(int nb_args) · 6 unmodified lines
683719 vpushv(sv);
684720 vstore();
685721 --vtop;
686−
687722 } else if (bt == VT_LDOUBLE) {
688−
689723 gv(RC_ST0);
690724 gen_offs_sp(0xdb, 0x107, struct_size);
691725 struct_size += 16;
692−
693726 }
694727 }
695728
696729 if (func_scratch < struct_size)
697730 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;
704733 struct_size = args_size;
705734
706735 for(i = 0; i < nb_args; i++) {
736+ --arg;
707737 bt = (vtop->type.t & VT_BTYPE);
708738
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) {
714741 /* align to stack align size */
715742 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);
719745 gen_offs_sp(0x8d, d, struct_size);
720− gen_offs_sp(0x89, d, j*8);
746+ gen_offs_sp(0x89, d, arg*8);
721747 } else {
722− d = arg_regs[j];
748+ d = arg_prepare_reg(arg);
723749 gen_offs_sp(0x8d, d, struct_size);
724750 }
725751 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− }
743752 } 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+ }
748768 } 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);
752778 } 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));
758782 }
759−
760783 }
761784 }
762785 vtop--;
763786 }
764787 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+
765797 gcall_or_jmp(0);
766798 vtop--;
767799 }
@@ -772,7 +804,7 @@ void gfunc_call(int nb_args) · 4 unmodified lines
772804 /* generate function prolog of type 't' */
773805 void gfunc_prolog(CType *func_type)
774806 {
775− int addr, reg_param_index, bt;
807+ int addr, reg_param_index, bt, size;
776808 Sym *sym;
777809 CType *type;
778810
@@ -790,34 +822,46 @@ void gfunc_prolog(CType *func_type) · 11 unmodified lines
790822 /* if the function returns a structure, then add an
791823 implicit pointer parameter */
792824 func_vt = sym->type;
793− if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
825+ size = gfunc_arg_size(&func_vt);
826+ if (size > 8) {
794827 gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);
828+ func_vc = addr;
795829 reg_param_index++;
796− addr += PTR_SIZE;
830+ addr += 8;
797831 }
798832
799833 /* define parameters */
800834 while ((sym = sym->next) != NULL) {
801835 type = &sym->type;
802836 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+ }
808842 sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL | VT_REF, addr);
809843 } 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+ }
810853 sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr);
811854 }
855+ addr += 8;
812856 reg_param_index++;
813− addr += PTR_SIZE;
814857 }
815858
816859 while (reg_param_index < REGN) {
817− if (func_type->ref->c == FUNC_ELLIPSIS)
860+ if (func_type->ref->c == FUNC_ELLIPSIS) {
818861 gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);
862+ addr += 8;
863+ }
819864 reg_param_index++;
820− addr += PTR_SIZE;
821865 }
822866 }
823867
@@ -1072,13 +1116,13 @@ void gfunc_call(int nb_args) · 248 unmodified lines
10721116 }
10731117
10741118 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. */
10791123 SValue tmp = vtop[0];
1080− vtop[0] = vtop[-i];
1081− vtop[-i] = tmp;
1124+ vtop[0] = vtop[-i];
1125+ vtop[-i] = tmp;
10821126
10831127 mode = classify_x86_64_arg(&vtop->type, NULL, &size, &reg_count);
10841128
@@ -1183,23 +1227,23 @@ void gfunc_call(int nb_args) · 98 unmodified lines
11831227 /* Alter stack entry type so that gv() knows how to treat it */
11841228 vtop->type = type;
11851229 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+ }
12031247 } else if (mode == x86_64_mode_integer) {
12041248 /* simple type */
12051249 /* XXX: implicit cast ? */
@@ -1209,8 +1253,6 @@ void gfunc_call(int nb_args) · 3 unmodified lines
12091253 orex(1,d,r,0x89); /* mov */
12101254 o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d));
12111255 if (reg_count == 2) {
1212− /* Second word of two-word value should always be in rdx
1213− this case is handled via RC_IRET */
12141256 d = arg_prepare_reg(gen_reg+1);
12151257 orex(1,d,vtop->r2,0x89); /* mov */
12161258 o(0xc0 + REG_VALUE(vtop->r2) * 8 + REG_VALUE(d));
@@ -1255,7 +1297,7 @@ void gfunc_prolog(CType *func_type) · 38 unmodified lines
12551297 {
12561298 X86_64_Mode mode;
12571299 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;
12591301 Sym *sym;
12601302 CType *type;
12611303
@@ -1328,7 +1370,6 @@ void gfunc_prolog(CType *func_type) · 66 unmodified lines
13281370 }
13291371
13301372 sym = func_type->ref;
1331− param_index = 0;
13321373 reg_param_index = 0;
13331374 sse_param_index = 0;
13341375
@@ -1338,10 +1379,7 @@ void gfunc_prolog(CType *func_type) · 3 unmodified lines
13381379 mode = classify_x86_64_arg(&func_vt, NULL, &size, &reg_count);
13391380 if (mode == x86_64_mode_memory) {
13401381 push_arg_reg(reg_param_index);
1341− param_addr = loc;
1342−
13431382 func_vc = loc;
1344− param_index++;
13451383 reg_param_index++;
13461384 }
13471385 /* define parameters */
@@ -1391,7 +1429,6 @@ void gfunc_prolog(CType *func_type) · 43 unmodified lines
13911429 }
13921430 sym_push(sym->v & ~SYM_FIELD, type,
13931431 VT_LOCAL | VT_LVAL, param_addr);
1394− param_index++;
13951432 }
13961433 }
13971434

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t