diff options
author | Mike Pall <mike> | 2015-01-07 21:06:40 +0100 |
---|---|---|
committer | Mike Pall <mike> | 2015-01-07 21:06:40 +0100 |
commit | 33f0c24f06d38ea618429c2ea2f7a849e8d7439c (patch) | |
tree | d1893a1e30a9a2a8b8972345da3cb89f1b51db9a /src/lj_ccall.c | |
parent | ce1a5ee535aea909f297a56bce8ff113e1763403 (diff) | |
download | luajit-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.c | 121 |
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. */ | ||
661 | static 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); | ||
696 | noth: /* 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 |