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
				
			
		| 
						 | 
					@ -1050,11 +1050,13 @@ 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);
 | 
				
			||||||
 | 
					                if (size) {
 | 
				
			||||||
                    vtop->type.t = VT_PTR;
 | 
					                    vtop->type.t = VT_PTR;
 | 
				
			||||||
                    gaddrof();
 | 
					                    gaddrof();
 | 
				
			||||||
                    gv(RC_R(a[i] / 2));
 | 
					                    gv(RC_R(a[i] / 2));
 | 
				
			||||||
                    arm64_ldrs(a[i] / 2, size);
 | 
					                    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;
 | 
				
			||||||
 | 
					            if (size == 8)
 | 
				
			||||||
                return ap->reg_save_area + ap->fp_offset - 16;
 | 
					                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 };
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,6 +1279,7 @@ 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 (size) {
 | 
				
			||||||
            if (!onstack[i + k]) {
 | 
					            if (!onstack[i + k]) {
 | 
				
			||||||
	        ++i;
 | 
						        ++i;
 | 
				
			||||||
	        continue;
 | 
						        continue;
 | 
				
			||||||
| 
						 | 
					@ -1293,6 +1295,7 @@ void gfunc_call(int nb_args)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
	    if (onstack[i + k] == 2)
 | 
						    if (onstack[i + k] == 2)
 | 
				
			||||||
	        stack_adjust = 1;
 | 
						        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