mirror of
https://github.com/mirror/tinycc.git
synced 2025-01-27 06:10:06 +08:00
Revert "fix-mixed-struct (patch by Pip Cet)"
This reverts commit 4e04f67c94
. Requested by grischka.
This commit is contained in:
parent
89ad24e7d6
commit
ef3d38c5c9
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);
|
||||||
|
523
x86_64-gen.c
523
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,79 +1076,61 @@ 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 {
|
||||||
size = type_size(ty, &align);
|
size = type_size(ty, &align);
|
||||||
*psize = (size + 7) & ~7;
|
*psize = (size + 7) & ~7;
|
||||||
*palign = (align + 7) & ~7;
|
*palign = (align + 7) & ~7;
|
||||||
|
|
||||||
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*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ret->ref = NULL;
|
ret->ref = NULL;
|
||||||
ret->t = ret_t;
|
ret->t = ret_t;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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,38 +1249,44 @@ 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:
|
||||||
/* allocate the necessary size on stack */
|
if (mode == x86_64_mode_sse) {
|
||||||
o(0x48);
|
if (sse_reg > 8)
|
||||||
oad(0xec81, size); /* sub $xxx, %rsp */
|
sse_reg -= reg_count;
|
||||||
/* generate structure store */
|
else
|
||||||
r = get_reg(RC_INT);
|
arg_stored = 0;
|
||||||
orex(1, r, 0, 0x89); /* mov %rsp, r */
|
} else if (mode == x86_64_mode_integer) {
|
||||||
o(0xe0 + REG_VALUE(r));
|
if (gen_reg > REGN)
|
||||||
vset(&vtop->type, r | VT_LVAL, 0);
|
gen_reg -= reg_count;
|
||||||
vswap();
|
else
|
||||||
vstore();
|
arg_stored = 0;
|
||||||
args_size += size;
|
}
|
||||||
|
|
||||||
|
if (arg_stored) {
|
||||||
|
/* allocate the necessary size on stack */
|
||||||
|
o(0x48);
|
||||||
|
oad(0xec81, size); /* sub $xxx, %rsp */
|
||||||
|
/* generate structure store */
|
||||||
|
r = get_reg(RC_INT);
|
||||||
|
orex(1, r, 0, 0x89); /* mov %rsp, r */
|
||||||
|
o(0xe0 + REG_VALUE(r));
|
||||||
|
vset(&vtop->type, r | VT_LVAL, 0);
|
||||||
|
vswap();
|
||||||
|
vstore();
|
||||||
|
args_size += size;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VT_LDOUBLE:
|
case VT_LDOUBLE:
|
||||||
@ -1376,43 +1295,57 @@ void gfunc_call(int nb_args)
|
|||||||
|
|
||||||
case VT_FLOAT:
|
case VT_FLOAT:
|
||||||
case VT_DOUBLE:
|
case VT_DOUBLE:
|
||||||
r = gv(RC_FLOAT);
|
assert(mode == x86_64_mode_sse);
|
||||||
o(0x50); /* push $rax */
|
if (sse_reg > 8) {
|
||||||
/* movq %xmmN, (%rsp) */
|
--sse_reg;
|
||||||
o(0xd60f66);
|
r = gv(RC_FLOAT);
|
||||||
o(0x04 + REG_VALUE(r)*8);
|
o(0x50); /* push $rax */
|
||||||
o(0x24);
|
/* movq %xmmN, (%rsp) */
|
||||||
args_size += size;
|
o(0xd60f66);
|
||||||
|
o(0x04 + REG_VALUE(r)*8);
|
||||||
|
o(0x24);
|
||||||
|
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 ? */
|
||||||
--gen_reg;
|
if (gen_reg > REGN) {
|
||||||
r = gv(RC_INT);
|
--gen_reg;
|
||||||
orex(0,r,0,0x50 + REG_VALUE(r)); /* push r */
|
r = gv(RC_INT);
|
||||||
args_size += size;
|
orex(0,r,0,0x50 + REG_VALUE(r)); /* push r */
|
||||||
|
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;
|
||||||
|
|
||||||
vrotb(i+1);
|
if (arg_stored) {
|
||||||
assert((vtop->type.t == tmp.type.t) && (vtop->r == tmp.r));
|
vrotb(i+1);
|
||||||
vpop();
|
assert((vtop->type.t == tmp.type.t) && (vtop->r == tmp.r));
|
||||||
memmove(reg_args + i, reg_args + i + 1, (nb_args - i - 1) * sizeof *reg_args);
|
vpop();
|
||||||
--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,24 +1375,13 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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);
|
} else {
|
||||||
vpop();
|
assert(reg_count == 1);
|
||||||
}
|
|
||||||
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 {
|
|
||||||
/* XXX is it really necessary to set vtop->type? */
|
|
||||||
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;
|
||||||
r = gv(RC_INT);
|
gen_reg -= reg_count;
|
||||||
d = arg_prepare_reg(gen_reg);
|
r = gv(RC_INT);
|
||||||
orex(1,d,r,0x89); /* mov */
|
d = arg_prepare_reg(gen_reg);
|
||||||
o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d));
|
orex(1,d,r,0x89); /* mov */
|
||||||
} else {
|
o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d));
|
||||||
assert(0);
|
if (reg_count == 2) {
|
||||||
|
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,37 +1483,31 @@ 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:
|
||||||
seen_stack_size = ((seen_stack_size + align - 1) & -align) + size;
|
seen_stack_size = ((seen_stack_size + align - 1) & -align) + size;
|
||||||
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;
|
||||||
|
|
||||||
|
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;
|
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,
|
||||||
@ -1741,7 +1631,7 @@ void gfunc_epilog(void)
|
|||||||
*bounds_ptr = 0;
|
*bounds_ptr = 0;
|
||||||
|
|
||||||
/* generate bound local allocation */
|
/* generate bound local allocation */
|
||||||
sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
|
sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
|
||||||
func_bound_offset, lbounds_section->data_offset);
|
func_bound_offset, lbounds_section->data_offset);
|
||||||
saved_ind = ind;
|
saved_ind = ind;
|
||||||
ind = func_bound_ind;
|
ind = func_bound_ind;
|
||||||
@ -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…
Reference in New Issue
Block a user