aboutsummaryrefslogtreecommitdiff
path: root/src/lj_ccall.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lj_ccall.c207
1 files changed, 157 insertions, 50 deletions
diff --git a/src/lj_ccall.c b/src/lj_ccall.c
index 58aad9a5..eb7c1ee0 100644
--- a/src/lj_ccall.c
+++ b/src/lj_ccall.c
@@ -9,7 +9,6 @@
9 9
10#include "lj_gc.h" 10#include "lj_gc.h"
11#include "lj_err.h" 11#include "lj_err.h"
12#include "lj_str.h"
13#include "lj_tab.h" 12#include "lj_tab.h"
14#include "lj_ctype.h" 13#include "lj_ctype.h"
15#include "lj_cconv.h" 14#include "lj_cconv.h"
@@ -291,6 +290,75 @@
291#define CCALL_HANDLE_RET \ 290#define CCALL_HANDLE_RET \
292 if ((ct->info & CTF_VARARG)) sp = (uint8_t *)&cc->gpr[0]; 291 if ((ct->info & CTF_VARARG)) sp = (uint8_t *)&cc->gpr[0];
293 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
294#elif LJ_TARGET_PPC 362#elif LJ_TARGET_PPC
295/* -- PPC calling conventions --------------------------------------------- */ 363/* -- PPC calling conventions --------------------------------------------- */
296 364
@@ -339,42 +407,6 @@
339 if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \ 407 if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
340 ctr = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */ 408 ctr = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */
341 409
342#elif LJ_TARGET_PPCSPE
343/* -- PPC/SPE calling conventions ----------------------------------------- */
344
345#define CCALL_HANDLE_STRUCTRET \
346 cc->retref = 1; /* Return all structs by reference. */ \
347 cc->gpr[ngpr++] = (GPRArg)dp;
348
349#define CCALL_HANDLE_COMPLEXRET \
350 /* Complex values are returned in 2 or 4 GPRs. */ \
351 cc->retref = 0;
352
353#define CCALL_HANDLE_COMPLEXRET2 \
354 memcpy(dp, sp, ctr->size); /* Copy complex from GPRs. */
355
356#define CCALL_HANDLE_STRUCTARG \
357 rp = cdataptr(lj_cdata_new(cts, did, sz)); \
358 sz = CTSIZE_PTR; /* Pass all structs by reference. */
359
360#define CCALL_HANDLE_COMPLEXARG \
361 /* Pass complex by value in 2 or 4 GPRs. */
362
363/* PPC/SPE has a softfp ABI. */
364#define CCALL_HANDLE_REGARG \
365 if (n > 1) { /* Doesn't fit in a single GPR? */ \
366 lua_assert(n == 2 || n == 4); /* int64_t, double or complex (float). */ \
367 if (n == 2) \
368 ngpr = (ngpr + 1u) & ~1u; /* Only align 64 bit value to regpair. */ \
369 else if (ngpr + n > maxgpr) \
370 ngpr = maxgpr; /* Prevent reordering. */ \
371 } \
372 if (ngpr + n <= maxgpr) { \
373 dp = &cc->gpr[ngpr]; \
374 ngpr += n; \
375 goto done; \
376 }
377
378#elif LJ_TARGET_MIPS 410#elif LJ_TARGET_MIPS
379/* -- MIPS calling conventions -------------------------------------------- */ 411/* -- MIPS calling conventions -------------------------------------------- */
380 412
@@ -386,6 +418,18 @@
386 /* Complex values are returned in 1 or 2 FPRs. */ \ 418 /* Complex values are returned in 1 or 2 FPRs. */ \
387 cc->retref = 0; 419 cc->retref = 0;
388 420
421#if LJ_ABI_SOFTFP
422#define CCALL_HANDLE_COMPLEXRET2 \
423 if (ctr->size == 2*sizeof(float)) { /* Copy complex float from GPRs. */ \
424 ((intptr_t *)dp)[0] = cc->gpr[0]; \
425 ((intptr_t *)dp)[1] = cc->gpr[1]; \
426 } else { /* Copy complex double from GPRs. */ \
427 ((intptr_t *)dp)[0] = cc->gpr[0]; \
428 ((intptr_t *)dp)[1] = cc->gpr[1]; \
429 ((intptr_t *)dp)[2] = cc->gpr[2]; \
430 ((intptr_t *)dp)[3] = cc->gpr[3]; \
431 }
432#else
389#define CCALL_HANDLE_COMPLEXRET2 \ 433#define CCALL_HANDLE_COMPLEXRET2 \
390 if (ctr->size == 2*sizeof(float)) { /* Copy complex float from FPRs. */ \ 434 if (ctr->size == 2*sizeof(float)) { /* Copy complex float from FPRs. */ \
391 ((float *)dp)[0] = cc->fpr[0].f; \ 435 ((float *)dp)[0] = cc->fpr[0].f; \
@@ -394,6 +438,7 @@
394 ((double *)dp)[0] = cc->fpr[0].d; \ 438 ((double *)dp)[0] = cc->fpr[0].d; \
395 ((double *)dp)[1] = cc->fpr[1].d; \ 439 ((double *)dp)[1] = cc->fpr[1].d; \
396 } 440 }
441#endif
397 442
398#define CCALL_HANDLE_STRUCTARG \ 443#define CCALL_HANDLE_STRUCTARG \
399 /* Pass all structs by value in registers and/or on the stack. */ 444 /* Pass all structs by value in registers and/or on the stack. */
@@ -401,6 +446,22 @@
401#define CCALL_HANDLE_COMPLEXARG \ 446#define CCALL_HANDLE_COMPLEXARG \
402 /* Pass complex by value in 2 or 4 GPRs. */ 447 /* Pass complex by value in 2 or 4 GPRs. */
403 448
449#define CCALL_HANDLE_GPR \
450 if ((d->info & CTF_ALIGN) > CTALIGN_PTR) \
451 ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \
452 if (ngpr < maxgpr) { \
453 dp = &cc->gpr[ngpr]; \
454 if (ngpr + n > maxgpr) { \
455 nsp += ngpr + n - maxgpr; /* Assumes contiguous gpr/stack fields. */ \
456 if (nsp > CCALL_MAXSTACK) goto err_nyi; /* Too many arguments. */ \
457 ngpr = maxgpr; \
458 } else { \
459 ngpr += n; \
460 } \
461 goto done; \
462 }
463
464#if !LJ_ABI_SOFTFP /* MIPS32 hard-float */
404#define CCALL_HANDLE_REGARG \ 465#define CCALL_HANDLE_REGARG \
405 if (isfp && nfpr < CCALL_NARG_FPR && !(ct->info & CTF_VARARG)) { \ 466 if (isfp && nfpr < CCALL_NARG_FPR && !(ct->info & CTF_VARARG)) { \
406 /* Try to pass argument in FPRs. */ \ 467 /* Try to pass argument in FPRs. */ \
@@ -409,24 +470,18 @@
409 goto done; \ 470 goto done; \
410 } else { /* Try to pass argument in GPRs. */ \ 471 } else { /* Try to pass argument in GPRs. */ \
411 nfpr = CCALL_NARG_FPR; \ 472 nfpr = CCALL_NARG_FPR; \
412 if ((d->info & CTF_ALIGN) > CTALIGN_PTR) \ 473 CCALL_HANDLE_GPR \
413 ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \
414 if (ngpr < maxgpr) { \
415 dp = &cc->gpr[ngpr]; \
416 if (ngpr + n > maxgpr) { \
417 nsp += ngpr + n - maxgpr; /* Assumes contiguous gpr/stack fields. */ \
418 if (nsp > CCALL_MAXSTACK) goto err_nyi; /* Too many arguments. */ \
419 ngpr = maxgpr; \
420 } else { \
421 ngpr += n; \
422 } \
423 goto done; \
424 } \
425 } 474 }
475#else /* MIPS32 soft-float */
476#define CCALL_HANDLE_REGARG CCALL_HANDLE_GPR
477#endif
426 478
479#if !LJ_ABI_SOFTFP
480/* On MIPS64 soft-float, position of float return values is endian-dependant. */
427#define CCALL_HANDLE_RET \ 481#define CCALL_HANDLE_RET \
428 if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \ 482 if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
429 sp = (uint8_t *)&cc->fpr[0].f; 483 sp = (uint8_t *)&cc->fpr[0].f;
484#endif
430 485
431#else 486#else
432#error "Missing calling convention definitions for this architecture" 487#error "Missing calling convention definitions for this architecture"
@@ -621,6 +676,52 @@ noth: /* Not a homogeneous float/double aggregate. */
621 676
622#endif 677#endif
623 678
679/* -- ARM64 ABI struct classification ------------------------------------- */
680
681#if LJ_TARGET_ARM64
682
683/* Classify a struct based on its fields. */
684static unsigned int ccall_classify_struct(CTState *cts, CType *ct)
685{
686 CTSize sz = ct->size;
687 unsigned int r = 0, n = 0, isu = (ct->info & CTF_UNION);
688 while (ct->sib) {
689 CType *sct;
690 ct = ctype_get(cts, ct->sib);
691 if (ctype_isfield(ct->info)) {
692 sct = ctype_rawchild(cts, ct);
693 if (ctype_isfp(sct->info)) {
694 r |= sct->size;
695 if (!isu) n++; else if (n == 0) n = 1;
696 } else if (ctype_iscomplex(sct->info)) {
697 r |= (sct->size >> 1);
698 if (!isu) n += 2; else if (n < 2) n = 2;
699 } else if (ctype_isstruct(sct->info)) {
700 goto substruct;
701 } else {
702 goto noth;
703 }
704 } else if (ctype_isbitfield(ct->info)) {
705 goto noth;
706 } else if (ctype_isxattrib(ct->info, CTA_SUBTYPE)) {
707 sct = ctype_rawchild(cts, ct);
708 substruct:
709 if (sct->size > 0) {
710 unsigned int s = ccall_classify_struct(cts, sct);
711 if (s <= 1) goto noth;
712 r |= (s & 255);
713 if (!isu) n += (s >> 8); else if (n < (s >>8)) n = (s >> 8);
714 }
715 }
716 }
717 if ((r == 4 || r == 8) && n <= 4)
718 return r + (n << 8);
719noth: /* Not a homogeneous float/double aggregate. */
720 return (sz <= 16); /* Return structs of size <= 16 in GPRs. */
721}
722
723#endif
724
624/* -- Common C call handling ---------------------------------------------- */ 725/* -- Common C call handling ---------------------------------------------- */
625 726
626/* Infer the destination CTypeID for a vararg argument. */ 727/* Infer the destination CTypeID for a vararg argument. */
@@ -803,6 +904,12 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct,
803 cc->fpr[nfpr-1].d[0] = cc->fpr[nfpr-2].d[1]; /* Split complex double. */ 904 cc->fpr[nfpr-1].d[0] = cc->fpr[nfpr-2].d[1]; /* Split complex double. */
804 cc->fpr[nfpr-2].d[1] = 0; 905 cc->fpr[nfpr-2].d[1] = 0;
805 } 906 }
907#elif LJ_TARGET_ARM64
908 if (isfp == 2 && (uint8_t *)dp < (uint8_t *)cc->stack) {
909 /* Split float HFA or complex float into separate registers. */
910 CTSize i = (sz >> 2) - 1;
911 do { ((uint64_t *)dp)[i] = ((uint32_t *)dp)[i]; } while (i--);
912 }
806#else 913#else
807 UNUSED(isfp); 914 UNUSED(isfp);
808#endif 915#endif