ARM: Add hard-float ABI support to the FFI (interpreter).

This commit is contained in:
Mike Pall
2012-07-30 19:00:52 +02:00
parent a373fddbd3
commit 4b0af611d0
5 changed files with 193 additions and 19 deletions

View File

@@ -168,6 +168,8 @@
#elif LJ_TARGET_ARM
/* -- ARM calling conventions --------------------------------------------- */
#if LJ_ABI_SOFTFP
#define CCALL_HANDLE_STRUCTRET \
/* Return structs of size <= 4 in a GPR. */ \
cc->retref = !(sz <= 4); \
@@ -186,13 +188,70 @@
#define CCALL_HANDLE_COMPLEXARG \
/* Pass complex by value in 2 or 4 GPRs. */
/* ARM has a softfp ABI. */
#define CCALL_HANDLE_REGARG_FP1
#define CCALL_HANDLE_REGARG_FP2
#else
#define CCALL_HANDLE_STRUCTRET \
cc->retref = !ccall_classify_struct(cts, ctr, ct); \
if (cc->retref) cc->gpr[ngpr++] = (GPRArg)dp;
#define CCALL_HANDLE_STRUCTRET2 \
if (ccall_classify_struct(cts, ctr, ct) > 1) sp = (uint8_t *)&cc->fpr[0]; \
memcpy(dp, sp, ctr->size);
#define CCALL_HANDLE_COMPLEXRET \
if (!(ct->info & CTF_VARARG)) cc->retref = 0; /* Return complex in FPRs. */
#define CCALL_HANDLE_COMPLEXRET2 \
if (!(ct->info & CTF_VARARG)) memcpy(dp, &cc->fpr[0], ctr->size);
#define CCALL_HANDLE_STRUCTARG \
isfp = (ccall_classify_struct(cts, d, ct) > 1);
/* Pass all structs by value in registers and/or on the stack. */
#define CCALL_HANDLE_COMPLEXARG \
isfp = 1; /* Pass complex by value in FPRs or on stack. */
#define CCALL_HANDLE_REGARG_FP1 \
if (isfp && !(ct->info & CTF_VARARG)) { \
if ((d->info & CTF_ALIGN) > CTALIGN_PTR) { \
if (nfpr + (n >> 1) <= CCALL_NARG_FPR) { \
dp = &cc->fpr[nfpr]; \
nfpr += (n >> 1); \
goto done; \
} \
} else { \
if (sz > 1 && fprodd != nfpr) fprodd = 0; \
if (fprodd) { \
if (2*nfpr+n <= 2*CCALL_NARG_FPR+1) { \
dp = (void *)&cc->fpr[fprodd-1].f[1]; \
nfpr += (n >> 1); \
if ((n & 1)) fprodd = 0; else fprodd = nfpr-1; \
goto done; \
} \
} else { \
if (2*nfpr+n <= 2*CCALL_NARG_FPR) { \
dp = (void *)&cc->fpr[nfpr]; \
nfpr += (n >> 1); \
if ((n & 1)) fprodd = ++nfpr; else fprodd = 0; \
goto done; \
} \
} \
} \
fprodd = 0; /* No reordering after the first FP value is on stack. */ \
} else {
#define CCALL_HANDLE_REGARG_FP2 }
#endif
#define CCALL_HANDLE_REGARG \
CCALL_HANDLE_REGARG_FP1 \
if ((d->info & CTF_ALIGN) > CTALIGN_PTR) { \
if (ngpr < maxgpr) \
ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \
else \
nsp = (nsp + 1u) & ~1u; /* Align argument on stack. */ \
} \
if (ngpr < maxgpr) { \
dp = &cc->gpr[ngpr]; \
@@ -204,7 +263,10 @@
ngpr += n; \
} \
goto done; \
}
} CCALL_HANDLE_REGARG_FP2
#define CCALL_HANDLE_RET \
if ((ct->info & CTF_VARARG)) sp = (uint8_t *)&cc->gpr[0];
#elif LJ_TARGET_PPC
/* -- PPC calling conventions --------------------------------------------- */
@@ -453,6 +515,49 @@ static void ccall_struct_ret(CCallState *cc, int *rcl, uint8_t *dp, CTSize sz)
}
#endif
/* -- ARM hard-float ABI struct classification ---------------------------- */
#if LJ_TARGET_ARM && !LJ_ABI_SOFTFP
/* Classify a struct based on its fields. */
static unsigned int ccall_classify_struct(CTState *cts, CType *ct, CType *ctf)
{
CTSize sz = ct->size;
unsigned int r = 0, n = 0, isu = (ct->info & CTF_UNION);
if ((ctf->info & CTF_VARARG)) goto noth;
while (ct->sib) {
ct = ctype_get(cts, ct->sib);
if (ctype_isfield(ct->info)) {
CType *sct = ctype_rawchild(cts, ct);
if (ctype_isfp(sct->info)) {
r |= sct->size;
if (!isu) n++; else if (n == 0) n = 1;
} else if (ctype_iscomplex(sct->info)) {
r |= (sct->size >> 1);
if (!isu) n += 2; else if (n < 2) n = 2;
} else {
goto noth;
}
} else if (ctype_isbitfield(ct->info)) {
goto noth;
} else if (ctype_isxattrib(ct->info, CTA_SUBTYPE)) {
CType *sct = ctype_child(cts, ct);
if (sct->size > 0) {
unsigned int s = ccall_classify_struct(cts, sct, ctf);
if (s <= 1) goto noth;
r |= (s & 255);
if (!isu) n += (s >> 8); else if (n < (s >>8)) n = (s >> 8);
}
}
}
if ((r == 4 || r == 8) && n <= 4)
return r + (n << 8);
noth: /* Not a homogeneous float/double aggregate. */
return (sz <= 4); /* Return structs of size <= 4 in a GPR. */
}
#endif
/* -- Common C call handling ---------------------------------------------- */
/* Infer the destination CTypeID for a vararg argument. */
@@ -494,6 +599,9 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct,
MSize maxgpr, ngpr = 0, nsp = 0, narg;
#if CCALL_NARG_FPR
MSize nfpr = 0;
#if LJ_TARGET_ARM
MSize fprodd = 0;
#endif
#endif
/* Clear unused regs to get some determinism in case of misdeclaration. */