1
0
Fork 0

Struct va_arg fix

lib/va_list.c:
- Handle struct {double, double} correctly

arm64-gen.c:
riscv64-gen.c:
x86_64-gen.c:
- Allow zero sized structs to work with va_arg

tcctest.c:
- Add new va_arg test code

test/bug.c:
- Remove tst2 va_arg test
This commit is contained in:
herman ten brugge 2020-09-17 08:42:28 +02:00
parent 757a97466f
commit 4a16bebfab
6 changed files with 99 additions and 40 deletions

View File

@ -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));

View File

@ -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:

View File

@ -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);
}
}

View File

@ -1,21 +1,6 @@
#include <stdio.h>
#include <stdarg.h>
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();
}

View File

@ -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 };

View File

@ -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, &reg_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, &reg_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, &reg_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) {