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
 | 
			
		||||
            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…
	
	Add table
		
		Reference in a new issue