Revert "fix-mixed-struct (patch by Pip Cet)"
This reverts commit 4e04f67c94. Requested by grischka.
			
			
This commit is contained in:
		
							parent
							
								
									89ad24e7d6
								
							
						
					
					
						commit
						ef3d38c5c9
					
				
					 8 changed files with 232 additions and 456 deletions
				
			
		
							
								
								
									
										22
									
								
								arm-gen.c
									
										
									
									
									
								
							
							
						
						
									
										22
									
								
								arm-gen.c
									
										
									
									
									
								
							| 
						 | 
					@ -34,8 +34,6 @@
 | 
				
			||||||
#define NB_REGS             9
 | 
					#define NB_REGS             9
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef int RegArgs;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef TCC_ARM_VERSION
 | 
					#ifndef TCC_ARM_VERSION
 | 
				
			||||||
# define TCC_ARM_VERSION 5
 | 
					# define TCC_ARM_VERSION 5
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -869,14 +867,9 @@ int floats_in_core_regs(SValue *sval)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ST_FUNC int regargs_nregs(RegArgs *args)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    return *args;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Return the number of registers needed to return the struct, or 0 if
 | 
					/* Return the number of registers needed to return the struct, or 0 if
 | 
				
			||||||
   returning via struct pointer. */
 | 
					   returning via struct pointer. */
 | 
				
			||||||
ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize, RegArgs *args) {
 | 
					ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) {
 | 
				
			||||||
#ifdef TCC_ARM_EABI
 | 
					#ifdef TCC_ARM_EABI
 | 
				
			||||||
    int size, align;
 | 
					    int size, align;
 | 
				
			||||||
    size = type_size(vt, &align);
 | 
					    size = type_size(vt, &align);
 | 
				
			||||||
| 
						 | 
					@ -886,20 +879,18 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int
 | 
				
			||||||
	*regsize = 8;
 | 
						*regsize = 8;
 | 
				
			||||||
        ret->ref = NULL;
 | 
					        ret->ref = NULL;
 | 
				
			||||||
        ret->t = VT_DOUBLE;
 | 
					        ret->t = VT_DOUBLE;
 | 
				
			||||||
        *args = (size + 7) >> 3;
 | 
					        return (size + 7) >> 3;
 | 
				
			||||||
    } else if (size <= 4) {
 | 
					    } else if (size <= 4) {
 | 
				
			||||||
        *ret_align = 4;
 | 
					        *ret_align = 4;
 | 
				
			||||||
	*regsize = 4;
 | 
						*regsize = 4;
 | 
				
			||||||
        ret->ref = NULL;
 | 
					        ret->ref = NULL;
 | 
				
			||||||
        ret->t = VT_INT;
 | 
					        ret->t = VT_INT;
 | 
				
			||||||
        *args = 1;
 | 
					        return 1;
 | 
				
			||||||
    } else
 | 
					    } else
 | 
				
			||||||
        *args = 0;
 | 
					        return 0;
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
    *args = 0;
 | 
					    return 0;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					 | 
				
			||||||
    return *args != 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Parameters are classified according to how they are copied to their final
 | 
					/* Parameters are classified according to how they are copied to their final
 | 
				
			||||||
| 
						 | 
					@ -1269,7 +1260,6 @@ void gfunc_prolog(CType *func_type)
 | 
				
			||||||
  int n, nf, size, align, rs, struct_ret = 0;
 | 
					  int n, nf, size, align, rs, struct_ret = 0;
 | 
				
			||||||
  int addr, pn, sn; /* pn=core, sn=stack */
 | 
					  int addr, pn, sn; /* pn=core, sn=stack */
 | 
				
			||||||
  CType ret_type;
 | 
					  CType ret_type;
 | 
				
			||||||
  RegArgs dummy;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef TCC_ARM_EABI
 | 
					#ifdef TCC_ARM_EABI
 | 
				
			||||||
  struct avail_regs avregs = AVAIL_REGS_INITIALIZER;
 | 
					  struct avail_regs avregs = AVAIL_REGS_INITIALIZER;
 | 
				
			||||||
| 
						 | 
					@ -1281,7 +1271,7 @@ void gfunc_prolog(CType *func_type)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  n = nf = 0;
 | 
					  n = nf = 0;
 | 
				
			||||||
  if ((func_vt.t & VT_BTYPE) == VT_STRUCT &&
 | 
					  if ((func_vt.t & VT_BTYPE) == VT_STRUCT &&
 | 
				
			||||||
      !gfunc_sret(&func_vt, func_var, &ret_type, &align, &rs, &dummy))
 | 
					      !gfunc_sret(&func_vt, func_var, &ret_type, &align, &rs))
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    n++;
 | 
					    n++;
 | 
				
			||||||
    struct_ret = 1;
 | 
					    struct_ret = 1;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								arm64-gen.c
									
										
									
									
									
								
							
							
						
						
									
										11
									
								
								arm64-gen.c
									
										
									
									
									
								
							| 
						 | 
					@ -14,8 +14,6 @@
 | 
				
			||||||
// Number of registers available to allocator:
 | 
					// Number of registers available to allocator:
 | 
				
			||||||
#define NB_REGS 28 // x0-x18, x30, v0-v7
 | 
					#define NB_REGS 28 // x0-x18, x30, v0-v7
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef int RegArgs;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define TREG_R(x) (x) // x = 0..18
 | 
					#define TREG_R(x) (x) // x = 0..18
 | 
				
			||||||
#define TREG_R30  19
 | 
					#define TREG_R30  19
 | 
				
			||||||
#define TREG_F(x) (x + 20) // x = 0..7
 | 
					#define TREG_F(x) (x + 20) // x = 0..7
 | 
				
			||||||
| 
						 | 
					@ -1198,15 +1196,8 @@ ST_FUNC void gen_va_arg(CType *t)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ST_FUNC int regargs_nregs(RegArgs *args)
 | 
					ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    return *args;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize, RegArgs *args)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    *args = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								c67-gen.c
									
										
									
									
									
								
							
							
						
						
									
										11
									
								
								c67-gen.c
									
										
									
									
									
								
							| 
						 | 
					@ -25,8 +25,6 @@
 | 
				
			||||||
/* number of available registers */
 | 
					/* number of available registers */
 | 
				
			||||||
#define NB_REGS            24
 | 
					#define NB_REGS            24
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef int RegArgs;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* a register can belong to several classes. The classes must be
 | 
					/* a register can belong to several classes. The classes must be
 | 
				
			||||||
   sorted from more general to more precise (see gv2() code which does
 | 
					   sorted from more general to more precise (see gv2() code which does
 | 
				
			||||||
   assumptions on it). */
 | 
					   assumptions on it). */
 | 
				
			||||||
| 
						 | 
					@ -1881,17 +1879,10 @@ static void gcall_or_jmp(int is_jmp)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ST_FUNC int regargs_nregs(RegArgs *args)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    return *args;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Return the number of registers needed to return the struct, or 0 if
 | 
					/* Return the number of registers needed to return the struct, or 0 if
 | 
				
			||||||
   returning via struct pointer. */
 | 
					   returning via struct pointer. */
 | 
				
			||||||
ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize, RegArgs *args) {
 | 
					ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) {
 | 
				
			||||||
    *ret_align = 1; // Never have to re-align return values for x86-64
 | 
					    *ret_align = 1; // Never have to re-align return values for x86-64
 | 
				
			||||||
    *args = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										19
									
								
								i386-gen.c
									
										
									
									
									
								
							
							
						
						
									
										19
									
								
								i386-gen.c
									
										
									
									
									
								
							| 
						 | 
					@ -24,8 +24,6 @@
 | 
				
			||||||
#define NB_REGS         4
 | 
					#define NB_REGS         4
 | 
				
			||||||
#define NB_ASM_REGS     8
 | 
					#define NB_ASM_REGS     8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef int RegArgs;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* a register can belong to several classes. The classes must be
 | 
					/* a register can belong to several classes. The classes must be
 | 
				
			||||||
   sorted from more general to more precise (see gv2() code which does
 | 
					   sorted from more general to more precise (see gv2() code which does
 | 
				
			||||||
   assumptions on it). */
 | 
					   assumptions on it). */
 | 
				
			||||||
| 
						 | 
					@ -376,14 +374,9 @@ static void gcall_or_jmp(int is_jmp)
 | 
				
			||||||
static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
 | 
					static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
 | 
				
			||||||
