aboutsummaryrefslogtreecommitdiff
path: root/tccgen.c
diff options
context:
space:
mode:
Diffstat (limited to 'tccgen.c')
-rw-r--r--tccgen.c95
1 files changed, 56 insertions, 39 deletions
diff --git a/tccgen.c b/tccgen.c
index 0a6250c..febab11 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -3850,7 +3850,7 @@ ST_FUNC void unary(void)
} else if (tok == '(') {
SValue ret;
Sym *sa;
- int nb_args;
+ int nb_args, sret;
/* function call */
if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
@@ -3874,18 +3874,26 @@ ST_FUNC void unary(void)
ret.r2 = VT_CONST;
/* compute first implicit argument if a structure is returned */
if ((s->type.t & VT_BTYPE) == VT_STRUCT) {
- /* get some space for the returned structure */
- size = type_size(&s->type, &align);
- loc = (loc - size) & -align;
- ret.type = s->type;
- ret.r = VT_LOCAL | VT_LVAL;
- /* pass it as 'int' to avoid structure arg passing
- problems */
- vseti(VT_LOCAL, loc);
- ret.c = vtop->c;
- nb_args++;
+ int ret_align;
+ sret = gfunc_sret(&s->type, &ret.type, &ret_align);
+ if (sret) {
+ /* get some space for the returned structure */
+ size = type_size(&s->type, &align);
+ loc = (loc - size) & -align;
+ ret.type = s->type;
+ ret.r = VT_LOCAL | VT_LVAL;
+ /* pass it as 'int' to avoid structure arg passing
+ problems */
+ vseti(VT_LOCAL, loc);
+ ret.c = vtop->c;
+ nb_args++;
+ }
} else {
- ret.type = s->type;
+ sret = 0;
+ ret.type = s->type;
+ }
+
+ if (!sret) {
/* return in register */
if (is_float(ret.type.t)) {
ret.r = reg_fret(ret.type.t);
@@ -3919,6 +3927,17 @@ ST_FUNC void unary(void)
/* return value */
vsetc(&ret.type, ret.r, &ret.c);
vtop->r2 = ret.r2;
+ /* handle packed struct return */
+ if (((s->type.t & VT_BTYPE) == VT_STRUCT) && !sret) {
+ size = type_size(&s->type, &align);
+ loc = (loc - size) & -align;
+ int addr = loc;
+ vset(&ret.type, VT_LOCAL | VT_LVAL, addr);
+ vswap();
+ vstore();
+ vtop--;
+ vset(&s->type, VT_LOCAL | VT_LVAL, addr);
+ }
} else {
break;
}
@@ -4466,40 +4485,38 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
gexpr();
gen_assign_cast(&func_vt);
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
- CType type;
- /* if returning structure, must copy it to implicit
- first pointer arg location */
-#ifdef TCC_ARM_EABI
- int align, size;
- size = type_size(&func_vt,&align);
- if(size <= 4)
- {
- if((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & 3))
- && (align & 3))
- {
- int addr;
- loc = (loc - size) & -4;
+ CType type, ret_type;
+ int ret_align;
+ if (gfunc_sret(&func_vt, &ret_type, &ret_align)) {
+ /* if returning structure, must copy it to implicit
+ first pointer arg location */
+ type = func_vt;
+ mk_pointer(&type);
+ vset(&type, VT_LOCAL | VT_LVAL, func_vc);
+ indir();
+ vswap();
+ /* copy structure value to pointer */
+ vstore();
+ } else {
+ /* returning structure packed into registers */
+ int size, addr, align;
+ size = type_size(&func_vt,&align);
+ if ((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & (ret_align-1)))
+ && (align & (ret_align-1))) {
+ loc = (loc - size) & -align;
addr = loc;
type = func_vt;
vset(&type, VT_LOCAL | VT_LVAL, addr);
vswap();
vstore();
- vset(&int_type, VT_LOCAL | VT_LVAL, addr);
+ vset(&ret_type, VT_LOCAL | VT_LVAL, addr);
}
- vtop->type = int_type;
- gv(RC_IRET);
- } else {
-#endif
- type = func_vt;
- mk_pointer(&type);
- vset(&type, VT_LOCAL | VT_LVAL, func_vc);
- indir();
- vswap();
- /* copy structure value to pointer */
- vstore();
-#ifdef TCC_ARM_EABI
+ vtop->type = ret_type;
+ if (is_float(ret_type.t))
+ gv(rc_fret(ret_type.t));
+ else
+ gv(RC_IRET);
}
-#endif
} else if (is_float(func_vt.t)) {
gv(rc_fret(func_vt.t));
} else {