diff --git a/arm64-gen.c b/arm64-gen.c index bb352ade..aeef6ef8 100644 --- a/arm64-gen.c +++ b/arm64-gen.c @@ -1050,10 +1050,12 @@ ST_FUNC void gfunc_call(int nb_args) // value in general-purpose registers if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { int align, size = type_size(&vtop->type, &align); - vtop->type.t = VT_PTR; - gaddrof(); - gv(RC_R(a[i] / 2)); - arm64_ldrs(a[i] / 2, size); + if (size) { + vtop->type.t = VT_PTR; + gaddrof(); + gv(RC_R(a[i] / 2)); + arm64_ldrs(a[i] / 2, size); + } } else gv(RC_R(a[i] / 2)); diff --git a/lib/va_list.c b/lib/va_list.c index fab6675c..1fb55127 100644 --- a/lib/va_list.c +++ b/lib/va_list.c @@ -23,6 +23,8 @@ typedef struct { } __builtin_va_list[1]; */ +extern void *memcpy(void *dest, const void *src, unsigned long n); + void *__va_arg(__builtin_va_list ap, int arg_type, int size, int align) @@ -40,9 +42,15 @@ void *__va_arg(__builtin_va_list ap, case __va_float_reg: if (ap->fp_offset < 128 + 48) { ap->fp_offset += 16; - return ap->reg_save_area + ap->fp_offset - 16; + if (size == 8) + return ap->reg_save_area + ap->fp_offset - 16; + if (ap->fp_offset < 128 + 48) { + memcpy(ap->reg_save_area + ap->fp_offset - 8, + ap->reg_save_area + ap->fp_offset, 8); + ap->fp_offset += 16; + return ap->reg_save_area + ap->fp_offset - 32; + } } - size = 8; goto use_overflow_area; case __va_stack: diff --git a/riscv64-gen.c b/riscv64-gen.c index baf7f5ee..2780eaa1 100644 --- a/riscv64-gen.c +++ b/riscv64-gen.c @@ -552,7 +552,9 @@ ST_FUNC void gfunc_call(int nb_args) if (!sa && align == 2*XLEN && size <= 2*XLEN) areg[0] = (areg[0] + 1) & ~1; nregs = prc[0]; - if ((prc[1] == RC_INT && areg[0] >= 8) + if (size == 0) + info[i] = 0; + else if ((prc[1] == RC_INT && areg[0] >= 8) || (prc[1] == RC_FLOAT && areg[1] >= 16) || (nregs == 2 && prc[1] == RC_FLOAT && prc[2] == RC_FLOAT && areg[1] >= 15) @@ -651,6 +653,8 @@ ST_FUNC void gfunc_call(int nb_args) vrotb(i+1); origtype = vtop->type; size = type_size(&vtop->type, &align); + if (size == 0) + goto done; loadt = vtop->type.t & VT_BTYPE; if (loadt == VT_STRUCT) { loadt = (ii >> 12) & VT_BTYPE; @@ -701,6 +705,7 @@ ST_FUNC void gfunc_call(int nb_args) EI(0x13, 0, ireg(r2), ireg(vtop->r2), 0); // mv Ra+1, RR2 vtop->r2 = r2; } +done: vrott(i+1); } } diff --git a/tests/bug.c b/tests/bug.c index 67614afe..0778b57a 100644 --- a/tests/bug.c +++ b/tests/bug.c @@ -1,21 +1,6 @@ #include #include -typedef struct{double x,y;}p; - -void tst2(int n,...) -{ - /* va_arg for struct double does not work on some targets */ - int i; - va_list args; - va_start(args,n); - for (i = 0; i < n; i++) { - p v = va_arg(args,p); - if (v.x != 1 || v.y != 2) printf("%g %g\n", v.x, v.y); - } - va_end(args); -} - void tst3(void) { /* Should VT_SYM be checked for TOK_builtin_constant_p */ @@ -60,7 +45,5 @@ int compile_errors(void) int main(void) { - p v = { 1, 2}; - tst2(1, v); tst3(); } diff --git a/tests/tcctest.c b/tests/tcctest.c index 4ac2cc00..0cf53a92 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -2627,18 +2627,34 @@ void vprintf1(const char *fmt, ...) struct myspace { short int profile; }; +struct myspace2 { + char a[0]; +}; +struct myspace3 { + char a[1]; +}; +struct myspace4 { + char a[2]; +}; void stdarg_for_struct(struct myspace bob, ...) { struct myspace george, bill; + struct myspace2 alex1; + struct myspace3 alex2; + struct myspace4 alex3; va_list ap; short int validate; va_start(ap, bob); + alex1 = va_arg(ap, struct myspace2); + alex2 = va_arg(ap, struct myspace3); + alex3 = va_arg(ap, struct myspace4); bill = va_arg(ap, struct myspace); george = va_arg(ap, struct myspace); validate = va_arg(ap, int); - printf("stdarg_for_struct: %d %d %d %d\n", + printf("stdarg_for_struct: %d %d %d %d %d %d %d\n", + alex2.a[0], alex3.a[0], alex3.a[1], bob.profile, bill.profile, george.profile, validate); va_end(ap); } @@ -2664,10 +2680,40 @@ void stdarg_syntax(int n, ...) (va_end(ap)); } +typedef struct{ + double x,y; +} point; +point pts[]={{1.0,2.0},{3.0,4.0},{5.0,6.0},{7.0,8.0},{9.0,10.0},{11.0,12.0}}; + +static void stdarg_double_struct(int nargs, int posd,...) +{ + int i; + double d; + point pi; + va_list args; + + printf ("stdarg_double_struct: %d\n", posd); + va_start(args,posd); + for(i = 0; i < nargs; i++) { + if (i == posd) { + d = va_arg (args, double); + printf ("d %d = %g\n", i, d); + } + else { + pi = va_arg (args, point); + printf ("pts[%d] = %g %g\n", i, pi.x, pi.y); + } + } + va_end(args); +} + void stdarg_test(void) { LONG_DOUBLE ld = 1234567891234LL; struct myspace bob; + struct myspace2 bob2; + struct myspace3 bob3; + struct myspace4 bob4; vprintf1("%d %d %d\n", 1, 2, 3); vprintf1("%f %d %f\n", 1.0, 2, 3.0); @@ -2709,9 +2755,20 @@ void stdarg_test(void) 42.0, 43.0, ld); bob.profile = 42; - stdarg_for_struct(bob, bob, bob, bob.profile); + bob3.a[0] = 1; + bob4.a[0] = 2; + bob4.a[1] = 3; + stdarg_for_struct(bob, bob2, bob3, bob4, bob, bob, bob.profile); stdarg_for_libc("stdarg_for_libc: %s %.2f %d\n", "string", 1.23, 456); stdarg_syntax(1, 17); +#ifndef __riscv + stdarg_double_struct(6,-1,pts[0],pts[1],pts[2],pts[3],pts[4],pts[5]); + stdarg_double_struct(7,1,pts[0],-1.0,pts[1],pts[2],pts[3],pts[4],pts[5]); + stdarg_double_struct(7,2,pts[0],pts[1],-1.0,pts[2],pts[3],pts[4],pts[5]); + stdarg_double_struct(7,3,pts[0],pts[1],pts[2],-1.0,pts[3],pts[4],pts[5]); + stdarg_double_struct(7,4,pts[0],pts[1],pts[2],pts[3],-1.0,pts[4],pts[5]); + stdarg_double_struct(7,5,pts[0],pts[1],pts[2],pts[3],pts[4],-1.0,pts[5]); +#endif } int reltab[3] = { 1, 2, 3 }; diff --git a/x86_64-gen.c b/x86_64-gen.c index e68ef947..44ff3e51 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -1244,6 +1244,7 @@ void gfunc_call(int nb_args) stack_adjust = 0; for(i = nb_args - 1; i >= 0; i--) { mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count); + if (size == 0) continue; if (mode == x86_64_mode_sse && nb_sse_args + reg_count <= 8) { nb_sse_args += reg_count; onstack[i] = 0; @@ -1278,21 +1279,23 @@ void gfunc_call(int nb_args) stack_adjust &= 15; for (i = k = 0; i < nb_args;) { mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count); - if (!onstack[i + k]) { - ++i; - continue; - } - /* Possibly adjust stack to align SSE boundary. We're processing - args from right to left while allocating happens left to right - (stack grows down), so the adjustment needs to happen _after_ - an argument that requires it. */ - if (stack_adjust) { - o(0x50); /* push %rax; aka sub $8,%rsp */ - args_size += 8; - stack_adjust = 0; + if (size) { + if (!onstack[i + k]) { + ++i; + continue; + } + /* Possibly adjust stack to align SSE boundary. We're processing + args from right to left while allocating happens left to right + (stack grows down), so the adjustment needs to happen _after_ + an argument that requires it. */ + if (stack_adjust) { + o(0x50); /* push %rax; aka sub $8,%rsp */ + args_size += 8; + stack_adjust = 0; + } + if (onstack[i + k] == 2) + stack_adjust = 1; } - if (onstack[i + k] == 2) - stack_adjust = 1; vrotb(i+1); @@ -1357,6 +1360,7 @@ void gfunc_call(int nb_args) assert(sse_reg <= 8); for(i = 0; i < nb_args; i++) { mode = classify_x86_64_arg(&vtop->type, &type, &size, &align, ®_count); + if (size == 0) continue; /* Alter stack entry type so that gv() knows how to treat it */ vtop->type = type; if (mode == x86_64_mode_sse) {