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
746 }746 }
747}747}
748 748
749/* Return 1 if this function returns via an sret pointer, 0 otherwise */
750ST_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
767#ifdef TCC_ARM_HARDFLOAT749#ifdef TCC_ARM_HARDFLOAT
768/* Return whether a structure is an homogeneous float aggregate or not.750/* Return whether a structure is an homogeneous float aggregate or not.
769 The answer is true if all the elements of the structure are of the same751 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
831}813}
832#endif814#endif
833 815
816/* Return the number of registers needed to return the struct, or 0 if
817 returning via struct pointer. */
818ST_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
834/* Parameters are classified according to how they are copied to their final843/* Parameters are classified according to how they are copied to their final
835 destination for the function call. Because the copying is performed class844 destination for the function call. Because the copying is performed class
836 after class according to the order in the union below, it is important that845 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
1198 n = nf = 0;1207 n = nf = 0;
1199 variadic = (func_type->ref->c == FUNC_ELLIPSIS);1208 variadic = (func_type->ref->c == FUNC_ELLIPSIS);
1200 if((func_vt.t & VT_BTYPE) == VT_STRUCT1209 if((func_vt.t & VT_BTYPE) == VT_STRUCT
1210#ifdef TCC_ARM_HARDFLOAT
1211 && (variadic || !is_hgen_float_aggr(&func_vt))
1212#endif
1201 && type_size(&func_vt,&align) > 4)1213 && type_size(&func_vt,&align) > 4)
1202 {1214 {
1203 n++;1215 n++;
c67-gen.c+3−2
@@ -1879,10 +1879,11 @@ static void gcall_or_jmp(int is_jmp) · 1878 unmodified lines
1879 }1879 }
1880}1880}
1881 1881
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. */
1883ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) {1884ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) {
1884 *ret_align = 1; // Never have to re-align return values for x86-641885 *ret_align = 1; // Never have to re-align return values for x86-64
1885 return 1;1886 return 0;
1886}1887}
1887 1888
1888/* generate function call with address in (vtop->t, vtop->c) and free function1889/* 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
374static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };374static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
375static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };375static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };
376 376
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. */
378ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align)379ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align)
379{380{
380#ifdef TCC_TARGET_PE381#ifdef TCC_TARGET_PE
@@ -383,11 +384,11 @@ ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) · 2 unmodified lines
383 *ret_align = 1; // Never have to re-align return values for x86384 *ret_align = 1; // Never have to re-align return values for x86
384 size = type_size(vt, &align);385 size = type_size(vt, &align);
385 if (size > 8) {386 if (size > 8) {
386 return 1;387 return 0;
387 } else if (size > 4) {388 } else if (size > 4) {
388 ret->ref = NULL;389 ret->ref = NULL;
389 ret->t = VT_LLONG;390 ret->t = VT_LLONG;
390 return 0;391 return 1;
391 } else {392 } else {
392 ret->ref = NULL;393 ret->ref = NULL;
393 ret->t = VT_INT;394 ret->t = VT_INT;
@@ -395,7 +396,7 @@ ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) · 1 unmodified line
395 }396 }
396#else397#else
397 *ret_align = 1; // Never have to re-align return values for x86398 *ret_align = 1; // Never have to re-align return values for x86
398 return 1;399 return 0;
399#endif400#endif
400}401}
401 402
tccgen.c+29−17
@@ -3927,7 +3927,7 @@ ST_FUNC void unary(void) · 3926 unmodified lines
3927 } else if (tok == '(') {3927 } else if (tok == '(') {
3928 SValue ret;3928 SValue ret;
3929 Sym *sa;3929 Sym *sa;
3930 int nb_args, sret;3930 int nb_args, sret, ret_align;
3931 3931
3932 /* function call */3932 /* function call */
3933 if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {3933 if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
@@ -3951,9 +3951,8 @@ ST_FUNC void unary(void) · 17 unmodified lines
3951 ret.r2 = VT_CONST;3951 ret.r2 = VT_CONST;
3952 /* compute first implicit argument if a structure is returned */3952 /* compute first implicit argument if a structure is returned */
3953 if ((s->type.t & VT_BTYPE) == VT_STRUCT) {3953 if ((s->type.t & VT_BTYPE) == VT_STRUCT) {
3954 int ret_align;
3955 sret = gfunc_sret(&s->type, &ret.type, &ret_align);3954 sret = gfunc_sret(&s->type, &ret.type, &ret_align);
3956 if (sret) {3955 if (!sret) {
3957 /* get some space for the returned structure */3956 /* get some space for the returned structure */
3958 size = type_size(&s->type, &align);3957 size = type_size(&s->type, &align);
3959 loc = (loc - size) & -align;3958 loc = (loc - size) & -align;
@@ -3966,11 +3965,11 @@ ST_FUNC void unary(void) · 6 unmodified lines
3966 nb_args++;3965 nb_args++;
3967 }3966 }
3968 } else {3967 } else {
3969 sret = 0;3968 sret = 1;
3970 ret.type = s->type;3969 ret.type = s->type;
3971 }3970 }
3972 3971
3973 if (!sret) {3972 if (sret) {
3974 /* return in register */3973 /* return in register */
3975 if (is_float(ret.type.t)) {3974 if (is_float(ret.type.t)) {
3976 ret.r = reg_fret(ret.type.t);3975 ret.r = reg_fret(ret.type.t);
@@ -4010,18 +4009,23 @@ ST_FUNC void unary(void) · 33 unmodified lines
4010 vtop -= (nb_args + 1);4009 vtop -= (nb_args + 1);
4011 }4010 }
4012 /* return value */4011 /* return value */
4013 vsetc(&ret.type, ret.r, &ret.c);4012 for (r = ret.r + sret + !sret; r-- > ret.r;) {
4014 vtop->r2 = ret.r2;4013 vsetc(&ret.type, r, &ret.c);
4014 vtop->r2 = ret.r2; /* Loop only happens when r2 is VT_CONST */
4015 }
4015 /* handle packed struct return */4016 /* handle packed struct return */
4016 if (((s->type.t & VT_BTYPE) == VT_STRUCT) && !sret) {4017 if (((s->type.t & VT_BTYPE) == VT_STRUCT) && sret) {
4017 int addr;4018 int addr, offset;
4019
4018 size = type_size(&s->type, &align);4020 size = type_size(&s->type, &align);
4019 loc = (loc - size) & -align;4021 loc = (loc - size) & -align;
4020 addr = loc;4022 addr = loc;
4021 vset(&ret.type, VT_LOCAL | VT_LVAL, addr);4023 for(offset = 0; offset < size; offset += ret_align) {
4022 vswap();4024 vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset);
4023 vstore();4025 vswap();
4024 vtop--;4026 vstore();
4027 vtop--;
4028 }
4025 vset(&s->type, VT_LOCAL | VT_LVAL, addr);4029 vset(&s->type, VT_LOCAL | VT_LVAL, addr);
4026 }4030 }
4027 } else {4031 } else {
@@ -4593,7 +4597,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 565 unmodified lines
4593 if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {4597 if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
4594 CType type, ret_type;4598 CType type, ret_type;
4595 int ret_align;4599 int ret_align;
4596 if (gfunc_sret(&func_vt, &ret_type, &ret_align)) {4600 if (!gfunc_sret(&func_vt, &ret_type, &ret_align)) {
4597 /* if returning structure, must copy it to implicit4601 /* if returning structure, must copy it to implicit
4598 first pointer arg location */4602 first pointer arg location */
4599 type = func_vt;4603 type = func_vt;
@@ -4605,7 +4609,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 5 unmodified lines
4605 vstore();4609 vstore();
4606 } else {4610 } else {
4607 /* returning structure packed into registers */4611 /* returning structure packed into registers */
4608 int size, addr, align;4612 int r, size, addr, offset, align;
4609 size = type_size(&func_vt,&align);4613 size = type_size(&func_vt,&align);
4610 if ((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & (ret_align-1)))4614 if ((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & (ret_align-1)))
4611 && (align & (ret_align-1))) {4615 && (align & (ret_align-1))) {
@@ -4619,9 +4623,17 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 7 unmodified lines
4619 }4623 }
4620 vtop->type = ret_type;4624 vtop->type = ret_type;
4621 if (is_float(ret_type.t))4625 if (is_float(ret_type.t))
4622 gv(rc_fret(ret_type.t));4626 r = rc_fret(ret_type.t);
4623 else4627 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 }
4625 }4637 }
4626 } else if (is_float(func_vt.t)) {4638 } else if (is_float(func_vt.t)) {
4627 gv(rc_fret(func_vt.t));4639 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
656 }656 }
657}657}
658 658
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. */
660ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align)661ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align)
661{662{
662 int size, align;663 int size, align;
@@ -664,19 +665,19 @@ ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) · 1 unmodified line
664 size = type_size(vt, &align);665 size = type_size(vt, &align);
665 ret->ref = NULL;666 ret->ref = NULL;
666 if (size > 8) {667 if (size > 8) {
667 return 1;668 return 0;
668 } else if (size > 4) {669 } else if (size > 4) {
669 ret->t = VT_LLONG;670 ret->t = VT_LLONG;
670 return 0;671 return 1;
671 } else if (size > 2) {672 } else if (size > 2) {
672 ret->t = VT_INT;673 ret->t = VT_INT;
673 return 0;674 return 1;
674 } else if (size > 1) {675 } else if (size > 1) {
675 ret->t = VT_SHORT;676 ret->t = VT_SHORT;
676 return 0;677 return 1;
677 } else {678 } else {
678 ret->t = VT_BYTE;679 ret->t = VT_BYTE;
679 return 0;680 return 1;
680 }681 }
681}682}
682 683
@@ -1056,11 +1057,12 @@ ST_FUNC int classify_x86_64_va_arg(CType *ty) { · 373 unmodified lines
1056 }1057 }
1057}1058}
1058 1059
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. */
1060int gfunc_sret(CType *vt, CType *ret, int *ret_align) {1062int gfunc_sret(CType *vt, CType *ret, int *ret_align) {
1061 int size, align, reg_count;1063 int size, align, reg_count;
1062 *ret_align = 1; // Never have to re-align return values for x86-641064 *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);
1064}1066}
1065 1067
1066#define REGN 61068#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