aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arm-gen.c8
-rw-r--r--arm64-gen.c2
-rw-r--r--c67-gen.c2
-rw-r--r--i386-gen.c3
-rw-r--r--tcc.h2
-rw-r--r--tccgen.c20
-rw-r--r--x86_64-gen.c6
7 files changed, 26 insertions, 17 deletions
diff --git a/arm-gen.c b/arm-gen.c
index 3bb5326..0201cd2 100644
--- a/arm-gen.c
+++ b/arm-gen.c
@@ -869,18 +869,20 @@ int floats_in_core_regs(SValue *sval)
/* 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) {
+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) {
#ifdef TCC_ARM_EABI
int size, align;
size = type_size(vt, &align);
if (float_abi == ARM_HARD_FLOAT && !variadic &&
(is_float(vt->t) || is_hgen_float_aggr(vt))) {
*ret_align = 8;
+ *regsize = 8;
ret->ref = NULL;
ret->t = VT_DOUBLE;
return (size + 7) >> 3;
} else if (size <= 4) {
*ret_align = 4;
+ *regsize = 4;
ret->ref = NULL;
ret->t = VT_INT;
return 1;
@@ -1255,7 +1257,7 @@ void gfunc_call(int nb_args)
void gfunc_prolog(CType *func_type)
{
Sym *sym,*sym2;
- int n, nf, size, align, struct_ret = 0;
+ int n, nf, size, align, rs, struct_ret = 0;
int addr, pn, sn; /* pn=core, sn=stack */
CType ret_type;
@@ -1269,7 +1271,7 @@ void gfunc_prolog(CType *func_type)
n = nf = 0;
if ((func_vt.t & VT_BTYPE) == VT_STRUCT &&
- !gfunc_sret(&func_vt, func_var, &ret_type, &align))
+ !gfunc_sret(&func_vt, func_var, &ret_type, &align, &rs))
{
n++;
struct_ret = 1;
diff --git a/arm64-gen.c b/arm64-gen.c
index 3581e5d..0c435d9 100644
--- a/arm64-gen.c
+++ b/arm64-gen.c
@@ -1196,7 +1196,7 @@ ST_FUNC void gen_va_arg(CType *t)
}
}
-ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align)
+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize)
{
return 0;
}
diff --git a/c67-gen.c b/c67-gen.c
index 5a6fd56..2182518 100644
--- a/c67-gen.c
+++ b/c67-gen.c
@@ -1881,7 +1881,7 @@ static void gcall_or_jmp(int is_jmp)
/* 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) {
+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
return 0;
}
diff --git a/i386-gen.c b/i386-gen.c
index 9bdf998..c2db3d0 100644
--- a/i386-gen.c
+++ b/i386-gen.c
@@ -376,12 +376,13 @@ static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };
/* 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)
+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)
{
#ifdef TCC_TARGET_PE
int size, align;
*ret_align = 1; // Never have to re-align return values for x86
+ *regsize = 4;
size = type_size(vt, &align);
if (size > 8) {
return 0;
diff --git a/tcc.h b/tcc.h
index 7d53b9b..759d3f4 100644
--- a/tcc.h
+++ b/tcc.h
@@ -1327,7 +1327,7 @@ ST_FUNC void gsym_addr(int t, int a);
ST_FUNC void gsym(int t);
ST_FUNC void load(int r, SValue *sv);
ST_FUNC void store(int r, SValue *v);
-ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align);
+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize);
ST_FUNC void gfunc_call(int nb_args);
ST_FUNC void gfunc_prolog(CType *func_type);
ST_FUNC void gfunc_epilog(void);
diff --git a/tccgen.c b/tccgen.c
index 52541e2..58c8b13 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -4153,7 +4153,7 @@ ST_FUNC void unary(void)
} else if (tok == '(') {
SValue ret;
Sym *sa;
- int nb_args, ret_nregs, ret_align, variadic;
+ int nb_args, ret_nregs, ret_align, regsize, variadic;
/* function call */
if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
@@ -4179,7 +4179,7 @@ ST_FUNC void unary(void)
if ((s->type.t & VT_BTYPE) == VT_STRUCT) {
variadic = (s->c == FUNC_ELLIPSIS);
ret_nregs = gfunc_sret(&s->type, variadic, &ret.type,
- &ret_align);
+ &ret_align, &regsize);
if (!ret_nregs) {
/* get some space for the returned structure */
size = type_size(&s->type, &align);
@@ -4259,6 +4259,10 @@ ST_FUNC void unary(void)
int addr, offset;
size = type_size(&s->type, &align);
+ /* We're writing whole regs often, make sure there's enough
+ space. Assume register size is power of 2. */
+ if (regsize > align)
+ align = regsize;
loc = (loc - size) & -align;
addr = loc;
offset = 0;
@@ -4269,8 +4273,7 @@ ST_FUNC void unary(void)
vtop--;
if (--ret_nregs == 0)
break;
- /* XXX: compatible with arm only: ret_align == register_size */
- offset += ret_align;
+ offset += regsize;
}
vset(&s->type, VT_LOCAL | VT_LVAL, addr);
}
@@ -4850,9 +4853,9 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
#else
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
CType type, ret_type;
- int ret_align, ret_nregs;
+ int ret_align, ret_nregs, regsize;
ret_nregs = gfunc_sret(&func_vt, func_var, &ret_type,
- &ret_align);
+ &ret_align, &regsize);
if (0 == ret_nregs) {
/* if returning structure, must copy it to implicit
first pointer arg location */
@@ -4890,9 +4893,10 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
/* We assume that when a structure is returned in multiple
registers, their classes are consecutive values of the
suite s(n) = 2^n */
+ /* XXX This seems confused, if r == 0, this never
+ changes r. */
r <<= 1;
- /* XXX: compatible with arm only: ret_align == register_size */
- vtop->c.i += ret_align;
+ vtop->c.i += regsize;
vtop->r = VT_LOCAL | VT_LVAL;
}
}
diff --git a/x86_64-gen.c b/x86_64-gen.c
index 67aaadc..d5ed4f6 100644
--- a/x86_64-gen.c
+++ b/x86_64-gen.c
@@ -662,9 +662,10 @@ void gen_offs_sp(int b, int r, int d)
/* 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)
+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)
{
int size, align;
+ *regsize = 8;
*ret_align = 1; // Never have to re-align return values for x86-64
size = type_size(vt, &align);
ret->ref = NULL;
@@ -1069,10 +1070,11 @@ ST_FUNC int classify_x86_64_va_arg(CType *ty)
/* 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)
+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)
{
int size, align, reg_count;
*ret_align = 1; // Never have to re-align return values for x86-64
+ *regsize = 8;
return (classify_x86_64_arg(vt, ret, &size, &align, &reg_count) != x86_64_mode_memory);
}