aboutsummaryrefslogtreecommitdiff
path: root/arm-gen.c
diff options
context:
space:
mode:
authorThomas Preud'homme <robotux@celest.fr>2013-11-22 09:27:15 +0800
committerThomas Preud'homme <robotux@celest.fr>2013-11-22 09:27:15 +0800
commitdcec8673f21da86ae3dcf1ca3e9498127715b795 (patch)
treed545ceed139dd57a6d6077368c9bbd248123f964 /arm-gen.c
parentd9d60a1ebd9ae24aafd2e042d5ad38f515583b7e (diff)
downloadtinycc-dcec8673f21da86ae3dcf1ca3e9498127715b795.tar.gz
tinycc-dcec8673f21da86ae3dcf1ca3e9498127715b795.tar.bz2
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.
Diffstat (limited to 'arm-gen.c')
-rw-r--r--arm-gen.c48
1 files changed, 30 insertions, 18 deletions
diff --git a/arm-gen.c b/arm-gen.c
index 92b080d..6d0acd8 100644
--- a/arm-gen.c
+++ b/arm-gen.c
@@ -746,24 +746,6 @@ static void gcall_or_jmp(int is_jmp)
}
}
-/* Return 1 if this function returns via an sret pointer, 0 otherwise */
-ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) {
-#ifdef TCC_ARM_EABI
- int size, align;
- size = type_size(vt, &align);
- if (size > 4) {
- return 1;
- } else {
- *ret_align = 4;
- ret->ref = NULL;
- ret->t = VT_INT;
- return 0;
- }
-#else
- return 1;
-#endif
-}
-
#ifdef TCC_ARM_HARDFLOAT
/* Return whether a structure is an homogeneous float aggregate or not.
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)
}
#endif
+/* Return the number of registers needed to return the struct, or 0 if
+ returning via struct pointer. */
+ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) {
+#ifdef TCC_ARM_EABI
+ int size, align;
+ size = type_size(vt, &align);
+#ifdef TCC_ARM_HARDFLOAT
+ if (is_float(vt->t) || is_hgen_float_aggr(vt)) {
+ *ret_align = 8;
+ ret->ref = NULL;
+ ret->t = VT_DOUBLE;
+ return (size + 7) >> 3;
+ } else
+#endif
+ if (size > 4) {
+ return 0;
+ } else {
+ *ret_align = 4;
+ ret->ref = NULL;
+ ret->t = VT_INT;
+ return 1;
+ }
+#else
+ return 0;
+#endif
+}
+
/* Parameters are classified according to how they are copied to their final
destination for the function call. Because the copying is performed class
after class according to the order in the union below, it is important that
@@ -1198,6 +1207,9 @@ void gfunc_prolog(CType *func_type)
n = nf = 0;
variadic = (func_type->ref->c == FUNC_ELLIPSIS);
if((func_vt.t & VT_BTYPE) == VT_STRUCT
+#ifdef TCC_ARM_HARDFLOAT
+ && (variadic || !is_hgen_float_aggr(&func_vt))
+#endif
&& type_size(&func_vt,&align) > 4)
{
n++;