History

Add support for struct > 4B returned via registers

On ARM with hardfloat calling convention, structure containing 4 fields or less of the same float type are returned via float registers. This means that a structure can be returned in up to 4 double registers in a structure is composed of 4 doubles. This commit adds support for return of structures in several registers.

Thomas Preud'homme committed 12 years ago

Commit dcec8671 parent d9d60a15 files · +77 −49Browse files

Unified · Split

5 files
  1. arm-gen.c +30 −18
  2. c67-gen.c +3 −2
  3. i386-gen.c +5 −4
  4. tccgen.c +29 −17
  5. x86_64-gen.c +10 −8
arm-gen.c+30−18
@@ -746,24 +746,6 @@ static void gcall_or_jmp(int is_jmp) · 745 unmodified lines
746746 }
747747 }
748748
749−/* Return 1 if this function returns via an sret pointer, 0 otherwise */
750−ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) {
751−#ifdef TCC_ARM_EABI
752− int size, align;
753− size = type_size(vt, &align);
754− if (size > 4) {
755− return 1;
756− } else {
757− *ret_align = 4;
758− ret->ref = NULL;
759− ret->t = VT_INT;
760− return 0;
761− }
762−#else
763− return 1;
764−#endif
765−}
766−
767749 #ifdef TCC_ARM_HARDFLOAT
768750 /* Return whether a structure is an homogeneous float aggregate or not.
769751 The answer is true if all the elements of the structure are of the same
@@ -831,6 +813,33 @@ int assign_vfpreg(struct avail_regs *avregs, int align, int size) · 61 unmodified lines
831813 }
832814 #endif
833815
816+/* Return the number of registers needed to return the struct, or 0 if
817+ returning via struct pointer. */
818+ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) {
819+#ifdef TCC_ARM_EABI
820+ int size, align;
821+ size = type_size(vt, &align);
822+#ifdef TCC_ARM_HARDFLOAT
823+ if (is_float(vt->t) || is_hgen_float_aggr(vt)) {
824+ *ret_align = 8;
825+ ret->ref = NULL;
826+ ret->t = VT_DOUBLE;
827+ return (size + 7) >> 3;
828+ } else
829+#endif
830+ if (size > 4) {
831+ return 0;
832+ } else {
833+ *ret_align = 4;
834+ ret->ref = NULL;
835+ ret->t = VT_INT;
836+ return 1;
837+ }
838+#else
839+ return 0;
840+#endif
841+}
842+
834843 /* Parameters are classified according to how they are copied to their final
835844 destination for the function call. Because the copying is performed class
836845 after class according to the order in the union below, it is important that
@@ -1198,6 +1207,9 @@ void gfunc_prolog(CType *func_type) · 361 unmodified lines
11981207 n = nf = 0;
11991208 variadic = (func_type->ref->c == FUNC_ELLIPSIS);
12001209 if((func_vt.t & VT_BTYPE) == VT_STRUCT
1210+#ifdef TCC_ARM_HARDFLOAT
1211+ && (variadic || !is_hgen_float_aggr(&func_vt))
1212+#endif
12011213 && type_size(&func_vt,&align) > 4)
12021214 {
12031215 n++;
c67-gen.c+3−2
@@ -1879,10 +1879,11 @@ static void gcall_or_jmp(int is_jmp) · 1878 unmodified lines
18791879 }
18801880 }
18811881
1882−/* Return 1 if this function returns via an sret pointer, 0 otherwise */
1882+/* Return the number of registers needed to return the struct, or 0 if
1883+ returning via struct pointer. */
18831884 ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) {
18841885 *ret_align = 1; // Never have to re-align return values for x86-64
1885− return 1;
1886+ return 0;
18861887 }
18871888
18881889 /* generate function call with address in (vtop->t, vtop->c) and free function
i386-gen.c+5−4
@@ -374,7 +374,8 @@ static void gcall_or_jmp(int is_jmp) · 373 unmodified lines
374374 static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
375375 static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };
376376
377−/* Return 1 if this function returns via an sret pointer, 0 otherwise */
377+/* Return the number of registers needed to return the struct, or 0 if
378+ returning via struct pointer. */
378379 ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align)
379380 {
380381 #ifdef TCC_TARGET_PE
@@ -383,11 +384,11 @@ ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) · 2 unmodified lines
383384 *ret_align = 1; // Never have to re-align return values for x86
384385 size = type_size(vt, &align);
385386 if (size > 8) {
386− return 1;
387+ return 0;
387388 } else if (size > 4) {
388389 ret->ref = NULL;
389390 ret->t = VT_LLONG;
390− return 0;
391+ return 1;
391392 } else {
392393 ret->ref = NULL;
393394 ret->t = VT_INT;
@@ -395,7 +396,7 @@ ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) · 1 unmodified line
395396 }
396397 #else
397398 *ret_align = 1; // Never have to re-align return values for x86
398− return 1;
399+ return 0;
399400 #endif
400401 }
401402
tccgen.c+29−17
@@ -3927,7 +3927,7 @@ ST_FUNC void unary(void) · 3926 unmodified lines
39273927 } else if (tok == '(') {
39283928 SValue ret;
39293929 Sym *sa;
3930− int nb_args, sret;
3930+ int nb_args, sret, ret_align;
39313931
39323932 /* function call */
39333933 if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
@@ -3951,9 +3951,8 @@ ST_FUNC void unary(void) · 17 unmodified lines
39513951 ret.r2 = VT_CONST;
39523952 /* compute first implicit argument if a structure is returned */
39533953 if ((s->type.t & VT_BTYPE) == VT_STRUCT) {
3954− int ret_align;
39553954 sret = gfunc_sret(&s->type, &ret.type, &ret_align);
3956− if (sret) {
3955+ if (!sret) {
39573956 /* get some space for the returned structure */
39583957 size = type_size(&s->type, &align);
39593958 loc = (loc - size) & -align;
@@ -3966,11 +3965,11 @@ ST_FUNC void unary(void) · 6 unmodified lines
39663965 nb_args++;
39673966 }
39683967 } else {
3969− sret = 0;
3968+ sret = 1;
39703969 ret.type = s->type;
39713970 }
39723971
3973− if (!sret) {
3972+ if (sret) {
39743973 /* return in register */
39753974 if (is_float(ret.type.t)) {
39763975 ret.r = reg_fret(ret.type.t);
@@ -4010,18 +4009,23 @@ ST_FUNC void unary(void) · 33 unmodified lines
40104009 vtop -= (nb_args + 1);
40114010 }
40124011 /* return value */
4013− vsetc(&ret.type, ret.r, &ret.c);
4014− vtop->r2 = ret.r2;
4012+ for (r = ret.r + sret + !sret; r-- > ret.r;) {
4013+ vsetc(&ret.type, r, &ret.c);
4014+ vtop->r2 = ret.r2; /* Loop only happens when r2 is VT_CONST */
4015+ }
40154016 /* handle packed struct return */
4016− if (((s->type.t & VT_BTYPE) == VT_STRUCT) && !sret) {
4017− int addr;
4017+ if (((s->type.t & VT_BTYPE) == VT_STRUCT) && sret) {
4018+ int addr, offset;
4019+
40184020 size = type_size(&s->type, &align);
40194021 loc = (loc - size) & -align;
40204022 addr = loc;
4021− vset(&ret.type, VT_LOCAL | VT_LVAL, addr);
4022− vswap();
4023− vstore();
4024− vtop--;
4023+ for(offset = 0; offset < size; offset += ret_align) {
4024+ vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset);
4025+ vswap();
4026+ vstore();
4027+ vtop--;
4028+ }
40254029 vset(&s->type, VT_LOCAL | VT_LVAL, addr);
40264030 }
40274031 } else {
@@ -4593,7 +4597,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 565 unmodified lines
45934597 if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
45944598 CType type, ret_type;
45954599 int ret_align;
4596− if (gfunc_sret(&func_vt, &ret_type, &ret_align)) {
4600+ if (!gfunc_sret(&func_vt, &ret_type, &ret_align)) {
45974601 /* if returning structure, must copy it to implicit
45984602 first pointer arg location */
45994603 type = func_vt;
@@ -4605,7 +4609,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 5 unmodified lines
46054609 vstore();
46064610 } else {
46074611 /* returning structure packed into registers */
4608− int size, addr, align;
4612+ int r, size, addr, offset, align;
46094613 size = type_size(&func_vt,&align);
46104614 if ((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & (ret_align-1)))
46114615 && (align & (ret_align-1))) {
@@ -4619,9 +4623,17 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 7 unmodified lines
46194623 }
46204624 vtop->type = ret_type;
46214625 if (is_float(ret_type.t))
4622− gv(rc_fret(ret_type.t));
4626+ r = rc_fret(ret_type.t);
46234627 else
4624− gv(RC_IRET);
4628+ r = RC_IRET;
4629+ /* We assume that when a structure is returned in multiple
4630+ registers, their classes are consecutive values of the
4631+ suite s(n) = 2^n */
4632+ for (offset = 0; offset < size; offset += ret_align, r<<=1) {
4633+ gv(r);
4634+ vtop->c.i += ret_align;
4635+ vtop->r = VT_LOCAL | VT_LVAL;
4636+ }
46254637 }
46264638 } else if (is_float(func_vt.t)) {
46274639 gv(rc_fret(func_vt.t));
x86_64-gen.c+10−8
@@ -656,7 +656,8 @@ void gen_offs_sp(int b, int r, int d) · 655 unmodified lines
656656 }
657657 }
658658
659−/* Return 1 if this function returns via an sret pointer, 0 otherwise */
659+/* Return the number of registers needed to return the struct, or 0 if
660+ returning via struct pointer. */
660661 ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align)
661662 {
662663 int size, align;
@@ -664,19 +665,19 @@ ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) · 1 unmodified line
664665 size = type_size(vt, &align);
665666 ret->ref = NULL;
666667 if (size > 8) {
667− return 1;
668+ return 0;
668669 } else if (size > 4) {
669670 ret->t = VT_LLONG;
670− return 0;
671+ return 1;
671672 } else if (size > 2) {
672673 ret->t = VT_INT;
673− return 0;
674+ return 1;
674675 } else if (size > 1) {
675676 ret->t = VT_SHORT;
676− return 0;
677+ return 1;
677678 } else {
678679 ret->t = VT_BYTE;
679− return 0;
680+ return 1;
680681 }
681682 }
682683
@@ -1056,11 +1057,12 @@ ST_FUNC int classify_x86_64_va_arg(CType *ty) { · 373 unmodified lines
10561057 }
10571058 }
10581059
1059−/* Return 1 if this function returns via an sret pointer, 0 otherwise */
1060+/* Return the number of registers needed to return the struct, or 0 if
1061+ returning via struct pointer. */
10601062 int gfunc_sret(CType *vt, CType *ret, int *ret_align) {
10611063 int size, align, reg_count;
10621064 *ret_align = 1; // Never have to re-align return values for x86-64
1063− return (classify_x86_64_arg(vt, ret, &size, &align, &reg_count) == x86_64_mode_memory);
1065+ return (classify_x86_64_arg(vt, ret, &size, &align, &reg_count) != x86_64_mode_memory);
10641066 }
10651067
10661068 #define REGN 6

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t