aboutsummaryrefslogtreecommitdiff
path: root/src/lj_ccall.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lj_ccall.c')
-rw-r--r--src/lj_ccall.c397
1 files changed, 343 insertions, 54 deletions
diff --git a/src/lj_ccall.c b/src/lj_ccall.c
index 4a859c73..25f54dee 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,56 +290,85 @@
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
294#elif LJ_TARGET_PPC 293#elif LJ_TARGET_ARM64
295/* -- PPC calling conventions --------------------------------------------- */ 294/* -- ARM64 calling conventions ------------------------------------------- */
296 295
297#define CCALL_HANDLE_STRUCTRET \ 296#define CCALL_HANDLE_STRUCTRET \
298 cc->retref = 1; /* Return all structs by reference. */ \ 297 cc->retref = !ccall_classify_struct(cts, ctr); \
299 cc->gpr[ngpr++] = (GPRArg)dp; 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].lo; } while (i--); \
305 } else { \
306 if (cl > 1) sp = (uint8_t *)&cc->fpr[0]; \
307 memcpy(dp, sp, ctr->size); \
308 }
300 309
301#define CCALL_HANDLE_COMPLEXRET \ 310#define CCALL_HANDLE_COMPLEXRET \
302 /* Complex values are returned in 2 or 4 GPRs. */ \ 311 /* Complex values are returned in one or two FPRs. */ \
303 cc->retref = 0; 312 cc->retref = 0;
304 313
305#define CCALL_HANDLE_COMPLEXRET2 \ 314#define CCALL_HANDLE_COMPLEXRET2 \
306 memcpy(dp, sp, ctr->size); /* Copy complex from GPRs. */ 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 }
307 322
308#define CCALL_HANDLE_STRUCTARG \ 323#define CCALL_HANDLE_STRUCTARG \
309 rp = cdataptr(lj_cdata_new(cts, did, sz)); \ 324 unsigned int cl = ccall_classify_struct(cts, d); \
310 sz = CTSIZE_PTR; /* Pass all structs by reference. */ 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. */
311 331
312#define CCALL_HANDLE_COMPLEXARG \ 332#define CCALL_HANDLE_COMPLEXARG \
313 /* Pass complex by value in 2 or 4 GPRs. */ 333 /* Pass complex by value in separate (!) FPRs or on stack. */ \
334 isfp = sz == 2*sizeof(float) ? 2 : 1;
314 335
315#define CCALL_HANDLE_REGARG \ 336#define CCALL_HANDLE_REGARG \
316 if (isfp) { /* Try to pass argument in FPRs. */ \ 337 if (LJ_TARGET_OSX && isva) { \
317 if (nfpr + 1 <= CCALL_NARG_FPR) { \ 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 : \
341 isfp == 1 ? n : (d->size >> (4-isfp)); \
342 if (nfpr + n2 <= CCALL_NARG_FPR) { \
318 dp = &cc->fpr[nfpr]; \ 343 dp = &cc->fpr[nfpr]; \
319 nfpr += 1; \ 344 nfpr += n2; \
320 d = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */ \
321 goto done; \ 345 goto done; \
346 } else { \
347 nfpr = CCALL_NARG_FPR; /* Prevent reordering. */ \
348 if (LJ_TARGET_OSX && d->size < 8) goto err_nyi; \
322 } \ 349 } \
323 } else { /* Try to pass argument in GPRs. */ \ 350 } else { /* Try to pass argument in GPRs. */ \
324 if (n > 1) { \ 351 if (!LJ_TARGET_OSX && (d->info & CTF_ALIGN) > CTALIGN_PTR) \
325 lua_assert(n == 2 || n == 4); /* int64_t or complex (float). */ \ 352 ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \
326 if (ctype_isinteger(d->info)) \
327 ngpr = (ngpr + 1u) & ~1u; /* Align int64_t to regpair. */ \
328 else if (ngpr + n > maxgpr) \
329 ngpr = maxgpr; /* Prevent reordering. */ \
330 } \
331 if (ngpr + n <= maxgpr) { \ 353 if (ngpr + n <= maxgpr) { \
332 dp = &cc->gpr[ngpr]; \ 354 dp = &cc->gpr[ngpr]; \
333 ngpr += n; \ 355 ngpr += n; \
334 goto done; \ 356 goto done; \
357 } else { \
358 ngpr = maxgpr; /* Prevent reordering. */ \
359 if (LJ_TARGET_OSX && d->size < 8) goto err_nyi; \
335 } \ 360 } \
336 } 361 }
337 362
363#if LJ_BE
338#define CCALL_HANDLE_RET \ 364#define CCALL_HANDLE_RET \
339 if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \ 365 if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
340 ctr = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */ 366 sp = (uint8_t *)&cc->fpr[0].f;
367#endif
341 368
342#elif LJ_TARGET_PPCSPE 369
343/* -- PPC/SPE calling conventions ----------------------------------------- */ 370#elif LJ_TARGET_PPC
371/* -- PPC calling conventions --------------------------------------------- */
344 372
345#define CCALL_HANDLE_STRUCTRET \ 373#define CCALL_HANDLE_STRUCTRET \
346 cc->retref = 1; /* Return all structs by reference. */ \ 374 cc->retref = 1; /* Return all structs by reference. */ \
@@ -360,12 +388,13 @@
360#define CCALL_HANDLE_COMPLEXARG \ 388#define CCALL_HANDLE_COMPLEXARG \
361 /* Pass complex by value in 2 or 4 GPRs. */ 389 /* Pass complex by value in 2 or 4 GPRs. */
362 390
363/* PPC/SPE has a softfp ABI. */ 391#define CCALL_HANDLE_GPR \
364#define CCALL_HANDLE_REGARG \ 392 /* Try to pass argument in GPRs. */ \
365 if (n > 1) { /* Doesn't fit in a single GPR? */ \ 393 if (n > 1) { \
366 lua_assert(n == 2 || n == 4); /* int64_t, double or complex (float). */ \ 394 /* int64_t or complex (float). */ \
367 if (n == 2) \ 395 lj_assertL(n == 2 || n == 4, "bad GPR size %d", n); \
368 ngpr = (ngpr + 1u) & ~1u; /* Only align 64 bit value to regpair. */ \ 396 if (ctype_isinteger(d->info) || ctype_isfp(d->info)) \
397 ngpr = (ngpr + 1u) & ~1u; /* Align int64_t to regpair. */ \
369 else if (ngpr + n > maxgpr) \ 398 else if (ngpr + n > maxgpr) \
370 ngpr = maxgpr; /* Prevent reordering. */ \ 399 ngpr = maxgpr; /* Prevent reordering. */ \
371 } \ 400 } \
@@ -373,10 +402,32 @@
373 dp = &cc->gpr[ngpr]; \ 402 dp = &cc->gpr[ngpr]; \
374 ngpr += n; \ 403 ngpr += n; \
375 goto done; \ 404 goto done; \
405 } \
406
407#if LJ_ABI_SOFTFP
408#define CCALL_HANDLE_REGARG CCALL_HANDLE_GPR
409#else
410#define CCALL_HANDLE_REGARG \
411 if (isfp) { /* Try to pass argument in FPRs. */ \
412 if (nfpr + 1 <= CCALL_NARG_FPR) { \
413 dp = &cc->fpr[nfpr]; \
414 nfpr += 1; \
415 d = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */ \
416 goto done; \
417 } \
418 } else { \
419 CCALL_HANDLE_GPR \
376 } 420 }
421#endif
377 422
378#elif LJ_TARGET_MIPS 423#if !LJ_ABI_SOFTFP
379/* -- MIPS calling conventions -------------------------------------------- */ 424#define CCALL_HANDLE_RET \
425 if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
426 ctr = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */
427#endif
428
429#elif LJ_TARGET_MIPS32
430/* -- MIPS o32 calling conventions ---------------------------------------- */
380 431
381#define CCALL_HANDLE_STRUCTRET \ 432#define CCALL_HANDLE_STRUCTRET \
382 cc->retref = 1; /* Return all structs by reference. */ \ 433 cc->retref = 1; /* Return all structs by reference. */ \
@@ -386,6 +437,18 @@
386 /* Complex values are returned in 1 or 2 FPRs. */ \ 437 /* Complex values are returned in 1 or 2 FPRs. */ \
387 cc->retref = 0; 438 cc->retref = 0;
388 439
440#if LJ_ABI_SOFTFP
441#define CCALL_HANDLE_COMPLEXRET2 \
442 if (ctr->size == 2*sizeof(float)) { /* Copy complex float from GPRs. */ \
443 ((intptr_t *)dp)[0] = cc->gpr[0]; \
444 ((intptr_t *)dp)[1] = cc->gpr[1]; \
445 } else { /* Copy complex double from GPRs. */ \
446 ((intptr_t *)dp)[0] = cc->gpr[0]; \
447 ((intptr_t *)dp)[1] = cc->gpr[1]; \
448 ((intptr_t *)dp)[2] = cc->gpr[2]; \
449 ((intptr_t *)dp)[3] = cc->gpr[3]; \
450 }
451#else
389#define CCALL_HANDLE_COMPLEXRET2 \ 452#define CCALL_HANDLE_COMPLEXRET2 \
390 if (ctr->size == 2*sizeof(float)) { /* Copy complex float from FPRs. */ \ 453 if (ctr->size == 2*sizeof(float)) { /* Copy complex float from FPRs. */ \
391 ((float *)dp)[0] = cc->fpr[0].f; \ 454 ((float *)dp)[0] = cc->fpr[0].f; \
@@ -394,6 +457,7 @@
394 ((double *)dp)[0] = cc->fpr[0].d; \ 457 ((double *)dp)[0] = cc->fpr[0].d; \
395 ((double *)dp)[1] = cc->fpr[1].d; \ 458 ((double *)dp)[1] = cc->fpr[1].d; \
396 } 459 }
460#endif
397 461
398#define CCALL_HANDLE_STRUCTARG \ 462#define CCALL_HANDLE_STRUCTARG \
399 /* Pass all structs by value in registers and/or on the stack. */ 463 /* Pass all structs by value in registers and/or on the stack. */
@@ -401,6 +465,22 @@
401#define CCALL_HANDLE_COMPLEXARG \ 465#define CCALL_HANDLE_COMPLEXARG \
402 /* Pass complex by value in 2 or 4 GPRs. */ 466 /* Pass complex by value in 2 or 4 GPRs. */
403 467
468#define CCALL_HANDLE_GPR \
469 if ((d->info & CTF_ALIGN) > CTALIGN_PTR) \
470 ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \
471 if (ngpr < maxgpr) { \
472 dp = &cc->gpr[ngpr]; \
473 if (ngpr + n > maxgpr) { \
474 nsp += ngpr + n - maxgpr; /* Assumes contiguous gpr/stack fields. */ \
475 if (nsp > CCALL_MAXSTACK) goto err_nyi; /* Too many arguments. */ \
476 ngpr = maxgpr; \
477 } else { \
478 ngpr += n; \
479 } \
480 goto done; \
481 }
482
483#if !LJ_ABI_SOFTFP /* MIPS32 hard-float */
404#define CCALL_HANDLE_REGARG \ 484#define CCALL_HANDLE_REGARG \
405 if (isfp && nfpr < CCALL_NARG_FPR && !(ct->info & CTF_VARARG)) { \ 485 if (isfp && nfpr < CCALL_NARG_FPR && !(ct->info & CTF_VARARG)) { \
406 /* Try to pass argument in FPRs. */ \ 486 /* Try to pass argument in FPRs. */ \
@@ -409,25 +489,91 @@
409 goto done; \ 489 goto done; \
410 } else { /* Try to pass argument in GPRs. */ \ 490 } else { /* Try to pass argument in GPRs. */ \
411 nfpr = CCALL_NARG_FPR; \ 491 nfpr = CCALL_NARG_FPR; \
412 if ((d->info & CTF_ALIGN) > CTALIGN_PTR) \ 492 CCALL_HANDLE_GPR \
413 ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \ 493 }
414 if (ngpr < maxgpr) { \ 494#else /* MIPS32 soft-float */
415 dp = &cc->gpr[ngpr]; \ 495#define CCALL_HANDLE_REGARG CCALL_HANDLE_GPR
416 if (ngpr + n > maxgpr) { \ 496#endif
417 nsp += ngpr + n - maxgpr; /* Assumes contiguous gpr/stack fields. */ \ 497
418 if (nsp > CCALL_MAXSTACK) goto err_nyi; /* Too many arguments. */ \ 498#if !LJ_ABI_SOFTFP
419 ngpr = maxgpr; \ 499/* On MIPS64 soft-float, position of float return values is endian-dependant. */
420 } else { \ 500#define CCALL_HANDLE_RET \
421 ngpr += n; \ 501 if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
422 } \ 502 sp = (uint8_t *)&cc->fpr[0].f;
423 goto done; \ 503#endif
424 } \ 504
505#elif LJ_TARGET_MIPS64
506/* -- MIPS n64 calling conventions ---------------------------------------- */
507
508#define CCALL_HANDLE_STRUCTRET \
509 cc->retref = !(sz <= 16); \
510 if (cc->retref) cc->gpr[ngpr++] = (GPRArg)dp;
511
512#define CCALL_HANDLE_STRUCTRET2 \
513 ccall_copy_struct(cc, ctr, dp, sp, ccall_classify_struct(cts, ctr, ct));
514
515#define CCALL_HANDLE_COMPLEXRET \
516 /* Complex values are returned in 1 or 2 FPRs. */ \
517 cc->retref = 0;
518
519#if LJ_ABI_SOFTFP /* MIPS64 soft-float */
520
521#define CCALL_HANDLE_COMPLEXRET2 \
522 if (ctr->size == 2*sizeof(float)) { /* Copy complex float from GPRs. */ \
523 ((intptr_t *)dp)[0] = cc->gpr[0]; \
524 } else { /* Copy complex double from GPRs. */ \
525 ((intptr_t *)dp)[0] = cc->gpr[0]; \
526 ((intptr_t *)dp)[1] = cc->gpr[1]; \
527 }
528
529#define CCALL_HANDLE_COMPLEXARG \
530 /* Pass complex by value in 2 or 4 GPRs. */
531
532/* Position of soft-float 'float' return value depends on endianess. */
533#define CCALL_HANDLE_RET \
534 if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
535 sp = (uint8_t *)cc->gpr + LJ_ENDIAN_SELECT(0, 4);
536
537#else /* MIPS64 hard-float */
538
539#define CCALL_HANDLE_COMPLEXRET2 \
540 if (ctr->size == 2*sizeof(float)) { /* Copy complex float from FPRs. */ \
541 ((float *)dp)[0] = cc->fpr[0].f; \
542 ((float *)dp)[1] = cc->fpr[1].f; \
543 } else { /* Copy complex double from FPRs. */ \
544 ((double *)dp)[0] = cc->fpr[0].d; \
545 ((double *)dp)[1] = cc->fpr[1].d; \
546 }
547
548#define CCALL_HANDLE_COMPLEXARG \
549 if (sz == 2*sizeof(float)) { \
550 isfp = 2; \
551 if (ngpr < maxgpr) \
552 sz *= 2; \
425 } 553 }
426 554
427#define CCALL_HANDLE_RET \ 555#define CCALL_HANDLE_RET \
428 if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \ 556 if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
429 sp = (uint8_t *)&cc->fpr[0].f; 557 sp = (uint8_t *)&cc->fpr[0].f;
430 558
559#endif
560
561#define CCALL_HANDLE_STRUCTARG \
562 /* Pass all structs by value in registers and/or on the stack. */
563
564#define CCALL_HANDLE_REGARG \
565 if (ngpr < maxgpr) { \
566 dp = &cc->gpr[ngpr]; \
567 if (ngpr + n > maxgpr) { \
568 nsp += ngpr + n - maxgpr; /* Assumes contiguous gpr/stack fields. */ \
569 if (nsp > CCALL_MAXSTACK) goto err_nyi; /* Too many arguments. */ \
570 ngpr = maxgpr; \
571 } else { \
572 ngpr += n; \
573 } \
574 goto done; \
575 }
576
431#else 577#else
432#error "Missing calling convention definitions for this architecture" 578#error "Missing calling convention definitions for this architecture"
433#endif 579#endif
@@ -497,7 +643,8 @@ static void ccall_classify_ct(CTState *cts, CType *ct, int *rcl, CTSize ofs)
497 ccall_classify_struct(cts, ct, rcl, ofs); 643 ccall_classify_struct(cts, ct, rcl, ofs);
498 } else { 644 } else {
499 int cl = ctype_isfp(ct->info) ? CCALL_RCL_SSE : CCALL_RCL_INT; 645 int cl = ctype_isfp(ct->info) ? CCALL_RCL_SSE : CCALL_RCL_INT;
500 lua_assert(ctype_hassize(ct->info)); 646 lj_assertCTS(ctype_hassize(ct->info),
647 "classify ctype %08x without size", ct->info);
501 if ((ofs & (ct->size-1))) cl = CCALL_RCL_MEM; /* Unaligned. */ 648 if ((ofs & (ct->size-1))) cl = CCALL_RCL_MEM; /* Unaligned. */
502 rcl[(ofs >= 8)] |= cl; 649 rcl[(ofs >= 8)] |= cl;
503 } 650 }
@@ -522,12 +669,13 @@ static int ccall_classify_struct(CTState *cts, CType *ct, int *rcl, CTSize ofs)
522} 669}
523 670
524/* Try to split up a small struct into registers. */ 671/* Try to split up a small struct into registers. */
525static int ccall_struct_reg(CCallState *cc, GPRArg *dp, int *rcl) 672static int ccall_struct_reg(CCallState *cc, CTState *cts, GPRArg *dp, int *rcl)
526{ 673{
527 MSize ngpr = cc->ngpr, nfpr = cc->nfpr; 674 MSize ngpr = cc->ngpr, nfpr = cc->nfpr;
528 uint32_t i; 675 uint32_t i;
676 UNUSED(cts);
529 for (i = 0; i < 2; i++) { 677 for (i = 0; i < 2; i++) {
530 lua_assert(!(rcl[i] & CCALL_RCL_MEM)); 678 lj_assertCTS(!(rcl[i] & CCALL_RCL_MEM), "pass mem struct in reg");
531 if ((rcl[i] & CCALL_RCL_INT)) { /* Integer class takes precedence. */ 679 if ((rcl[i] & CCALL_RCL_INT)) { /* Integer class takes precedence. */
532 if (ngpr >= CCALL_NARG_GPR) return 1; /* Register overflow. */ 680 if (ngpr >= CCALL_NARG_GPR) return 1; /* Register overflow. */
533 cc->gpr[ngpr++] = dp[i]; 681 cc->gpr[ngpr++] = dp[i];
@@ -548,7 +696,8 @@ static int ccall_struct_arg(CCallState *cc, CTState *cts, CType *d, int *rcl,
548 dp[0] = dp[1] = 0; 696 dp[0] = dp[1] = 0;
549 /* Convert to temp. struct. */ 697 /* Convert to temp. struct. */
550 lj_cconv_ct_tv(cts, d, (uint8_t *)dp, o, CCF_ARG(narg)); 698 lj_cconv_ct_tv(cts, d, (uint8_t *)dp, o, CCF_ARG(narg));
551 if (ccall_struct_reg(cc, dp, rcl)) { /* Register overflow? Pass on stack. */ 699 if (ccall_struct_reg(cc, cts, dp, rcl)) {
700 /* Register overflow? Pass on stack. */
552 MSize nsp = cc->nsp, n = rcl[1] ? 2 : 1; 701 MSize nsp = cc->nsp, n = rcl[1] ? 2 : 1;
553 if (nsp + n > CCALL_MAXSTACK) return 1; /* Too many arguments. */ 702 if (nsp + n > CCALL_MAXSTACK) return 1; /* Too many arguments. */
554 cc->nsp = nsp + n; 703 cc->nsp = nsp + n;
@@ -621,6 +770,125 @@ noth: /* Not a homogeneous float/double aggregate. */
621 770
622#endif 771#endif
623 772
773/* -- ARM64 ABI struct classification ------------------------------------- */
774
775#if LJ_TARGET_ARM64
776
777/* Classify a struct based on its fields. */
778static unsigned int ccall_classify_struct(CTState *cts, CType *ct)
779{
780 CTSize sz = ct->size;
781 unsigned int r = 0, n = 0, isu = (ct->info & CTF_UNION);
782 while (ct->sib) {
783 CType *sct;
784 ct = ctype_get(cts, ct->sib);
785 if (ctype_isfield(ct->info)) {
786 sct = ctype_rawchild(cts, ct);
787 if (ctype_isfp(sct->info)) {
788 r |= sct->size;
789 if (!isu) n++; else if (n == 0) n = 1;
790 } else if (ctype_iscomplex(sct->info)) {
791 r |= (sct->size >> 1);
792 if (!isu) n += 2; else if (n < 2) n = 2;
793 } else if (ctype_isstruct(sct->info)) {
794 goto substruct;
795 } else {
796 goto noth;
797 }
798 } else if (ctype_isbitfield(ct->info)) {
799 goto noth;
800 } else if (ctype_isxattrib(ct->info, CTA_SUBTYPE)) {
801 sct = ctype_rawchild(cts, ct);
802 substruct:
803 if (sct->size > 0) {
804 unsigned int s = ccall_classify_struct(cts, sct);
805 if (s <= 1) goto noth;
806 r |= (s & 255);
807 if (!isu) n += (s >> 8); else if (n < (s >>8)) n = (s >> 8);
808 }
809 }
810 }
811 if ((r == 4 || r == 8) && n <= 4)
812 return r + (n << 8);
813noth: /* Not a homogeneous float/double aggregate. */
814 return (sz <= 16); /* Return structs of size <= 16 in GPRs. */
815}
816
817#endif
818
819/* -- MIPS64 ABI struct classification ---------------------------- */
820
821#if LJ_TARGET_MIPS64
822
823#define FTYPE_FLOAT 1
824#define FTYPE_DOUBLE 2
825
826/* Classify FP fields (max. 2) and their types. */
827static unsigned int ccall_classify_struct(CTState *cts, CType *ct, CType *ctf)
828{
829 int n = 0, ft = 0;
830 if ((ctf->info & CTF_VARARG) || (ct->info & CTF_UNION))
831 goto noth;
832 while (ct->sib) {
833 CType *sct;
834 ct = ctype_get(cts, ct->sib);
835 if (n == 2) {
836 goto noth;
837 } else if (ctype_isfield(ct->info)) {
838 sct = ctype_rawchild(cts, ct);
839 if (ctype_isfp(sct->info)) {
840 ft |= (sct->size == 4 ? FTYPE_FLOAT : FTYPE_DOUBLE) << 2*n;
841 n++;
842 } else {
843 goto noth;
844 }
845 } else if (ctype_isbitfield(ct->info) ||
846 ctype_isxattrib(ct->info, CTA_SUBTYPE)) {
847 goto noth;
848 }
849 }
850 if (n <= 2)
851 return ft;
852noth: /* Not a homogeneous float/double aggregate. */
853 return 0; /* Struct is in GPRs. */
854}
855
856static void ccall_copy_struct(CCallState *cc, CType *ctr, void *dp, void *sp,
857 int ft)
858{
859 if (LJ_ABI_SOFTFP ? ft :
860 ((ft & 3) == FTYPE_FLOAT || (ft >> 2) == FTYPE_FLOAT)) {
861 int i, ofs = 0;
862 for (i = 0; ft != 0; i++, ft >>= 2) {
863 if ((ft & 3) == FTYPE_FLOAT) {
864#if LJ_ABI_SOFTFP
865 /* The 2nd FP struct result is in CARG1 (gpr[2]) and not CRET2. */
866 memcpy((uint8_t *)dp + ofs,
867 (uint8_t *)&cc->gpr[2*i] + LJ_ENDIAN_SELECT(0, 4), 4);
868#else
869 *(float *)((uint8_t *)dp + ofs) = cc->fpr[i].f;
870#endif
871 ofs += 4;
872 } else {
873 ofs = (ofs + 7) & ~7; /* 64 bit alignment. */
874#if LJ_ABI_SOFTFP
875 *(intptr_t *)((uint8_t *)dp + ofs) = cc->gpr[2*i];
876#else
877 *(double *)((uint8_t *)dp + ofs) = cc->fpr[i].d;
878#endif
879 ofs += 8;
880 }
881 }
882 } else {
883#if !LJ_ABI_SOFTFP
884 if (ft) sp = (uint8_t *)&cc->fpr[0];
885#endif
886 memcpy(dp, sp, ctr->size);
887 }
888}
889
890#endif
891
624/* -- Common C call handling ---------------------------------------------- */ 892/* -- Common C call handling ---------------------------------------------- */
625 893
626/* Infer the destination CTypeID for a vararg argument. */ 894/* Infer the destination CTypeID for a vararg argument. */
@@ -726,7 +994,7 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct,
726 if (fid) { /* Get argument type from field. */ 994 if (fid) { /* Get argument type from field. */
727 CType *ctf = ctype_get(cts, fid); 995 CType *ctf = ctype_get(cts, fid);
728 fid = ctf->sib; 996 fid = ctf->sib;
729 lua_assert(ctype_isfield(ctf->info)); 997 lj_assertL(ctype_isfield(ctf->info), "field expected");
730 did = ctype_cid(ctf->info); 998 did = ctype_cid(ctf->info);
731 } else { 999 } else {
732 if (!(ct->info & CTF_VARARG)) 1000 if (!(ct->info & CTF_VARARG))
@@ -788,6 +1056,19 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct,
788 *(int32_t *)dp = d->size == 1 ? (int32_t)*(int8_t *)dp : 1056 *(int32_t *)dp = d->size == 1 ? (int32_t)*(int8_t *)dp :
789 (int32_t)*(int16_t *)dp; 1057 (int32_t)*(int16_t *)dp;
790 } 1058 }
1059#if LJ_TARGET_ARM64 && LJ_BE
1060 if (isfp && d->size == sizeof(float))
1061 ((float *)dp)[1] = ((float *)dp)[0]; /* Floats occupy high slot. */
1062#endif
1063#if LJ_TARGET_MIPS64 || (LJ_TARGET_ARM64 && LJ_BE)
1064 if ((ctype_isinteger_or_bool(d->info) || ctype_isenum(d->info)
1065#if LJ_TARGET_MIPS64
1066 || (isfp && nsp == 0)
1067#endif
1068 ) && d->size <= 4) {
1069 *(int64_t *)dp = (int64_t)*(int32_t *)dp; /* Sign-extend to 64 bit. */
1070 }
1071#endif
791#if LJ_TARGET_X64 && LJ_ABI_WIN 1072#if LJ_TARGET_X64 && LJ_ABI_WIN
792 if (isva) { /* Windows/x64 mirrors varargs in both register sets. */ 1073 if (isva) { /* Windows/x64 mirrors varargs in both register sets. */
793 if (nfpr == ngpr) 1074 if (nfpr == ngpr)
@@ -803,13 +1084,19 @@ 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. */ 1084 cc->fpr[nfpr-1].d[0] = cc->fpr[nfpr-2].d[1]; /* Split complex double. */
804 cc->fpr[nfpr-2].d[1] = 0; 1085 cc->fpr[nfpr-2].d[1] = 0;
805 } 1086 }
1087#elif LJ_TARGET_ARM64 || (LJ_TARGET_MIPS64 && !LJ_ABI_SOFTFP)
1088 if (isfp == 2 && (uint8_t *)dp < (uint8_t *)cc->stack) {
1089 /* Split float HFA or complex float into separate registers. */
1090 CTSize i = (sz >> 2) - 1;
1091 do { ((uint64_t *)dp)[i] = ((uint32_t *)dp)[i]; } while (i--);
1092 }
806#else 1093#else
807 UNUSED(isfp); 1094 UNUSED(isfp);
808#endif 1095#endif
809 } 1096 }
810 if (fid) lj_err_caller(L, LJ_ERR_FFI_NUMARG); /* Too few arguments. */ 1097 if (fid) lj_err_caller(L, LJ_ERR_FFI_NUMARG); /* Too few arguments. */
811 1098
812#if LJ_TARGET_X64 || LJ_TARGET_PPC 1099#if LJ_TARGET_X64 || (LJ_TARGET_PPC && !LJ_ABI_SOFTFP)
813 cc->nfpr = nfpr; /* Required for vararg functions. */ 1100 cc->nfpr = nfpr; /* Required for vararg functions. */
814#endif 1101#endif
815 cc->nsp = nsp; 1102 cc->nsp = nsp;
@@ -844,7 +1131,8 @@ static int ccall_get_results(lua_State *L, CTState *cts, CType *ct,
844 CCALL_HANDLE_COMPLEXRET2 1131 CCALL_HANDLE_COMPLEXRET2
845 return 1; /* One GC step. */ 1132 return 1; /* One GC step. */
846 } 1133 }
847 if (LJ_BE && ctype_isinteger_or_bool(ctr->info) && ctr->size < CTSIZE_PTR) 1134 if (LJ_BE && ctr->size < CTSIZE_PTR &&
1135 (ctype_isinteger_or_bool(ctr->info) || ctype_isenum(ctr->info)))
848 sp += (CTSIZE_PTR - ctr->size); 1136 sp += (CTSIZE_PTR - ctr->size);
849#if CCALL_NUM_FPR 1137#if CCALL_NUM_FPR
850 if (ctype_isfp(ctr->info) || ctype_isvector(ctr->info)) 1138 if (ctype_isfp(ctr->info) || ctype_isvector(ctr->info))
@@ -854,7 +1142,8 @@ static int ccall_get_results(lua_State *L, CTState *cts, CType *ct,
854 CCALL_HANDLE_RET 1142 CCALL_HANDLE_RET
855#endif 1143#endif
856 /* No reference types end up here, so there's no need for the CTypeID. */ 1144 /* No reference types end up here, so there's no need for the CTypeID. */
857 lua_assert(!(ctype_isrefarray(ctr->info) || ctype_isstruct(ctr->info))); 1145 lj_assertL(!(ctype_isrefarray(ctr->info) || ctype_isstruct(ctr->info)),
1146 "unexpected reference ctype");
858 return lj_cconv_tv_ct(cts, ctr, 0, L->top-1, sp); 1147 return lj_cconv_tv_ct(cts, ctr, 0, L->top-1, sp);
859} 1148}
860 1149
@@ -878,7 +1167,7 @@ int lj_ccall_func(lua_State *L, GCcdata *cd)
878 lj_vm_ffi_call(&cc); 1167 lj_vm_ffi_call(&cc);
879 if (cts->cb.slot != ~0u) { /* Blacklist function that called a callback. */ 1168 if (cts->cb.slot != ~0u) { /* Blacklist function that called a callback. */
880 TValue tv; 1169 TValue tv;
881 setlightudV(&tv, (void *)cc.func); 1170 tv.u64 = ((uintptr_t)(void *)cc.func >> 2) | U64x(800000000, 00000000);
882 setboolV(lj_tab_set(L, cts->miscmap, &tv), 1); 1171 setboolV(lj_tab_set(L, cts->miscmap, &tv), 1);
883 } 1172 }
884 ct = (CType *)((intptr_t)ct+(intptr_t)cts->tab); /* May be reallocated. */ 1173 ct = (CType *)((intptr_t)ct+(intptr_t)cts->tab); /* May be reallocated. */