static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };
 | 
					static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ST_FUNC int regargs_nregs(RegArgs *args)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    return *args;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Return the number of registers needed to return the struct, or 0 if
 | 
					/* Return the number of registers needed to return the struct, or 0 if
 | 
				
			||||||
   returning via struct pointer. */
 | 
					   returning via struct pointer. */
 | 
				
			||||||
ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize, RegArgs *args)
 | 
					ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef TCC_TARGET_PE
 | 
					#ifdef TCC_TARGET_PE
 | 
				
			||||||
    int size, align;
 | 
					    int size, align;
 | 
				
			||||||
| 
						 | 
					@ -392,22 +385,20 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int
 | 
				
			||||||
    *regsize = 4;
 | 
					    *regsize = 4;
 | 
				
			||||||
    size = type_size(vt, &align);
 | 
					    size = type_size(vt, &align);
 | 
				
			||||||
    if (size > 8) {
 | 
					    if (size > 8) {
 | 
				
			||||||
        *args = 0;
 | 
					        return 0;
 | 
				
			||||||
    } else if (size > 4) {
 | 
					    } else if (size > 4) {
 | 
				
			||||||
        ret->ref = NULL;
 | 
					        ret->ref = NULL;
 | 
				
			||||||
        ret->t = VT_LLONG;
 | 
					        ret->t = VT_LLONG;
 | 
				
			||||||
        *args = 1;
 | 
					        return 1;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        ret->ref = NULL;
 | 
					        ret->ref = NULL;
 | 
				
			||||||
        ret->t = VT_INT;
 | 
					        ret->t = VT_INT;
 | 
				
			||||||
        *args = 1;
 | 
					        return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
    *ret_align = 1; // Never have to re-align return values for x86
 | 
					    *ret_align = 1; // Never have to re-align return values for x86
 | 
				
			||||||
    *args = 0;
 | 
					    return 0;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					 | 
				
			||||||
    return *args != 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Generate function call. The function address is pushed first, then
 | 
					/* Generate function call. The function address is pushed first, then
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										8
									
								
								tcc.h
									
										
									
									
									
								
							
							
						
						
									
										8
									
								
								tcc.h
									
										
									
									
									
								
							| 
						 | 
					@ -796,8 +796,8 @@ struct TCCState {
 | 
				
			||||||
#define VT_LLONG           12  /* 64 bit integer */
 | 
					#define VT_LLONG           12  /* 64 bit integer */
 | 
				
			||||||
#define VT_LONG            13  /* long integer (NEVER USED as type, only
 | 
					#define VT_LONG            13  /* long integer (NEVER USED as type, only
 | 
				
			||||||
                                  during parsing) */
 | 
					                                  during parsing) */
 | 
				
			||||||
#define VT_QLONG           14  /* 128-bit integer. No longer used. */
 | 
					#define VT_QLONG           14  /* 128-bit integer. Only used for x86-64 ABI */
 | 
				
			||||||
#define VT_QFLOAT          15  /* 128-bit float. No longer used. */
 | 
					#define VT_QFLOAT          15  /* 128-bit float. Only used for x86-64 ABI */
 | 
				
			||||||
#define VT_UNSIGNED    0x0010  /* unsigned type */
 | 
					#define VT_UNSIGNED    0x0010  /* unsigned type */
 | 
				
			||||||
#define VT_ARRAY       0x0020  /* array type (also has VT_PTR) */
 | 
					#define VT_ARRAY       0x0020  /* array type (also has VT_PTR) */
 | 
				
			||||||
#define VT_BITFIELD    0x0040  /* bitfield modifier */
 | 
					#define VT_BITFIELD    0x0040  /* bitfield modifier */
 | 
				
			||||||
| 
						 | 
					@ -1267,7 +1267,6 @@ ST_FUNC void save_regs(int n);
 | 
				
			||||||
ST_FUNC void gaddrof(void);
 | 
					ST_FUNC void gaddrof(void);
 | 
				
			||||||
ST_FUNC int gv(int rc);
 | 
					ST_FUNC int gv(int rc);
 | 
				
			||||||
ST_FUNC void gv2(int rc1, int rc2);
 | 
					ST_FUNC void gv2(int rc1, int rc2);
 | 
				
			||||||
ST_FUNC void vdup(void);
 | 
					 | 
				
			||||||
ST_FUNC void vpop(void);
 | 
					ST_FUNC void vpop(void);
 | 
				
			||||||
ST_FUNC void gen_op(int op);
 | 
					ST_FUNC void gen_op(int op);
 | 
				
			||||||
ST_FUNC int type_size(CType *type, int *a);
 | 
					ST_FUNC int type_size(CType *type, int *a);
 | 
				
			||||||
| 
						 | 
					@ -1356,8 +1355,7 @@ ST_FUNC void gsym_addr(int t, int a);
 | 
				
			||||||
ST_FUNC void gsym(int t);
 | 
					ST_FUNC void gsym(int t);
 | 
				
			||||||
ST_FUNC void load(int r, SValue *sv);
 | 
					ST_FUNC void load(int r, SValue *sv);
 | 
				
			||||||
ST_FUNC void store(int r, SValue *v);
 | 
					ST_FUNC void store(int r, SValue *v);
 | 
				
			||||||
ST_FUNC int regargs_nregs(RegArgs *args);
 | 
					ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize);
 | 
				
			||||||
ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize, RegArgs *args);
 | 
					 | 
				
			||||||
ST_FUNC void gfunc_call(int nb_args);
 | 
					ST_FUNC void gfunc_call(int nb_args);
 | 
				
			||||||
ST_FUNC void gfunc_prolog(CType *func_type);
 | 
					ST_FUNC void gfunc_prolog(CType *func_type);
 | 
				
			||||||
