summaryrefslogtreecommitdiff
path: root/src/lj_ccall.c
diff options
context:
space:
mode:
authorMike Pall <mike>2015-01-07 21:06:40 +0100
committerMike Pall <mike>2015-01-07 21:06:40 +0100
commit33f0c24f06d38ea618429c2ea2f7a849e8d7439c (patch)
treed1893a1e30a9a2a8b8972345da3cb89f1b51db9a /src/lj_ccall.c
parentce1a5ee535aea909f297a56bce8ff113e1763403 (diff)
downloadluajit-33f0c24f06d38ea618429c2ea2f7a849e8d7439c.tar.gz
luajit-33f0c24f06d38ea618429c2ea2f7a849e8d7439c.tar.bz2
luajit-33f0c24f06d38ea618429c2ea2f7a849e8d7439c.zip
ARM64: Add FFI support.
Diffstat (limited to 'src/lj_ccall.c')
-rw-r--r--src/lj_ccall.c121
1 files changed, 121 insertions, 0 deletions
diff --git a/src/lj_ccall.c b/src/lj_ccall.c
index 4885820c..5ab5b60d 100644
--- a/src/lj_ccall.c
+++ b/src/lj_ccall.c
@@ -290,6 +290,75 @@
290#define CCALL_HANDLE_RET \ 290#define CCALL_HANDLE_RET \
291 if ((ct->info & CTF_VARARG)) sp = (uint8_t *)&cc->gpr[0]; 291 if ((ct->info & CTF_VARARG)) sp = (uint8_t *)&cc->gpr[0];
292 292
293#elif LJ_TARGET_ARM64
294/* -- ARM64 calling conventions ------------------------------------------- */
295
296#define CCALL_HANDLE_STRUCTRET \
297 cc->retref = !ccall_classify_struct(cts, ctr); \
298 if (cc->retref) cc->retp = dp;
299
300#define CCALL_HANDLE_STRUCTRET2 \
301 unsigned int cl = ccall_classify_struct(cts, ctr); \
302 if ((cl & 4)) { /* Combine float HFA from separate registers. */ \
303 CTSize i = (cl >> 8) - 1; \
304 do { ((uint32_t *)dp)[i] = cc->fpr[i].u32; } while (i--); \
305 } else { \
306 if (cl > 1) sp = (uint8_t *)&cc->fpr[0]; \
307 memcpy(dp, sp, ctr->size); \
308 }
309
310#define CCALL_HANDLE_COMPLEXRET \
311 /* Complex values are returned in one or two FPRs. */ \
312 cc->retref = 0;
313
314#define CCALL_HANDLE_COMPLEXRET2 \
315 if (ctr->size == 2*sizeof(float)) { /* Copy complex float from FPRs. */ \
316 ((float *)dp)[0] = cc->fpr[0].f; \
317 ((float *)dp)[1] = cc->fpr[1].f; \
318 } else { /* Copy complex double from FPRs. */ \
319 ((double *)dp)[0] = cc->fpr[0].d; \
320 ((double *)dp)[1] = cc->fpr[1].d; \
321 }
322
323#define CCALL_HANDLE_STRUCTARG \
324 unsigned int cl = ccall_classify_struct(cts, d); \
325 if (cl == 0) { /* Pass struct by reference. */ \
326 rp = cdataptr(lj_cdata_new(cts, did, sz)); \
327 sz = CTSIZE_PTR; \
328 } else if (cl > 1) { /* Pass struct in FPRs or on stack. */ \
329 isfp = (cl & 4) ? 2 : 1; \
330 } /* else: Pass struct in GPRs or on stack. */
331
332#define CCALL_HANDLE_COMPLEXARG \
333 /* Pass complex by value in separate (!) FPRs or on stack. */ \
334 isfp = ctr->size == 2*sizeof(float) ? 2 : 1;
335
336#define CCALL_HANDLE_REGARG \
337 if (LJ_TARGET_IOS && isva) { \
338 /* IOS: All variadic arguments are on the stack. */ \
339 } else if (isfp) { /* Try to pass argument in FPRs. */ \
340 int n2 = ctype_isvector(d->info) ? 1 : n*isfp; \
341 if (nfpr + n2 <= CCALL_NARG_FPR) { \
342 dp = &cc->fpr[nfpr]; \
343 nfpr += n2; \
344 goto done; \
345 } else { \
346 nfpr = CCALL_NARG_FPR; /* Prevent reordering. */ \
347 if (LJ_TARGET_IOS && d->size < 8) goto err_nyi; \
348 } \
349 } else { /* Try to pass argument in GPRs. */ \
350 if (!LJ_TARGET_IOS && (d->info & CTF_ALIGN) > CTALIGN_PTR) \
351 ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \
352 if (ngpr + n <= maxgpr) { \
353 dp = &cc->gpr[ngpr]; \
354 ngpr += n; \
355 goto done; \
356 } else { \
357 ngpr = maxgpr; /* Prevent reordering. */ \
358 if (LJ_TARGET_IOS && d->size < 8) goto err_nyi; \
359 } \
360 }
361
293#elif LJ_TARGET_PPC 362#elif LJ_TARGET_PPC
294/* -- PPC calling conventions --------------------------------------------- */ 363/* -- PPC calling conventions --------------------------------------------- */
295 364
@@ -584,6 +653,52 @@ noth: /* Not a homogeneous float/double aggregate. */
584 653
585#endif 654#endif
586 655
656/* -- ARM64 ABI struct classification ------------------------------------- */
657
658#if LJ_TARGET_ARM64
659
660/* Classify a struct based on its fields. */
661static unsigned int ccall_classify_struct(CTState *cts, CType *ct)
662{
663 CTSize sz = ct->size;
664 unsigned int r = 0, n = 0, isu = (ct->info & CTF_UNION);
665 while (ct->sib) {
666 CType *sct;
667 ct = ctype_get(cts, ct->sib);
668 if (ctype_isfield(ct->info)) {
669 sct = ctype_rawchild(cts, ct);
670 if (ctype_isfp(sct->info)) {
671 r |= sct->size;
672 if (!isu) n++; else if (n == 0) n = 1;
673 } else if (ctype_iscomplex(sct->info)) {
674 r |= (sct->size >> 1);
675 if (!isu) n += 2; else if (n < 2) n = 2;
676 } else if (ctype_isstruct(sct->info)) {
677 goto substruct;
678 } else {
679 goto noth;
680 }
681 } else if (ctype_isbitfield(ct->info)) {
682 goto noth;
683 } else if (ctype_isxattrib(ct->info, CTA_SUBTYPE)) {
684 sct = ctype_rawchild(cts, ct);
685 substruct:
686 if (sct->size > 0) {
687 unsigned int s = ccall_classify_struct(cts, sct);
688 if (s <= 1) goto noth;
689 r |= (s & 255);
690 if (!isu) n += (s >> 8); else if (n < (s >>8)) n = (s >> 8);
691 }
692 }
693 }
694 if ((r == 4 || r == 8) && n <= 4)
695 return r + (n << 8);
696noth: /* Not a homogeneous float/double aggregate. */
697 return (sz <= 16); /* Return structs of size <= 16 in GPRs. */
698}
699
700#endif
701
587/* -- Common C call handling ---------------------------------------------- */ 702/* -- Common C call handling ---------------------------------------------- */
588 703
589/* Infer the destination CTypeID for a vararg argument. */ 704/* Infer the destination CTypeID for a vararg argument. */
@@ -766,6 +881,12 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct,
766 cc->fpr[nfpr-1].d[0] = cc->fpr[nfpr-2].d[1]; /* Split complex double. */ 881 cc->fpr[nfpr-1].d[0] = cc->fpr[nfpr-2].d[1]; /* Split complex double. */
767 cc->fpr[nfpr-2].d[1] = 0; 882 cc->fpr[nfpr-2].d[1] = 0;
768 } 883 }
884#elif LJ_TARGET_ARM64
885 if (isfp == 2 && (uint8_t *)dp < (uint8_t *)cc->stack) {
886 /* Split float HFA or complex float into separate registers. */
887 CTSize i = (sz >> 2) - 1;
888 do { ((uint64_t *)dp)[i] = ((uint32_t *)dp)[i]; } while (i--);
889 }
769#else 890#else
770 UNUSED(isfp); 891 UNUSED(isfp);
771#endif 892#endif