From 2bbfaf436f937ace4809d84be812ea1ac7fd7352 Mon Sep 17 00:00:00 2001 From: James Lyon Date: Thu, 18 Apr 2013 17:27:34 +0100 Subject: Tests in abitest.c now work on Win32. I expect that Linux-x86 is probably fine. All other architectures except ARM are definitely broken since I haven't yet implemented gfunc_sret for these, although replicating the current behaviour should be straightforward. --- tccgen.c | 95 ++++++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 56 insertions(+), 39 deletions(-) (limited to 'tccgen.c') 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 { -- cgit v1.3.1