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:
parent
757a97466f
commit
4a16bebfab
6 changed files with 99 additions and 40 deletions
10
arm64-gen.c
10
arm64-gen.c
|
|
@ -1050,10 +1050,12 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||||
// value in general-purpose registers
|
// value in general-purpose registers
|
||||||
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
|
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
|
||||||
int align, size = type_size(&vtop->type, &align);
|
int align, size = type_size(&vtop->type, &align);
|
||||||
vtop->type.t = VT_PTR;
|
if (size) {
|
||||||
gaddrof();
|
vtop->type.t = VT_PTR;
|
||||||
gv(RC_R(a[i] / 2));
|
gaddrof();
|
||||||
arm64_ldrs(a[i] / 2, size);
|
gv(RC_R(a[i] / 2));
|
||||||
|
arm64_ldrs(a[i] / 2, size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
gv(RC_R(a[i] / 2));
|
gv(RC_R(a[i] / 2));
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@ typedef struct {
|
||||||
} __builtin_va_list[1];
|
} __builtin_va_list[1];
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
extern void *memcpy(void *dest, const void *src, unsigned long n);
|
||||||
|
|
||||||
void *__va_arg(__builtin_va_list ap,
|
void *__va_arg(__builtin_va_list ap,
|
||||||
int arg_type,
|
int arg_type,
|
||||||
int size, int align)
|
int size, int align)
|
||||||
|
|
@ -40,9 +42,15 @@ void *__va_arg(__builtin_va_list ap,
|
||||||
case __va_float_reg:
|
case __va_float_reg:
|
||||||
if (ap->fp_offset < 128 + 48) {
|
if (ap->fp_offset < 128 + 48) {
|
||||||
ap->fp_offset += 16;
|
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;
|
goto use_overflow_area;
|
||||||
|
|
||||||
case __va_stack:
|
case __va_stack:
|
||||||
|
|
|
||||||
|
|
@ -552,7 +552,9 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||||
if (!sa && align == 2*XLEN && size <= 2*XLEN)
|
if (!sa && align == 2*XLEN && size <= 2*XLEN)
|
||||||
areg[0] = (areg[0] + 1) & ~1;
|
areg[0] = (areg[0] + 1) & ~1;
|
||||||
nregs = prc[0];
|
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)
|
|| (prc[1] == RC_FLOAT && areg[1] >= 16)
|
||||||
|| (nregs == 2 && prc[1] == RC_FLOAT && prc[2] == RC_FLOAT
|
|| (nregs == 2 && prc[1] == RC_FLOAT && prc[2] == RC_FLOAT
|
||||||
&& areg[1] >= 15)
|
&& areg[1] >= 15)
|
||||||
|
|
@ -651,6 +653,8 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||||
vrotb(i+1);
|
vrotb(i+1);
|
||||||
origtype = vtop->type;
|
origtype = vtop->type;
|
||||||
size = type_size(&vtop->type, &align);
|
size = type_size(&vtop->type, &align);
|
||||||
|
if (size == 0)
|
||||||
|
goto done;
|
||||||
loadt = vtop->type.t & VT_BTYPE;
|
loadt = vtop->type.t & VT_BTYPE;
|
||||||
if (loadt == VT_STRUCT) {
|
if (loadt == VT_STRUCT) {
|
||||||
loadt = (ii >> 12) & VT_BTYPE;
|
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
|
EI(0x13, 0, ireg(r2), ireg(vtop->r2), 0); // mv Ra+1, RR2
|
||||||
vtop->r2 = r2;
|
vtop->r2 = r2;
|
||||||
}
|
}
|
||||||
|
done:
|
||||||
vrott(i+1);
|
vrott(i+1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
17
tests/bug.c
17
tests/bug.c
|
|
@ -1,21 +1,6 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.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)
|
void tst3(void)
|
||||||
{
|
{
|
||||||
/* Should VT_SYM be checked for TOK_builtin_constant_p */
|
/* Should VT_SYM be checked for TOK_builtin_constant_p */
|
||||||
|
|
@ -60,7 +45,5 @@ int compile_errors(void)
|
||||||
int
|
int
|
||||||
main(void)
|
main(void)
|
||||||
{
|
{
|
||||||
p v = { 1, 2};
|
|
||||||
tst2(1, v);
|
|
||||||
tst3();
|
tst3();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2627,18 +2627,34 @@ void vprintf1(const char *fmt, ...)
|
||||||
struct myspace {
|
struct myspace {
|
||||||
short int profile;
|
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, ...)
|
void stdarg_for_struct(struct myspace bob, ...)
|
||||||
{
|
{
|
||||||
struct myspace george, bill;
|
struct myspace george, bill;
|
||||||
|
struct myspace2 alex1;
|
||||||
|
struct myspace3 alex2;
|
||||||
|
struct myspace4 alex3;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
short int validate;
|
short int validate;
|
||||||
|
|
||||||
va_start(ap, bob);
|
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);
|
bill = va_arg(ap, struct myspace);
|
||||||
george = va_arg(ap, struct myspace);
|
george = va_arg(ap, struct myspace);
|
||||||
validate = va_arg(ap, int);
|
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);
|
bob.profile, bill.profile, george.profile, validate);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
@ -2664,10 +2680,40 @@ void stdarg_syntax(int n, ...)
|
||||||
(va_end(ap));
|
(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)
|
void stdarg_test(void)
|
||||||
{
|
{
|
||||||
LONG_DOUBLE ld = 1234567891234LL;
|
LONG_DOUBLE ld = 1234567891234LL;
|
||||||
struct myspace bob;
|
struct myspace bob;
|
||||||
|
struct myspace2 bob2;
|
||||||
|
struct myspace3 bob3;
|
||||||
|
struct myspace4 bob4;
|
||||||
|
|
||||||
vprintf1("%d %d %d\n", 1, 2, 3);
|
vprintf1("%d %d %d\n", 1, 2, 3);
|
||||||
vprintf1("%f %d %f\n", 1.0, 2, 3.0);
|
vprintf1("%f %d %f\n", 1.0, 2, 3.0);
|
||||||
|
|
@ -2709,9 +2755,20 @@ void stdarg_test(void)
|
||||||
42.0, 43.0, ld);
|
42.0, 43.0, ld);
|
||||||
|
|
||||||
bob.profile = 42;
|
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_for_libc("stdarg_for_libc: %s %.2f %d\n", "string", 1.23, 456);
|
||||||
stdarg_syntax(1, 17);
|
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 };
|
int reltab[3] = { 1, 2, 3 };
|
||||||
|
|
|
||||||
32
x86_64-gen.c
32
x86_64-gen.c
|
|
@ -1244,6 +1244,7 @@ void gfunc_call(int nb_args)
|
||||||
stack_adjust = 0;
|
stack_adjust = 0;
|
||||||
for(i = nb_args - 1; i >= 0; i--) {
|
for(i = nb_args - 1; i >= 0; i--) {
|
||||||
mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count);
|
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) {
|
if (mode == x86_64_mode_sse && nb_sse_args + reg_count <= 8) {
|
||||||
nb_sse_args += reg_count;
|
nb_sse_args += reg_count;
|
||||||
onstack[i] = 0;
|
onstack[i] = 0;
|
||||||
|
|
@ -1278,21 +1279,23 @@ void gfunc_call(int nb_args)
|
||||||
stack_adjust &= 15;
|
stack_adjust &= 15;
|
||||||
for (i = k = 0; i < nb_args;) {
|
for (i = k = 0; i < nb_args;) {
|
||||||
mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count);
|
mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count);
|
||||||
if (!onstack[i + k]) {
|
if (size) {
|
||||||
++i;
|
if (!onstack[i + k]) {
|
||||||
continue;
|
++i;
|
||||||
}
|
continue;
|
||||||
/* Possibly adjust stack to align SSE boundary. We're processing
|
}
|
||||||
args from right to left while allocating happens left to right
|
/* Possibly adjust stack to align SSE boundary. We're processing
|
||||||
(stack grows down), so the adjustment needs to happen _after_
|
args from right to left while allocating happens left to right
|
||||||
an argument that requires it. */
|
(stack grows down), so the adjustment needs to happen _after_
|
||||||
if (stack_adjust) {
|
an argument that requires it. */
|
||||||
o(0x50); /* push %rax; aka sub $8,%rsp */
|
if (stack_adjust) {
|
||||||
args_size += 8;
|
o(0x50); /* push %rax; aka sub $8,%rsp */
|
||||||
stack_adjust = 0;
|
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);
|
vrotb(i+1);
|
||||||
|
|
||||||
|
|
@ -1357,6 +1360,7 @@ void gfunc_call(int nb_args)
|
||||||
assert(sse_reg <= 8);
|
assert(sse_reg <= 8);
|
||||||
for(i = 0; i < nb_args; i++) {
|
for(i = 0; i < nb_args; i++) {
|
||||||
mode = classify_x86_64_arg(&vtop->type, &type, &size, &align, ®_count);
|
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 */
|
/* Alter stack entry type so that gv() knows how to treat it */
|
||||||
vtop->type = type;
|
vtop->type = type;
|
||||||
if (mode == x86_64_mode_sse) {
|
if (mode == x86_64_mode_sse) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue