aboutsummaryrefslogtreecommitdiff
path: root/arm-gen.c
diff options
context:
space:
mode:
authorThomas Preud'homme <robotux@celest.fr>2014-01-06 22:27:39 +0800
committerThomas Preud'homme <robotux@celest.fr>2014-01-06 22:57:05 +0800
commit8efaa711904b897f9a4821656ac10f980c5ae9fe (patch)
treeca8a2805bec48ebcedb68553753f238a6b6df71b /arm-gen.c
parentbcc1904f9c950cbf5aae8711d1dcdcfe422fb456 (diff)
downloadtinycc-8efaa711904b897f9a4821656ac10f980c5ae9fe.tar.gz
tinycc-8efaa711904b897f9a4821656ac10f980c5ae9fe.tar.bz2
Fix struct ret in variadic fct with ARM hardfloat
The procedure calling standard for ARM architecture mandate the use of the base standard for variadic function. Therefore, hgen float aggregate must be returned via stack when greater than 4 bytes and via core registers else in case of variadic function. This patch improve gfunc_sret() to take into account whether the function is variadic or not and make use of gfunc_sret() return value to determine whether to pass a structure via stack in gfunc_prolog(). It also take advantage of knowing if a function is variadic or not move float result value from VFP register to core register in gfunc_epilog().
Diffstat (limited to 'arm-gen.c')
-rw-r--r--arm-gen.c34
1 files changed, 18 insertions, 16 deletions
diff --git a/arm-gen.c b/arm-gen.c
index eecb7d2..9e6c638 100644
--- a/arm-gen.c
+++ b/arm-gen.c
@@ -839,12 +839,12 @@ int floats_in_core_regs(SValue *sval)
/* 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) {
+ST_FUNC int gfunc_sret(CType *vt, int variadic, 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)) {
+ if (!variadic && (is_float(vt->t) || is_hgen_float_aggr(vt))) {
*ret_align = 8;
ret->ref = NULL;
ret->t = VT_DOUBLE;
@@ -1221,21 +1221,19 @@ void gfunc_call(int nb_args)
void gfunc_prolog(CType *func_type)
{
Sym *sym,*sym2;
- int n,nf,size,align, variadic, struct_ret = 0;
+ int n, nf, size, align, struct_ret = 0;
#ifdef TCC_ARM_HARDFLOAT
struct avail_regs avregs = AVAIL_REGS_INITIALIZER;
#endif
+ CType ret_type;
sym = func_type->ref;
func_vt = sym->type;
+ func_var = (func_type->ref->c == FUNC_ELLIPSIS);
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)
+ if ((func_vt.t & VT_BTYPE) == VT_STRUCT &&
+ !gfunc_sret(&func_vt, func_var, &ret_type, &align))
{
n++;
struct_ret = 1;
@@ -1244,7 +1242,7 @@ void gfunc_prolog(CType *func_type)
for(sym2=sym->next;sym2 && (n<4 || nf<16);sym2=sym2->next) {
size = type_size(&sym2->type, &align);
#ifdef TCC_ARM_HARDFLOAT
- if (!variadic && (is_float(sym2->type.t)
+ if (!func_var && (is_float(sym2->type.t)
|| is_hgen_float_aggr(&sym2->type))) {
int tmpnf = assign_vfpreg(&avregs, align, size);
tmpnf += (size + 3) / 4;
@@ -1255,9 +1253,9 @@ void gfunc_prolog(CType *func_type)
n += (size + 3) / 4;
}
o(0xE1A0C00D); /* mov ip,sp */
- if(variadic)
+ if (func_var)
n=4;
- if(n) {
+ if (n) {
if(n>4)
n=4;
#ifdef TCC_ARM_EABI
@@ -1289,7 +1287,7 @@ void gfunc_prolog(CType *func_type)
size = (size + 3) >> 2;
align = (align + 3) & ~3;
#ifdef TCC_ARM_HARDFLOAT
- if (!variadic && (is_float(sym->type.t)
+ if (!func_var && (is_float(sym->type.t)
|| is_hgen_float_aggr(&sym->type))) {
int fpn = assign_vfpreg(&avregs, align, size << 2);
if (fpn >= 0) {
@@ -1329,10 +1327,14 @@ void gfunc_epilog(void)
{
uint32_t x;
int diff;
+ /* Copy float return value to core register if base standard is used and
+ float computation is made with VFP */
#ifdef TCC_ARM_EABI
- /* Useless but harmless copy of the float result into main register(s) in case
- of variadic function in the hardfloat variant */
- if(is_float(func_vt.t)) {
+ if (
+#ifdef TCC_ARM_HARDFLOAT
+ func_var &&
+#endif
+ is_float(func_vt.t)) {
if((func_vt.t & VT_BTYPE) == VT_FLOAT)
o(0xEE100A10); /* fmrs r0, s0 */
else {