mirror of
https://github.com/mirror/tinycc.git
synced 2025-03-14 09:10:07 +08:00
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
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
|
||||
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));
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
17
tests/bug.c
17
tests/bug.c
@ -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();
|
||||
}
|
||||
|
@ -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 };
|
||||
|
32
x86_64-gen.c
32
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) {
|
||||
|
Loading…
Reference in New Issue
Block a user