ARM: Add hard-float ABI support to the FFI (interpreter).
This commit is contained in:
116
src/lj_ccall.c
116
src/lj_ccall.c
@@ -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. */
|
||||
|
||||
Reference in New Issue
Block a user