ST_FUNC void gfunc_epilog(void);
 | 
					ST_FUNC void gfunc_epilog(void);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										86
									
								
								tccgen.c
									
										
									
									
									
								
							
							
						
						
									
										86
									
								
								tccgen.c
									
										
									
									
									
								
							| 
						 | 
					@ -525,7 +525,7 @@ ST_FUNC void vpushv(SValue *v)
 | 
				
			||||||
    *vtop = *v;
 | 
					    *vtop = *v;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ST_FUNC void vdup(void)
 | 
					static void vdup(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    vpushv(vtop);
 | 
					    vpushv(vtop);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -4200,7 +4200,6 @@ ST_FUNC void unary(void)
 | 
				
			||||||
            SValue ret;
 | 
					            SValue ret;
 | 
				
			||||||
            Sym *sa;
 | 
					            Sym *sa;
 | 
				
			||||||
            int nb_args, ret_nregs, ret_align, regsize, variadic;
 | 
					            int nb_args, ret_nregs, ret_align, regsize, variadic;
 | 
				
			||||||
            RegArgs args;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            /* function call  */
 | 
					            /* function call  */
 | 
				
			||||||
            if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
 | 
					            if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
 | 
				
			||||||
| 
						 | 
					@ -4225,10 +4224,8 @@ ST_FUNC void unary(void)
 | 
				
			||||||
            /* compute first implicit argument if a structure is returned */
 | 
					            /* compute first implicit argument if a structure is returned */
 | 
				
			||||||
            if ((s->type.t & VT_BTYPE) == VT_STRUCT) {
 | 
					            if ((s->type.t & VT_BTYPE) == VT_STRUCT) {
 | 
				
			||||||
                variadic = (s->c == FUNC_ELLIPSIS);
 | 
					                variadic = (s->c == FUNC_ELLIPSIS);
 | 
				
			||||||
                gfunc_sret(&s->type, variadic, &ret.type,
 | 
					                ret_nregs = gfunc_sret(&s->type, variadic, &ret.type,
 | 
				
			||||||
                           &ret_align, ®size, &args);
 | 
					                                       &ret_align, ®size);
 | 
				
			||||||
                ret_nregs = regargs_nregs(&args);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (!ret_nregs) {
 | 
					                if (!ret_nregs) {
 | 
				
			||||||
                    /* get some space for the returned structure */
 | 
					                    /* get some space for the returned structure */
 | 
				
			||||||
                    size = type_size(&s->type, &align);
 | 
					                    size = type_size(&s->type, &align);
 | 
				
			||||||
| 
						 | 
					@ -4306,10 +4303,6 @@ ST_FUNC void unary(void)
 | 
				
			||||||
            /* handle packed struct return */
 | 
					            /* handle packed struct return */
 | 
				
			||||||
            if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs) {
 | 
					            if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs) {
 | 
				
			||||||
                int addr, offset;
 | 
					                int addr, offset;
 | 
				
			||||||
#if defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_PE)
 | 
					 | 
				
			||||||
                int i;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                size = type_size(&s->type, &align);
 | 
					                size = type_size(&s->type, &align);
 | 
				
			||||||
		/* We're writing whole regs often, make sure there's enough
 | 
							/* We're writing whole regs often, make sure there's enough
 | 
				
			||||||
| 
						 | 
					@ -4318,34 +4311,6 @@ ST_FUNC void unary(void)
 | 
				
			||||||
		  align = regsize;
 | 
							  align = regsize;
 | 
				
			||||||
                loc = (loc - size) & -align;
 | 
					                loc = (loc - size) & -align;
 | 
				
			||||||
                addr = loc;
 | 
					                addr = loc;
 | 
				
			||||||
#if defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_PE)
 | 
					 | 
				
			||||||
                for (i=0; i<REG_ARGS_MAX; i++) {
 | 
					 | 
				
			||||||
                    offset = args.ireg[i];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    if (offset == -1)
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    ret.type.t = VT_LLONG;
 | 
					 | 
				
			||||||
                    vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset);
 | 
					 | 
				
			||||||
                    vsetc(&ret.type, i ? REG_LRET : REG_IRET, &ret.c);
 | 
					 | 
				
			||||||
                    vstore();
 | 
					 | 
				
			||||||
                    vtop--;
 | 
					 | 
				
			||||||
                    vtop--;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                for (i=0; i<REG_ARGS_MAX; i++) {
 | 
					 | 
				
			||||||
                    offset = args.freg[i];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    if (offset == -1)
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    ret.type.t = VT_DOUBLE;
 | 
					 | 
				
			||||||
                    vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset);
 | 
					 | 
				
			||||||
                    vsetc(&ret.type, i ? REG_QRET : REG_FRET, &ret.c);
 | 
					 | 
				
			||||||
                    vstore();
 | 
					 | 
				
			||||||
                    vtop--;
 | 
					 | 
				
			||||||
                    vtop--;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
                offset = 0;
 | 
					                offset = 0;
 | 
				
			||||||
                for (;;) {
 | 
					                for (;;) {
 | 
				
			||||||
                    vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset);
 | 
					                    vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset);
 | 
				
			||||||
| 
						 | 
					@ -4356,7 +4321,6 @@ ST_FUNC void unary(void)
 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                    offset += regsize;
 | 
					                    offset += regsize;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
                vset(&s->type, VT_LOCAL | VT_LVAL, addr);
 | 
					                vset(&s->type, VT_LOCAL | VT_LVAL, addr);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
| 
						 | 
					@ -4927,11 +4891,8 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
 | 
				
			||||||
            if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
 | 
					            if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
 | 
				
			||||||
                CType type, ret_type;
 | 
					                CType type, ret_type;
 | 
				
			||||||
                int ret_align, ret_nregs, regsize;
 | 
					                int ret_align, ret_nregs, regsize;
 | 
				
			||||||
                RegArgs args;
 | 
					                ret_nregs = gfunc_sret(&func_vt, func_var, &ret_type,
 | 
				
			||||||
 | 
					                                       &ret_align, ®size);
 | 
				
			||||||
                gfunc_sret(&func_vt, func_var, &ret_type,
 | 
					 | 
				
			||||||
                           &ret_align, ®size, &args);
 | 
					 | 
				
			||||||
                ret_nregs = regargs_nregs(&args);
 | 
					 | 
				
			||||||
                if (0 == ret_nregs) {
 | 
					                if (0 == ret_nregs) {
 | 
				
			||||||
                    /* if returning structure, must copy it to implicit
 | 
					                    /* if returning structure, must copy it to implicit
 | 
				
			||||||
                       first pointer arg location */
 | 
					                       first pointer arg location */
 | 
				
			||||||
| 
						 | 
					@ -4945,9 +4906,6 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    /* returning structure packed into registers */
 | 
					                    /* returning structure packed into registers */
 | 
				
			||||||
                    int r, size, addr, align;
 | 
					                    int r, size, addr, align;
 | 
				
			||||||
#if defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_PE)
 | 
					 | 
				
			||||||
                    int i;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
                    size = type_size(&func_vt,&align);
 | 
					                    size = type_size(&func_vt,&align);
 | 
				
			||||||
                    if ((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & (ret_align-1)))
 | 
					                    if ((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & (ret_align-1)))
 | 
				
			||||||
                        && (align & (ret_align-1))) {
 | 
					                        && (align & (ret_align-1))) {
 | 
				
			||||||
| 
						 | 
					@ -4961,39 +4919,6 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
 | 
				
			||||||
                        vset(&ret_type, VT_LOCAL | VT_LVAL, addr);
 | 
					                        vset(&ret_type, VT_LOCAL | VT_LVAL, addr);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    vtop->type = ret_type;
 | 
					                    vtop->type = ret_type;
 | 
				
			||||||
#if defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_PE)
 | 
					 | 
				
			||||||
                    for (i=0; i<REG_ARGS_MAX; i++) {
 | 
					 | 
				
			||||||
                        int off = args.ireg[i];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        if (off == -1)
 | 
					 | 
				
			||||||
                            break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        r = i ? RC_LRET : RC_IRET;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        vdup();
 | 
					 | 
				
			||||||
                        vtop->c.i += off;
 | 
					 | 
				
			||||||
                        vtop->type.t = VT_LLONG;
 | 
					 | 
				
			||||||
                        gv(r);
 | 
					 | 
				
			||||||
                        vpop();
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    for (i=0; i<REG_ARGS_MAX; i++) {
 | 
					 | 
				
			||||||
                        int off = args.freg[i];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        if (off == -1)
 | 
					 | 
				
			||||||
                            break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        /* We assume that when a structure is returned in multiple
 | 
					 | 
				
			||||||
                           registers, their classes are consecutive values of the
 | 
					 | 
				
			||||||
                           suite s(n) = 2^n */
 | 
					 | 
				
			||||||
                        r = rc_fret(ret_type.t) << i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        vdup();
 | 
					 | 
				
			||||||
                        vtop->c.i += off;
 | 
					 | 
				
			||||||
                        vtop->type.t = VT_DOUBLE;
 | 
					 | 
				
			||||||
                        gv(r);
 | 
					 | 
				
			||||||
                        vpop();
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
                    if (is_float(ret_type.t))
 | 
					                    if (is_float(ret_type.t))
 | 
				
			||||||
                        r = rc_fret(ret_type.t);
 | 
					                        r = rc_fret(ret_type.t);
 | 
				
			||||||
                    else
 | 
					                    else
 | 
				
			||||||
| 
						 | 
					@ -5010,7 +4935,6 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
 | 
				
			||||||
                        vtop->c.i += regsize;
 | 
					                        vtop->c.i += regsize;
 | 
				
			||||||
                        vtop->r = VT_LOCAL | VT_LVAL;
 | 
					                        vtop->r = VT_LOCAL | VT_LVAL;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            } else if (is_float(func_vt.t)) {
 | 
					            } else if (is_float(func_vt.t)) {
 | 
				
			||||||
                gv(rc_fret(func_vt.t));
 | 
					                gv(rc_fret(func_vt.t));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -637,10 +637,10 @@ int main(int argc, char **argv) {
 | 
				
			||||||
  RUN_TEST(ret_longdouble_test);
 | 
					  RUN_TEST(ret_longdouble_test);
 | 
				
			||||||
  RUN_TEST(ret_2float_test);
 | 
					  RUN_TEST(ret_2float_test);
 | 
				
			||||||
  RUN_TEST(ret_2double_test);
 | 
					  RUN_TEST(ret_2double_test);
 | 
				
			||||||
  RUN_TEST(ret_8plus2double_test);
 | 
					  /* RUN_TEST(ret_8plus2double_test); currently broken on x86_64 */
 | 
				
			||||||
  RUN_TEST(ret_6plus2longlong_test);
 | 
					  /* RUN_TEST(ret_6plus2longlong_test); currently broken on x86_64 */
 | 
				
			||||||
  RUN_TEST(ret_mixed_test);
 | 
					  /* RUN_TEST(ret_mixed_test); currently broken on x86_64 */
 | 
				
			||||||
  RUN_TEST(ret_mixed2_test);
 | 
					  /* RUN_TEST(ret_mixed2_test); currently broken on x86_64 */
 | 
				
			||||||
  RUN_TEST(ret_mixed3_test);
 | 
					  RUN_TEST(ret_mixed3_test);
 | 
				
			||||||
  RUN_TEST(reg_pack_test);
 | 
					  RUN_TEST(reg_pack_test);
 | 
				
			||||||
  RUN_TEST(reg_pack_longlong_test);
 | 
					  RUN_TEST(reg_pack_longlong_test);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										437
									
								
								x86_64-gen.c
									
										
									
									
									
								
							
							
						
						
									
										437
									
								
								x86_64-gen.c
									
										
									
									
									
								
							| 
						 | 
					@ -25,24 +25,6 @@
 | 
				
			||||||
/* number of available registers */
 | 
					/* number of available registers */
 | 
				
			||||||
#define NB_REGS         25
 | 
					#define NB_REGS         25
 | 
				
			||||||
#define NB_ASM_REGS     8
 | 
					#define NB_ASM_REGS     8
 | 
				
			||||||
#define REG_ARGS_MAX    2 /* at most 2 registers used for each argument */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef TCC_TARGET_PE
 | 
					 | 
				
			||||||
typedef int RegArgs;
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
/* This struct stores the struct offsets at which %rax, %rdx, %xmm0, and
 | 
					 | 
				
			||||||
 * %xmm1 are to be stored.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * struct { long long l; double x; }: ireg = { 0, -1 } freg = { 8, -1 }
 | 
					 | 
				
			||||||
 * struct { double x; long long l; }: ireg = { 8, -1 } freg = { 0, -1 }
 | 
					 | 
				
			||||||
 * struct { long long l; long long l2; }: ireg = { 0, 8 } freg = { -1, -1 }
 | 
					 | 
				
			||||||
 * struct { double x; double x2; }: ireg = { -1, -1 } freg = { 0, 8 }
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
typedef struct {
 | 
					 | 
				
			||||||
    int ireg[REG_ARGS_MAX];
 | 
					 | 
				
			||||||
    int freg[REG_ARGS_MAX];
 | 
					 | 
				
			||||||
} RegArgs;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* a register can belong to several classes. The classes must be
 | 
					/* a register can belong to several classes. The classes must be
 | 
				
			||||||
   sorted from more general to more precise (see gv2() code which does
 | 
					   sorted from more general to more precise (see gv2() code which does
 | 
				
			||||||
| 
						 | 
					@ -763,14 +745,9 @@ void gen_offs_sp(int b, int r, int d)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ST_FUNC int regargs_nregs(RegArgs *args)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    return *args;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Return the number of registers needed to return the struct, or 0 if
 | 
					/* Return the number of registers needed to return the struct, or 0 if
 | 
				
			||||||
   returning via struct pointer. */
 | 
					   returning via struct pointer. */
 | 
				
			||||||
ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize, RegArgs *args)
 | 
					ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int size, align;
 | 
					    int size, align;
 | 
				
			||||||
    *regsize = 8;
 | 
					    *regsize = 8;
 | 
				
			||||||
| 
						 | 
					@ -778,22 +755,20 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int
 | 
				
			||||||
    size = type_size(vt, &align);
 | 
					    size = type_size(vt, &align);
 | 
				
			||||||
    ret->ref = NULL;
 | 
					    ret->ref = NULL;
 | 
				
			||||||
    if (size > 8) {
 | 
					    if (size > 8) {
 | 
				
			||||||
        *args = 0;
 | 
					        return 0;
 | 
				
			||||||
    } else if (size > 4) {
 | 
					    } else if (size > 4) {
 | 
				
			||||||
        ret->t = VT_LLONG;
 | 
					        ret->t = VT_LLONG;
 | 
				
			||||||
        *args = 1;
 | 
					        return 1;
 | 
				
			||||||
    } else if (size > 2) {
 | 
					    } else if (size > 2) {
 | 
				
			||||||
        ret->t = VT_INT;
 | 
					        ret->t = VT_INT;
 | 
				
			||||||
        *args = 1;
 | 
					        return 1;
 | 
				
			||||||
    } else if (size > 1) {
 | 
					    } else if (size > 1) {
 | 
				
			||||||
        ret->t = VT_SHORT;
 | 
					        ret->t = VT_SHORT;
 | 
				
			||||||
        *args = 1;
 | 
					        return 1;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        ret->t = VT_BYTE;
 | 
					        ret->t = VT_BYTE;
 | 
				
			||||||
        *args = 1;
 | 
					        return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    return *args != 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int is_sse_float(int t) {
 | 
					static int is_sse_float(int t) {
 | 
				
			||||||
| 
						 | 
					@ -1066,9 +1041,7 @@ static X86_64_Mode classify_x86_64_merge(X86_64_Mode a, X86_64_Mode b)
 | 
				
			||||||
        return x86_64_mode_sse;
 | 
					        return x86_64_mode_sse;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* classify the x86 eightbytes from byte index start to byte index
 | 
					static X86_64_Mode classify_x86_64_inner(CType *ty)
 | 
				
			||||||
 * end, at offset offset from the root struct */
 | 
					 | 
				
			||||||
static X86_64_Mode classify_x86_64_inner(CType *ty, int offset, int start, int end)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    X86_64_Mode mode;
 | 
					    X86_64_Mode mode;
 | 
				
			||||||
    Sym *f;
 | 
					    Sym *f;
 | 
				
			||||||
| 
						 | 
					@ -1094,10 +1067,8 @@ static X86_64_Mode classify_x86_64_inner(CType *ty, int offset, int start, int e
 | 
				
			||||||
        f = ty->ref;
 | 
					        f = ty->ref;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        mode = x86_64_mode_none;
 | 
					        mode = x86_64_mode_none;
 | 
				
			||||||
        while ((f = f->next) != NULL) {
 | 
					        for (f = f->next; f; f = f->next)
 | 
				
			||||||
            if (f->c + offset >= start && f->c + offset < end)
 | 
					            mode = classify_x86_64_merge(mode, classify_x86_64_inner(&f->type));
 | 
				
			||||||
                mode = classify_x86_64_merge(mode, classify_x86_64_inner(&f->type, f->c + offset, start, end));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        return mode;
 | 
					        return mode;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -1105,40 +1076,15 @@ static X86_64_Mode classify_x86_64_inner(CType *ty, int offset, int start, int e
 | 
				
			||||||
    assert(0);
 | 
					    assert(0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static X86_64_Mode classify_x86_64_arg_eightbyte(CType *ty, int offset)
 | 
					static X86_64_Mode classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *palign, int *reg_count)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    X86_64_Mode mode;
 | 
					    X86_64_Mode mode;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    assert((ty->t & VT_BTYPE) == VT_STRUCT);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    mode = classify_x86_64_inner(ty, 0, offset, offset + 8);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return mode;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void regargs_init(RegArgs *args)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int i;
 | 
					 | 
				
			||||||
    for(i=0; i<REG_ARGS_MAX; i++) {
 | 
					 | 
				
			||||||
        args->ireg[i] = -1;
 | 
					 | 
				
			||||||
        args->freg[i] = -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static X86_64_Mode classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *palign, RegArgs *args)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    X86_64_Mode mode = x86_64_mode_none;
 | 
					 | 
				
			||||||
    int size, align, ret_t = 0;
 | 
					    int size, align, ret_t = 0;
 | 
				
			||||||
    int ireg = 0, freg = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (args)
 | 
					 | 
				
			||||||
        regargs_init(args);
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    if (ty->t & (VT_BITFIELD|VT_ARRAY)) {
 | 
					    if (ty->t & (VT_BITFIELD|VT_ARRAY)) {
 | 
				
			||||||
        *psize = 8;
 | 
					        *psize = 8;
 | 
				
			||||||
        *palign = 8;
 | 
					        *palign = 8;
 | 
				
			||||||
        if (args)
 | 
					        *reg_count = 1;
 | 
				
			||||||
            args->ireg[ireg++] = 0;
 | 
					 | 
				
			||||||
        ret_t = ty->t;
 | 
					        ret_t = ty->t;
 | 
				
			||||||
        mode = x86_64_mode_integer;
 | 
					        mode = x86_64_mode_integer;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
| 
						 | 
					@ -1149,26 +1095,33 @@ static X86_64_Mode classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *p
 | 
				
			||||||
        if (size > 16) {
 | 
					        if (size > 16) {
 | 
				
			||||||
            mode = x86_64_mode_memory;
 | 
					            mode = x86_64_mode_memory;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            int start;
 | 
					            mode = classify_x86_64_inner(ty);
 | 
				
			||||||
 | 
					            switch (mode) {
 | 
				
			||||||
            for(start=0; start < size; start += 8) {
 | 
					            case x86_64_mode_integer:
 | 
				
			||||||
                if ((ty->t & VT_BTYPE) == VT_STRUCT) {
 | 
					                if (size > 8) {
 | 
				
			||||||
                    mode = classify_x86_64_arg_eightbyte(ty, start);
 | 
					                    *reg_count = 2;
 | 
				
			||||||
 | 
					                    ret_t = VT_QLONG;
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    mode = classify_x86_64_inner(ty, 0, 0, size);
 | 
					                    *reg_count = 1;
 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (mode == x86_64_mode_integer) {
 | 
					 | 
				
			||||||
                    if (args)
 | 
					 | 
				
			||||||
                        args->ireg[ireg++] = start;
 | 
					 | 
				
			||||||
                    ret_t = (size > 4) ? VT_LLONG : VT_INT;
 | 
					                    ret_t = (size > 4) ? VT_LLONG : VT_INT;
 | 
				
			||||||
                } else if (mode == x86_64_mode_sse) {
 | 
					 | 
				
			||||||
                    if (args)
 | 
					 | 
				
			||||||
                        args->freg[freg++] = start;
 | 
					 | 
				
			||||||
                    ret_t = (size > 4) ? VT_DOUBLE : VT_FLOAT;
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    ret_t = VT_LDOUBLE;
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					            case x86_64_mode_x87:
 | 
				
			||||||
 | 
					                *reg_count = 1;
 | 
				
			||||||
 | 
					                ret_t = VT_LDOUBLE;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case x86_64_mode_sse:
 | 
				
			||||||
 | 
					                if (size > 8) {
 | 
				
			||||||
 | 
					                    *reg_count = 2;
 | 
				
			||||||
 | 
					                    ret_t = VT_QFLOAT;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    *reg_count = 1;
 | 
				
			||||||
 | 
					                    ret_t = (size > 4) ? VT_DOUBLE : VT_FLOAT;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            default: break; /* nothing to be done for x86_64_mode_memory and x86_64_mode_none*/
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -1187,8 +1140,8 @@ ST_FUNC int classify_x86_64_va_arg(CType *ty)
 | 
				
			||||||
    enum __va_arg_type {
 | 
					    enum __va_arg_type {
 | 
				
			||||||
        __va_gen_reg, __va_float_reg, __va_stack
 | 
					        __va_gen_reg, __va_float_reg, __va_stack
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    int size, align;
 | 
					    int size, align, reg_count;
 | 
				
			||||||
    X86_64_Mode mode = classify_x86_64_arg(ty, NULL, &size, &align, NULL);
 | 
					    X86_64_Mode mode = classify_x86_64_arg(ty, NULL, &size, &align, ®_count);
 | 
				
			||||||
    switch (mode) {
 | 
					    switch (mode) {
 | 
				
			||||||
    default: return __va_stack;
 | 
					    default: return __va_stack;
 | 
				
			||||||
    case x86_64_mode_integer: return __va_gen_reg;
 | 
					    case x86_64_mode_integer: return __va_gen_reg;
 | 
				
			||||||
| 
						 | 
					@ -1196,57 +1149,14 @@ ST_FUNC int classify_x86_64_va_arg(CType *ty)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int regargs_iregs(RegArgs *args)
 | 
					/* Return the number of registers needed to return the struct, or 0 if
 | 
				
			||||||
 | 
					   returning via struct pointer. */
 | 
				
			||||||
 | 
					ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int i;
 | 
					    int size, align, reg_count;
 | 
				
			||||||
    int ret = 0;
 | 
					 | 
				
			||||||
    for(i=0; i<REG_ARGS_MAX; i++) {
 | 
					 | 
				
			||||||
        if(args->ireg[i] != -1)
 | 
					 | 
				
			||||||
            ret++;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int regargs_fregs(RegArgs *args)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int i;
 | 
					 | 
				
			||||||
    int ret = 0;
 | 
					 | 
				
			||||||
    for(i=0; i<REG_ARGS_MAX; i++) {
 | 
					 | 
				
			||||||
        if(args->freg[i] != -1)
 | 
					 | 
				
			||||||
            ret++;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Count the total number of registers used by args */
 | 
					 | 
				
			||||||
ST_FUNC int regargs_nregs(RegArgs *args)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int i;
 | 
					 | 
				
			||||||
    int ret = 0;
 | 
					 | 
				
			||||||
    for(i=0; i<REG_ARGS_MAX; i++) {
 | 
					 | 
				
			||||||
        if(args->ireg[i] != -1)
 | 
					 | 
				
			||||||
            ret++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(args->freg[i] != -1)
 | 
					 | 
				
			||||||
            ret++;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize, RegArgs *args)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int size, align;
 | 
					 | 
				
			||||||
    X86_64_Mode mode;
 | 
					 | 
				
			||||||
    *ret_align = 1; // Never have to re-align return values for x86-64
 | 
					    *ret_align = 1; // Never have to re-align return values for x86-64
 | 
				
			||||||
    *regsize = 8;
 | 
					    *regsize = 8;
 | 
				
			||||||
 | 
					    return (classify_x86_64_arg(vt, ret, &size, &align, ®_count) != x86_64_mode_memory);
 | 
				
			||||||
    mode = classify_x86_64_arg(vt, ret, &size, &align, args);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return mode != x86_64_mode_memory &&
 | 
					 | 
				
			||||||
        mode != x86_64_mode_none;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define REGN 6
 | 
					#define REGN 6
 | 
				
			||||||
| 
						 | 
					@ -1269,28 +1179,18 @@ void gfunc_call(int nb_args)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    X86_64_Mode mode;
 | 
					    X86_64_Mode mode;
 | 
				
			||||||
    CType type;
 | 
					    CType type;
 | 
				
			||||||
    int size, align, r, args_size, stack_adjust, run_start, run_end, i;
 | 
					    int size, align, r, args_size, stack_adjust, run_start, run_end, i, reg_count;
 | 
				
			||||||
    int nb_reg_args = 0;
 | 
					    int nb_reg_args = 0;
 | 
				
			||||||
    int nb_sse_args = 0;
 | 
					    int nb_sse_args = 0;
 | 
				
			||||||
    int sse_reg = 0, gen_reg = 0;
 | 
					    int sse_reg, gen_reg;
 | 
				
			||||||
    RegArgs *reg_args = alloca(nb_args * sizeof *reg_args);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* calculate the number of integer/float register arguments */
 | 
					    /* calculate the number of integer/float register arguments */
 | 
				
			||||||
    for(i = nb_args - 1; i >= 0; i--) {
 | 
					    for(i = 0; i < nb_args; i++) {
 | 
				
			||||||
        int fregs, iregs;
 | 
					        mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count);
 | 
				
			||||||
        mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_args[i]);
 | 
					        if (mode == x86_64_mode_sse)
 | 
				
			||||||
        fregs = regargs_fregs(®_args[i]);
 | 
					            nb_sse_args += reg_count;
 | 
				
			||||||
        iregs = regargs_iregs(®_args[i]);
 | 
					        else if (mode == x86_64_mode_integer)
 | 
				
			||||||
 | 
					            nb_reg_args += reg_count;
 | 
				
			||||||
        nb_sse_args += fregs;
 | 
					 | 
				
			||||||
        nb_reg_args += iregs;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (sse_reg + fregs > 8 || gen_reg + iregs > REGN) {
 | 
					 | 
				
			||||||
            regargs_init(®_args[i]);
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            sse_reg += fregs;
 | 
					 | 
				
			||||||
            gen_reg += iregs;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* arguments are collected in runs. Each run is a collection of 8-byte aligned arguments
 | 
					    /* arguments are collected in runs. Each run is a collection of 8-byte aligned arguments
 | 
				
			||||||
| 
						 | 
					@ -1309,14 +1209,27 @@ void gfunc_call(int nb_args)
 | 
				
			||||||
        run_end = nb_args;
 | 
					        run_end = nb_args;
 | 
				
			||||||
        stack_adjust = 0;
 | 
					        stack_adjust = 0;
 | 
				
			||||||
        for(i = run_start; (i < nb_args) && (run_end == nb_args); i++) {
 | 
					        for(i = run_start; (i < nb_args) && (run_end == nb_args); i++) {
 | 
				
			||||||
            int stack = regargs_nregs(®_args[i]) == 0;
 | 
					            mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count);
 | 
				
			||||||
            classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, NULL);
 | 
					            switch (mode) {
 | 
				
			||||||
 | 
					            case x86_64_mode_memory:
 | 
				
			||||||
            if (stack) {
 | 
					            case x86_64_mode_x87:
 | 
				
			||||||
 | 
					            stack_arg:
 | 
				
			||||||
                if (align == 16)
 | 
					                if (align == 16)
 | 
				
			||||||
                    run_end = i;
 | 
					                    run_end = i;
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                    stack_adjust += size;
 | 
					                    stack_adjust += size;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					            case x86_64_mode_sse:
 | 
				
			||||||
 | 
					                sse_reg -= reg_count;
 | 
				
			||||||
 | 
					                if (sse_reg + reg_count > 8) goto stack_arg;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            case x86_64_mode_integer:
 | 
				
			||||||
 | 
					                gen_reg -= reg_count;
 | 
				
			||||||
 | 
					                if (gen_reg + reg_count > REGN) goto stack_arg;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
						    default: break; /* nothing to be done for x86_64_mode_none */
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
| 
						 | 
					@ -1336,27 +1249,32 @@ void gfunc_call(int nb_args)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        for(i = run_start; i < run_end;) {
 | 
					        for(i = run_start; i < run_end;) {
 | 
				
			||||||
            int arg_stored = regargs_nregs(®_args[i]) == 0;
 | 
					 | 
				
			||||||
            SValue tmp;
 | 
					 | 
				
			||||||
            RegArgs args;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (!arg_stored) {
 | 
					 | 
				
			||||||
                ++i;
 | 
					 | 
				
			||||||
                continue;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            /* Swap argument to top, it will possibly be changed here,
 | 
					            /* Swap argument to top, it will possibly be changed here,
 | 
				
			||||||
              and might use more temps. At the end of the loop we keep
 | 
					              and might use more temps. At the end of the loop we keep
 | 
				
			||||||
              in on the stack and swap it back to its original position
 | 
					              in on the stack and swap it back to its original position
 | 
				
			||||||
              if it is a register. */
 | 
					              if it is a register. */
 | 
				
			||||||
            tmp = vtop[0];
 | 
					            SValue tmp = vtop[0];
 | 
				
			||||||
 | 
					            int arg_stored = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            vtop[0] = vtop[-i];
 | 
					            vtop[0] = vtop[-i];
 | 
				
			||||||
            vtop[-i] = tmp;
 | 
					            vtop[-i] = tmp;
 | 
				
			||||||
            
 | 
					            mode = classify_x86_64_arg(&vtop->type, NULL, &size, &align, ®_count);
 | 
				
			||||||
            classify_x86_64_arg(&vtop->type, NULL, &size, &align, &args);
 | 
					 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            switch (vtop->type.t & VT_BTYPE) {
 | 
					            switch (vtop->type.t & VT_BTYPE) {
 | 
				
			||||||
            case VT_STRUCT:
 | 
					            case VT_STRUCT:
 | 
				
			||||||
 | 
					                if (mode == x86_64_mode_sse) {
 | 
				
			||||||
 | 
					                    if (sse_reg > 8)
 | 
				
			||||||
 | 
					                        sse_reg -= reg_count;
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                        arg_stored = 0;
 | 
				
			||||||
 | 
					                } else if (mode == x86_64_mode_integer) {
 | 
				
			||||||
 | 
					                    if (gen_reg > REGN)
 | 
				
			||||||
 | 
					                        gen_reg -= reg_count;
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                        arg_stored = 0;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                if (arg_stored) {
 | 
				
			||||||
                    /* allocate the necessary size on stack */
 | 
					                    /* allocate the necessary size on stack */
 | 
				
			||||||
                    o(0x48);
 | 
					                    o(0x48);
 | 
				
			||||||
                    oad(0xec81, size); /* sub $xxx, %rsp */
 | 
					                    oad(0xec81, size); /* sub $xxx, %rsp */
 | 
				
			||||||
| 
						 | 
					@ -1368,6 +1286,7 @@ void gfunc_call(int nb_args)
 | 
				
			||||||
                    vswap();
 | 
					                    vswap();
 | 
				
			||||||
                    vstore();
 | 
					                    vstore();
 | 
				
			||||||
                    args_size += size;
 | 
					                    args_size += size;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
                
 | 
					                
 | 
				
			||||||
            case VT_LDOUBLE:
 | 
					            case VT_LDOUBLE:
 | 
				
			||||||
| 
						 | 
					@ -1376,6 +1295,9 @@ void gfunc_call(int nb_args)
 | 
				
			||||||
                
 | 
					                
 | 
				
			||||||
            case VT_FLOAT:
 | 
					            case VT_FLOAT:
 | 
				
			||||||
            case VT_DOUBLE:
 | 
					            case VT_DOUBLE:
 | 
				
			||||||
 | 
					                assert(mode == x86_64_mode_sse);
 | 
				
			||||||
 | 
					                if (sse_reg > 8) {
 | 
				
			||||||
 | 
					                    --sse_reg;
 | 
				
			||||||
                    r = gv(RC_FLOAT);
 | 
					                    r = gv(RC_FLOAT);
 | 
				
			||||||
                    o(0x50); /* push $rax */
 | 
					                    o(0x50); /* push $rax */
 | 
				
			||||||
                    /* movq %xmmN, (%rsp) */
 | 
					                    /* movq %xmmN, (%rsp) */
 | 
				
			||||||
| 
						 | 
					@ -1383,36 +1305,47 @@ void gfunc_call(int nb_args)
 | 
				
			||||||
                    o(0x04 + REG_VALUE(r)*8);
 | 
					                    o(0x04 + REG_VALUE(r)*8);
 | 
				
			||||||
                    o(0x24);
 | 
					                    o(0x24);
 | 
				
			||||||
                    args_size += size;
 | 
					                    args_size += size;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    arg_stored = 0;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
                
 | 
					                
 | 
				
			||||||
            default:
 | 
					            default:
 | 
				
			||||||
 | 
					                assert(mode == x86_64_mode_integer);
 | 
				
			||||||
                /* simple type */
 | 
					                /* simple type */
 | 
				
			||||||
                /* XXX: implicit cast ? */
 | 
					                /* XXX: implicit cast ? */
 | 
				
			||||||
 | 
					                if (gen_reg > REGN) {
 | 
				
			||||||
                    --gen_reg;
 | 
					                    --gen_reg;
 | 
				
			||||||
                    r = gv(RC_INT);
 | 
					                    r = gv(RC_INT);
 | 
				
			||||||
                    orex(0,r,0,0x50 + REG_VALUE(r)); /* push r */
 | 
					                    orex(0,r,0,0x50 + REG_VALUE(r)); /* push r */
 | 
				
			||||||
                    args_size += size;
 | 
					                    args_size += size;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    arg_stored = 0;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            /* And swap the argument back to its original position.  */
 | 
					            /* And swap the argument back to it's original position.  */
 | 
				
			||||||
            tmp = vtop[0];
 | 
					            tmp = vtop[0];
 | 
				
			||||||
            vtop[0] = vtop[-i];
 | 
					            vtop[0] = vtop[-i];
 | 
				
			||||||
            vtop[-i] = tmp;
 | 
					            vtop[-i] = tmp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (arg_stored) {
 | 
				
			||||||
              vrotb(i+1);
 | 
					              vrotb(i+1);
 | 
				
			||||||
              assert((vtop->type.t == tmp.type.t) && (vtop->r == tmp.r));
 | 
					              assert((vtop->type.t == tmp.type.t) && (vtop->r == tmp.r));
 | 
				
			||||||
              vpop();
 | 
					              vpop();
 | 
				
			||||||
            memmove(reg_args + i, reg_args + i + 1, (nb_args - i - 1) * sizeof *reg_args);
 | 
					 | 
				
			||||||
              --nb_args;
 | 
					              --nb_args;
 | 
				
			||||||
              --run_end;
 | 
					              --run_end;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					              ++i;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* handle 16 byte aligned arguments at end of run */
 | 
					        /* handle 16 byte aligned arguments at end of run */
 | 
				
			||||||
        run_start = i = run_end;
 | 
					        run_start = i = run_end;
 | 
				
			||||||
        while (i < nb_args) {
 | 
					        while (i < nb_args) {
 | 
				
			||||||
            /* Rotate argument to top since it will always be popped */
 | 
					            /* Rotate argument to top since it will always be popped */
 | 
				
			||||||
            mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, NULL);
 | 
					            mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count);
 | 
				
			||||||
            if (align != 16)
 | 
					            if (align != 16)
 | 
				
			||||||
              break;
 | 
					              break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1442,7 +1375,6 @@ void gfunc_call(int nb_args)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            vpop();
 | 
					            vpop();
 | 
				
			||||||
            memmove(reg_args + i, reg_args + i + 1, (nb_args - i - 1) * sizeof *reg_args);
 | 
					 | 
				
			||||||
            --nb_args;
 | 
					            --nb_args;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -1450,16 +1382,6 @@ void gfunc_call(int nb_args)
 | 
				
			||||||
    /* XXX This should be superfluous.  */
 | 
					    /* XXX This should be superfluous.  */
 | 
				
			||||||
    save_regs(0); /* save used temporary registers */
 | 
					    save_regs(0); /* save used temporary registers */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* recalculate the number of register arguments there actually
 | 
					 | 
				
			||||||
     * are. This is slow but more obviously correct than using the
 | 
					 | 
				
			||||||
     * old counts. */
 | 
					 | 
				
			||||||
    gen_reg = 0;
 | 
					 | 
				
			||||||
    sse_reg = 0;
 | 
					 | 
				
			||||||
    for(i = 0; i < nb_args; i++) {
 | 
					 | 
				
			||||||
        gen_reg += regargs_iregs(®_args[i]);
 | 
					 | 
				
			||||||
        sse_reg += regargs_fregs(®_args[i]);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* then, we prepare register passing arguments.
 | 
					    /* then, we prepare register passing arguments.
 | 
				
			||||||
       Note that we cannot set RDX and RCX in this loop because gv()
 | 
					       Note that we cannot set RDX and RCX in this loop because gv()
 | 
				
			||||||
       may break these temporary registers. Let's use R10 and R11
 | 
					       may break these temporary registers. Let's use R10 and R11
 | 
				
			||||||
| 
						 | 
					@ -1467,62 +1389,40 @@ void gfunc_call(int nb_args)
 | 
				
			||||||
    assert(gen_reg <= REGN);
 | 
					    assert(gen_reg <= REGN);
 | 
				
			||||||
    assert(sse_reg <= 8);
 | 
					    assert(sse_reg <= 8);
 | 
				
			||||||
    for(i = 0; i < nb_args; i++) {
 | 
					    for(i = 0; i < nb_args; i++) {
 | 
				
			||||||
        RegArgs args;
 | 
					        mode = classify_x86_64_arg(&vtop->type, &type, &size, &align, ®_count);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        args = reg_args[i];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* Alter stack entry type so that gv() knows how to treat it */
 | 
					        /* Alter stack entry type so that gv() knows how to treat it */
 | 
				
			||||||
        if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
 | 
					        vtop->type = type;
 | 
				
			||||||
            int k;
 | 
					        if (mode == x86_64_mode_sse) {
 | 
				
			||||||
 | 
					            if (reg_count == 2) {
 | 
				
			||||||
            for(k=REG_ARGS_MAX-1; k>=0; k--) {
 | 
					                sse_reg -= 2;
 | 
				
			||||||
                if (args.freg[k] == -1)
 | 
					                gv(RC_FRET); /* Use pair load into xmm0 & xmm1 */
 | 
				
			||||||
                    continue;
 | 
					                if (sse_reg) { /* avoid redundant movaps %xmm0, %xmm0 */
 | 
				
			||||||
 | 
					                    /* movaps %xmm0, %xmmN */
 | 
				
			||||||
                sse_reg--;
 | 
					                    o(0x280f);
 | 
				
			||||||
                assert(sse_reg >= 0);
 | 
					                    o(0xc0 + (sse_reg << 3));
 | 
				
			||||||
 | 
					                    /* movaps %xmm1, %xmmN */
 | 
				
			||||||
                vdup();
 | 
					                    o(0x280f);
 | 
				
			||||||
                vtop->type.t = VT_DOUBLE;
 | 
					                    o(0xc1 + ((sse_reg+1) << 3));
 | 
				
			||||||
                vtop->c.ull += args.freg[k];
 | 
					 | 
				
			||||||
                gv(RC_XMM0 << sse_reg);
 | 
					 | 
				
			||||||
                vpop();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            for(k=REG_ARGS_MAX-1; k>=0; k--) {
 | 
					 | 
				
			||||||
                int d;
 | 
					 | 
				
			||||||
                if (args.ireg[k] == -1)
 | 
					 | 
				
			||||||
                    continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                gen_reg--;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                vdup();
 | 
					 | 
				
			||||||
                vtop->type.t = VT_LLONG;
 | 
					 | 
				
			||||||
                vtop->c.ull += args.ireg[k];
 | 
					 | 
				
			||||||
                r = gv(RC_INT);
 | 
					 | 
				
			||||||
                d = arg_prepare_reg(gen_reg);
 | 
					 | 
				
			||||||
                orex(1,d,r,0x89); /* mov */
 | 
					 | 
				
			||||||
                o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d));
 | 
					 | 
				
			||||||
                vpop();
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
            /* XXX is it really necessary to set vtop->type? */
 | 
					                assert(reg_count == 1);
 | 
				
			||||||
            classify_x86_64_arg(&vtop->type, &type, &size, &align, NULL);
 | 
					 | 
				
			||||||
            vtop->type = type;
 | 
					 | 
				
			||||||
            if (args.freg[0] != -1) {
 | 
					 | 
				
			||||||
                --sse_reg;
 | 
					                --sse_reg;
 | 
				
			||||||
                /* Load directly to register */
 | 
					                /* Load directly to register */
 | 
				
			||||||
                gv(RC_XMM0 << sse_reg);
 | 
					                gv(RC_XMM0 << sse_reg);
 | 
				
			||||||
            } else if (args.ireg[0] != -1) {
 | 
					            }
 | 
				
			||||||
                int d;
 | 
					        } else if (mode == x86_64_mode_integer) {
 | 
				
			||||||
            /* simple type */
 | 
					            /* simple type */
 | 
				
			||||||
            /* XXX: implicit cast ? */
 | 
					            /* XXX: implicit cast ? */
 | 
				
			||||||
                gen_reg--;
 | 
					            int d;
 | 
				
			||||||
 | 
					            gen_reg -= reg_count;
 | 
				
			||||||
            r = gv(RC_INT);
 | 
					            r = gv(RC_INT);
 | 
				
			||||||
            d = arg_prepare_reg(gen_reg);
 | 
					            d = arg_prepare_reg(gen_reg);
 | 
				
			||||||
            orex(1,d,r,0x89); /* mov */
 | 
					            orex(1,d,r,0x89); /* mov */
 | 
				
			||||||
            o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d));
 | 
					            o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d));
 | 
				
			||||||
            } else {
 | 
					            if (reg_count == 2) {
 | 
				
			||||||
                assert(0);
 | 
					                d = arg_prepare_reg(gen_reg+1);
 | 
				
			||||||
 | 
					                orex(1,d,vtop->r2,0x89); /* mov */
 | 
				
			||||||
 | 
					                o(0xc0 + REG_VALUE(vtop->r2) * 8 + REG_VALUE(d));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        vtop--;
 | 
					        vtop--;
 | 
				
			||||||
| 
						 | 
					@ -1563,7 +1463,7 @@ static void push_arg_reg(int i) {
 | 
				
			||||||
void gfunc_prolog(CType *func_type)
 | 
					void gfunc_prolog(CType *func_type)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    X86_64_Mode mode;
 | 
					    X86_64_Mode mode;
 | 
				
			||||||
    int i, addr, align, size;
 | 
					    int i, addr, align, size, reg_count;
 | 
				
			||||||
    int param_addr = 0, reg_param_index, sse_param_index;
 | 
					    int param_addr = 0, reg_param_index, sse_param_index;
 | 
				
			||||||
    Sym *sym;
 | 
					    Sym *sym;
 | 
				
			||||||
    CType *type;
 | 
					    CType *type;
 | 
				
			||||||
| 
						 | 
					@ -1583,11 +1483,8 @@ void gfunc_prolog(CType *func_type)
 | 
				
			||||||
        /* count the number of seen parameters */
 | 
					        /* count the number of seen parameters */
 | 
				
			||||||
        sym = func_type->ref;
 | 
					        sym = func_type->ref;
 | 
				
			||||||
        while ((sym = sym->next) != NULL) {
 | 
					        while ((sym = sym->next) != NULL) {
 | 
				
			||||||
            RegArgs args;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            type = &sym->type;
 | 
					            type = &sym->type;
 | 
				
			||||||
            mode = classify_x86_64_arg(type, NULL, &size, &align, &args);
 | 
					            mode = classify_x86_64_arg(type, NULL, &size, &align, ®_count);
 | 
				
			||||||
 | 
					 | 
				
			||||||
            switch (mode) {
 | 
					            switch (mode) {
 | 
				
			||||||
            default:
 | 
					            default:
 | 
				
			||||||
            stack_arg:
 | 
					            stack_arg:
 | 
				
			||||||
| 
						 | 
					@ -1595,25 +1492,22 @@ void gfunc_prolog(CType *func_type)
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
                
 | 
					                
 | 
				
			||||||
            case x86_64_mode_integer:
 | 
					            case x86_64_mode_integer:
 | 
				
			||||||
            case x86_64_mode_sse: {
 | 
					                if (seen_reg_num + reg_count <= 8) {
 | 
				
			||||||
                int stack = 0;
 | 
					                    seen_reg_num += reg_count;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
                seen_sse_num += regargs_fregs(&args);
 | 
					 | 
				
			||||||
                seen_reg_num += regargs_iregs(&args);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (seen_reg_num > 8) {
 | 
					 | 
				
			||||||
                    seen_reg_num = 8;
 | 
					                    seen_reg_num = 8;
 | 
				
			||||||
                    stack = 1;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if (seen_sse_num > 8) {
 | 
					 | 
				
			||||||
                    seen_sse_num = 8;
 | 
					 | 
				
			||||||
                    stack = 1;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (stack)
 | 
					 | 
				
			||||||
                    goto stack_arg;
 | 
					                    goto stack_arg;
 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					            case x86_64_mode_sse:
 | 
				
			||||||
 | 
					                if (seen_sse_num + reg_count <= 8) {
 | 
				
			||||||
 | 
					                    seen_sse_num += reg_count;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    seen_sse_num = 8;
 | 
				
			||||||
 | 
					                    goto stack_arg;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1650,7 +1544,7 @@ void gfunc_prolog(CType *func_type)
 | 
				
			||||||
    /* if the function returns a structure, then add an
 | 
					    /* if the function returns a structure, then add an
 | 
				
			||||||
       implicit pointer parameter */
 | 
					       implicit pointer parameter */
 | 
				
			||||||
    func_vt = sym->type;
 | 
					    func_vt = sym->type;
 | 
				
			||||||
    mode = classify_x86_64_arg(&func_vt, NULL, &size, &align, NULL);
 | 
					    mode = classify_x86_64_arg(&func_vt, NULL, &size, &align, ®_count);
 | 
				
			||||||
    if (mode == x86_64_mode_memory) {
 | 
					    if (mode == x86_64_mode_memory) {
 | 
				
			||||||
        push_arg_reg(reg_param_index);
 | 
					        push_arg_reg(reg_param_index);
 | 
				
			||||||
        func_vc = loc;
 | 
					        func_vc = loc;
 | 
				
			||||||
| 
						 | 
					@ -1658,40 +1552,19 @@ void gfunc_prolog(CType *func_type)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    /* define parameters */
 | 
					    /* define parameters */
 | 
				
			||||||
    while ((sym = sym->next) != NULL) {
 | 
					    while ((sym = sym->next) != NULL) {
 | 
				
			||||||
        RegArgs args;
 | 
					 | 
				
			||||||
        int reg_count_integer = 0;
 | 
					 | 
				
			||||||
        int reg_count_sse = 0;
 | 
					 | 
				
			||||||
        int arg_stored = 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        type = &sym->type;
 | 
					        type = &sym->type;
 | 
				
			||||||
        mode = classify_x86_64_arg(type, NULL, &size, &align, &args);
 | 
					        mode = classify_x86_64_arg(type, NULL, &size, &align, ®_count);
 | 
				
			||||||
        reg_count_integer = regargs_iregs(&args);
 | 
					 | 
				
			||||||
        reg_count_sse = regargs_fregs(&args);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        switch (mode) {
 | 
					        switch (mode) {
 | 
				
			||||||
        case x86_64_mode_integer:
 | 
					 | 
				
			||||||
        case x86_64_mode_sse:
 | 
					        case x86_64_mode_sse:
 | 
				
			||||||
            if (reg_count_integer || reg_count_sse) {
 | 
					            if (sse_param_index + reg_count <= 8) {
 | 
				
			||||||
                if ((reg_count_sse == 0 || sse_param_index + reg_count_sse <= 8) &&
 | 
					 | 
				
			||||||
                    (reg_count_integer == 0 || reg_param_index + reg_count_integer <= REGN)) {
 | 
					 | 
				
			||||||
                    /* argument fits into registers */
 | 
					 | 
				
			||||||
                    arg_stored = 0;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (!arg_stored) {
 | 
					 | 
				
			||||||
                /* save arguments passed by register */
 | 
					                /* save arguments passed by register */
 | 
				
			||||||
                loc -= (reg_count_sse + reg_count_integer) * 8;
 | 
					                loc -= reg_count * 8;
 | 
				
			||||||
                param_addr = loc;
 | 
					                param_addr = loc;
 | 
				
			||||||
                for (i = 0; i < reg_count_sse; ++i) {
 | 
					                for (i = 0; i < reg_count; ++i) {
 | 
				
			||||||
                    o(0xd60f66); /* movq */
 | 
					                    o(0xd60f66); /* movq */
 | 
				
			||||||
                    gen_modrm(sse_param_index, VT_LOCAL, NULL, param_addr + args.freg[i]);
 | 
					                    gen_modrm(sse_param_index, VT_LOCAL, NULL, param_addr + i*8);
 | 
				
			||||||
                    ++sse_param_index;
 | 
					                    ++sse_param_index;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                for (i = 0; i < reg_count_integer; ++i) {
 | 
					 | 
				
			||||||
                    gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, param_addr + args.ireg[i]);
 | 
					 | 
				
			||||||
                    ++reg_param_index;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                addr = (addr + align - 1) & -align;
 | 
					                addr = (addr + align - 1) & -align;
 | 
				
			||||||
                param_addr = addr;
 | 
					                param_addr = addr;
 | 
				
			||||||
| 
						 | 
					@ -1705,6 +1578,23 @@ void gfunc_prolog(CType *func_type)
 | 
				
			||||||
            param_addr = addr;
 | 
					            param_addr = addr;
 | 
				
			||||||
            addr += size;
 | 
					            addr += size;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					        case x86_64_mode_integer: {
 | 
				
			||||||
 | 
					            if (reg_param_index + reg_count <= REGN) {
 | 
				
			||||||
 | 
					                /* save arguments passed by register */
 | 
				
			||||||
 | 
					                loc -= reg_count * 8;
 | 
				
			||||||
 | 
					                param_addr = loc;
 | 
				
			||||||
 | 
					                for (i = 0; i < reg_count; ++i) {
 | 
				
			||||||
 | 
					                    gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, param_addr + i*8);
 | 
				
			||||||
 | 
					                    ++reg_param_index;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                addr = (addr + align - 1) & -align;
 | 
				
			||||||
 | 
					                param_addr = addr;
 | 
				
			||||||
 | 
					                addr += size;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
	default: break; /* nothing to be done for x86_64_mode_none */
 | 
						default: break; /* nothing to be done for x86_64_mode_none */
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        sym_push(sym->v & ~SYM_FIELD, type,
 | 
					        sym_push(sym->v & ~SYM_FIELD, type,
 | 
				
			||||||
| 
						 | 
					@ -2343,7 +2233,8 @@ ST_FUNC void gen_vla_alloc(CType *type, int align) {
 | 
				
			||||||
    gfunc_call(1);
 | 
					    gfunc_call(1);
 | 
				
			||||||
    vset(type, REG_IRET, 0);
 | 
					    vset(type, REG_IRET, 0);
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
    int r = gv(RC_INT); /* allocation size */
 | 
					    int r;
 | 
				
			||||||
 | 
					    r = gv(RC_INT); /* allocation size */
 | 
				
			||||||
    /* sub r,%rsp */
 | 
					    /* sub r,%rsp */
 | 
				
			||||||
    o(0x2b48);
 | 
					    o(0x2b48);
 | 
				
			||||||
    o(0xe0 | REG_VALUE(r));
 | 
					    o(0xe0 | REG_VALUE(r));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue