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.c377
1 files changed, 330 insertions, 47 deletions
diff --git a/src/lj_ccall.c b/src/lj_ccall.c
index fe1e0a3a..a9b81aa5 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,84 @@
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_IOS && 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 : n*isfp; \
341 if (nfpr + n2 <= CCALL_NARG_FPR) { \
318 dp = &cc->fpr[nfpr]; \ 342 dp = &cc->fpr[nfpr]; \
319 nfpr += 1; \ 343 nfpr += n2; \
320 d = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */ \
321 goto done; \ 344 goto done; \
345 } else { \
346 nfpr = CCALL_NARG_FPR; /* Prevent reordering. */ \
347 if (LJ_TARGET_IOS && d->size < 8) goto err_nyi; \
322 } \ 348 } \
323 } else { /* Try to pass argument in GPRs. */ \ 349 } else { /* Try to pass argument in GPRs. */ \
324 if (n > 1) { \ 350 if (!LJ_TARGET_IOS && (d->info & CTF_ALIGN) > CTALIGN_PTR) \
325 lua_assert(n == 2 || n == 4); /* int64_t or complex (float). */ \ 351 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) { \ 352 if (ngpr + n <= maxgpr) { \
332 dp = &cc->gpr[ngpr]; \ 353 dp = &cc->gpr[ngpr]; \
333 ngpr += n; \ 354 ngpr += n; \
334 goto done; \ 355 goto done; \
356 } else { \
357 ngpr = maxgpr; /* Prevent reordering. */ \
358 if (LJ_TARGET_IOS && d->size < 8) goto err_nyi; \
335 } \ 359 } \
336 } 360 }
337 361
362#if LJ_BE
338#define CCALL_HANDLE_RET \ 363#define CCALL_HANDLE_RET \
339 if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \ 364 if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
340 ctr = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */ 365 sp = (uint8_t *)&cc->fpr[0].f;
366#endif
341 367
342#elif LJ_TARGET_PPCSPE 368
343/* -- PPC/SPE calling conventions ----------------------------------------- */ 369#elif LJ_TARGET_PPC
370/* -- PPC calling conventions --------------------------------------------- */
344 371
345#define CCALL_HANDLE_STRUCTRET \ 372#define CCALL_HANDLE_STRUCTRET \
346 cc->retref = 1; /* Return all structs by reference. */ \ 373 cc->retref = 1; /* Return all structs by reference. */ \
@@ -360,12 +387,12 @@
360#define CCALL_HANDLE_COMPLEXARG \ 387#define CCALL_HANDLE_COMPLEXARG \
361 /* Pass complex by value in 2 or 4 GPRs. */ 388 /* Pass complex by value in 2 or 4 GPRs. */
362 389
363/* PPC/SPE has a softfp ABI. */ 390#define CCALL_HANDLE_GPR \
364#define CCALL_HANDLE_REGARG \ 391 /* Try to pass argument in GPRs. */ \
365 if (n > 1) { /* Doesn't fit in a single GPR? */ \ 392 if (n > 1) { \
366 lua_assert(n == 2 || n == 4); /* int64_t, double or complex (float). */ \ 393 lua_assert(n == 2 || n == 4); /* int64_t or complex (float). */ \
367 if (n == 2) \ 394 if (ctype_isinteger(d->info) || ctype_isfp(d->info)) \
368 ngpr = (ngpr + 1u) & ~1u; /* Only align 64 bit value to regpair. */ \ 395 ngpr = (ngpr + 1u) & ~1u; /* Align int64_t to regpair. */ \
369 else if (ngpr + n > maxgpr) \ 396 else if (ngpr + n > maxgpr) \
370 ngpr = maxgpr; /* Prevent reordering. */ \ 397 ngpr = maxgpr; /* Prevent reordering. */ \
371 } \ 398 } \
@@ -373,10 +400,32 @@
373 dp = &cc->gpr[ngpr]; \ 400 dp = &cc->gpr[ngpr]; \
374 ngpr += n; \ 401 ngpr += n; \
375 goto done; \ 402 goto done; \
403 } \
404
405#if LJ_ABI_SOFTFP
406#define CCALL_HANDLE_REGARG CCALL_HANDLE_GPR
407#else
408#define CCALL_HANDLE_REGARG \
409 if (isfp) { /* Try to pass argument in FPRs. */ \
410 if (nfpr + 1 <= CCALL_NARG_FPR) { \
411 dp = &cc->fpr[nfpr]; \
412 nfpr += 1; \
413 d = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */ \
414 goto done; \
415 } \
416 } else { \
417 CCALL_HANDLE_GPR \
376 } 418 }
419#endif
377 420
378#elif LJ_TARGET_MIPS 421#if !LJ_ABI_SOFTFP
379/* -- MIPS calling conventions -------------------------------------------- */ 422#define CCALL_HANDLE_RET \
423 if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
424 ctr = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */
425#endif
426
427#elif LJ_TARGET_MIPS32
428/* -- MIPS o32 calling conventions ---------------------------------------- */
380 429
381#define CCALL_HANDLE_STRUCTRET \ 430#define CCALL_HANDLE_STRUCTRET \
382 cc->retref = 1; /* Return all structs by reference. */ \ 431 cc->retref = 1; /* Return all structs by reference. */ \
@@ -386,6 +435,18 @@
386 /* Complex values are returned in 1 or 2 FPRs. */ \ 435 /* Complex values are returned in 1 or 2 FPRs. */ \
387 cc->retref = 0; 436 cc->retref = 0;
388 437
438#if LJ_ABI_SOFTFP
439#define CCALL_HANDLE_COMPLEXRET2 \
440 if (ctr->size == 2*sizeof(float)) { /* Copy complex float from GPRs. */ \
441 ((intptr_t *)dp)[0] = cc->gpr[0]; \
442 ((intptr_t *)dp)[1] = cc->gpr[1]; \
443 } else { /* Copy complex double from GPRs. */ \
444 ((intptr_t *)dp)[0] = cc->gpr[0]; \
445 ((intptr_t *)dp)[1] = cc->gpr[1]; \
446 ((intptr_t *)dp)[2] = cc->gpr[2]; \
447 ((intptr_t *)dp)[3] = cc->gpr[3]; \
448 }
449#else
389#define CCALL_HANDLE_COMPLEXRET2 \ 450#define CCALL_HANDLE_COMPLEXRET2 \
390 if (ctr->size == 2*sizeof(float)) { /* Copy complex float from FPRs. */ \ 451 if (ctr->size == 2*sizeof(float)) { /* Copy complex float from FPRs. */ \
391 ((float *)dp)[0] = cc->fpr[0].f; \ 452 ((float *)dp)[0] = cc->fpr[0].f; \
@@ -394,6 +455,7 @@
394 ((double *)dp)[0] = cc->fpr[0].d; \ 455 ((double *)dp)[0] = cc->fpr[0].d; \
395 ((double *)dp)[1] = cc->fpr[1].d; \ 456 ((double *)dp)[1] = cc->fpr[1].d; \
396 } 457 }
458#endif
397 459
398#define CCALL_HANDLE_STRUCTARG \ 460#define CCALL_HANDLE_STRUCTARG \
399 /* Pass all structs by value in registers and/or on the stack. */ 461 /* Pass all structs by value in registers and/or on the stack. */
@@ -401,6 +463,22 @@
401#define CCALL_HANDLE_COMPLEXARG \ 463#define CCALL_HANDLE_COMPLEXARG \
402 /* Pass complex by value in 2 or 4 GPRs. */ 464 /* Pass complex by value in 2 or 4 GPRs. */
403 465
466#define CCALL_HANDLE_GPR \
467 if ((d->info & CTF_ALIGN) > CTALIGN_PTR) \
468 ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \
469 if (ngpr < maxgpr) { \
470 dp = &cc->gpr[ngpr]; \
471 if (ngpr + n > maxgpr) { \
472 nsp += ngpr + n - maxgpr; /* Assumes contiguous gpr/stack fields. */ \
473 if (nsp > CCALL_MAXSTACK) goto err_nyi; /* Too many arguments. */ \
474 ngpr = maxgpr; \
475 } else { \
476 ngpr += n; \
477 } \
478 goto done; \
479 }
480
481#if !LJ_ABI_SOFTFP /* MIPS32 hard-float */
404#define CCALL_HANDLE_REGARG \ 482#define CCALL_HANDLE_REGARG \
405 if (isfp && nfpr < CCALL_NARG_FPR && !(ct->info & CTF_VARARG)) { \ 483 if (isfp && nfpr < CCALL_NARG_FPR && !(ct->info & CTF_VARARG)) { \
406 /* Try to pass argument in FPRs. */ \ 484 /* Try to pass argument in FPRs. */ \
@@ -409,25 +487,91 @@
409 goto done; \ 487 goto done; \
410 } else { /* Try to pass argument in GPRs. */ \ 488 } else { /* Try to pass argument in GPRs. */ \
411 nfpr = CCALL_NARG_FPR; \ 489 nfpr = CCALL_NARG_FPR; \
412 if ((d->info & CTF_ALIGN) > CTALIGN_PTR) \ 490 CCALL_HANDLE_GPR \
413 ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \ 491 }
414 if (ngpr < maxgpr) { \ 492#else /* MIPS32 soft-float */
415 dp = &cc->gpr[ngpr]; \ 493#define CCALL_HANDLE_REGARG CCALL_HANDLE_GPR
416 if (ngpr + n > maxgpr) { \ 494#endif
417 nsp += ngpr + n - maxgpr; /* Assumes contiguous gpr/stack fields. */ \ 495
418 if (nsp > CCALL_MAXSTACK) goto err_nyi; /* Too many arguments. */ \ 496#if !LJ_ABI_SOFTFP
419 ngpr = maxgpr; \ 497/* On MIPS64 soft-float, position of float return values is endian-dependant. */
420 } else { \ 498#define CCALL_HANDLE_RET \
421 ngpr += n; \ 499 if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
422 } \ 500 sp = (uint8_t *)&cc->fpr[0].f;
423 goto done; \ 501#endif
424 } \ 502
503#elif LJ_TARGET_MIPS64
504/* -- MIPS n64 calling conventions ---------------------------------------- */
505
506#define CCALL_HANDLE_STRUCTRET \
507 cc->retref = !(sz <= 16); \
508 if (cc->retref) cc->gpr[ngpr++] = (GPRArg)dp;
509
510#define CCALL_HANDLE_STRUCTRET2 \
511 ccall_copy_struct(cc, ctr, dp, sp, ccall_classify_struct(cts, ctr, ct));
512
513#define CCALL_HANDLE_COMPLEXRET \
514 /* Complex values are returned in 1 or 2 FPRs. */ \
515 cc->retref = 0;
516
517#if LJ_ABI_SOFTFP /* MIPS64 soft-float */
518
519#define CCALL_HANDLE_COMPLEXRET2 \
520 if (ctr->size == 2*sizeof(float)) { /* Copy complex float from GPRs. */ \
521 ((intptr_t *)dp)[0] = cc->gpr[0]; \
522 } else { /* Copy complex double from GPRs. */ \
523 ((intptr_t *)dp)[0] = cc->gpr[0]; \
524 ((intptr_t *)dp)[1] = cc->gpr[1]; \
525 }
526
527#define CCALL_HANDLE_COMPLEXARG \
528 /* Pass complex by value in 2 or 4 GPRs. */
529
530/* Position of soft-float 'float' return value depends on endianess. */
531#define CCALL_HANDLE_RET \
532 if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
533 sp = (uint8_t *)cc->gpr + LJ_ENDIAN_SELECT(0, 4);
534
535#else /* MIPS64 hard-float */
536
537#define CCALL_HANDLE_COMPLEXRET2 \
538 if (ctr->size == 2*sizeof(float)) { /* Copy complex float from FPRs. */ \
539 ((float *)dp)[0] = cc->fpr[0].f; \
540 ((float *)dp)[1] = cc->fpr[1].f; \
541 } else { /* Copy complex double from FPRs. */ \
542 ((double *)dp)[0] = cc->fpr[0].d; \
543 ((double *)dp)[1] = cc->fpr[1].d; \
544 }
545
546#define CCALL_HANDLE_COMPLEXARG \
547 if (sz == 2*sizeof(float)) { \
548 isfp = 2; \
549 if (ngpr < maxgpr) \
550 sz *= 2; \
425 } 551 }
426 552
427#define CCALL_HANDLE_RET \ 553#define CCALL_HANDLE_RET \
428 if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \ 554 if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
429 sp = (uint8_t *)&cc->fpr[0].f; 555 sp = (uint8_t *)&cc->fpr[0].f;
430 556
557#endif
558
559#define CCALL_HANDLE_STRUCTARG \
560 /* Pass all structs by value in registers and/or on the stack. */
561
562#define CCALL_HANDLE_REGARG \
563 if (ngpr < maxgpr) { \
564 dp = &cc->gpr[ngpr]; \
565 if (ngpr + n > maxgpr) { \
566 nsp += ngpr + n - maxgpr; /* Assumes contiguous gpr/stack fields. */ \
567 if (nsp > CCALL_MAXSTACK) goto err_nyi; /* Too many arguments. */ \
568 ngpr = maxgpr; \
569 } else { \
570 ngpr += n; \
571 } \
572 goto done; \
573 }
574
431#else 575#else
432#error "Missing calling convention definitions for this architecture" 576#error "Missing calling convention definitions for this architecture"
433#endif 577#endif
@@ -621,6 +765,125 @@ noth: /* Not a homogeneous float/double aggregate. */
621 765
622#endif 766#endif
623 767
768/* -- ARM64 ABI struct classification ------------------------------------- */
769
770#if LJ_TARGET_ARM64
771
772/* Classify a struct based on its fields. */
773static unsigned int ccall_classify_struct(CTState *cts, CType *ct)
774{
775 CTSize sz = ct->size;
776 unsigned int r = 0, n = 0, isu = (ct->info & CTF_UNION);
777 while (ct->sib) {
778 CType *sct;
779 ct = ctype_get(cts, ct->sib);
780 if (ctype_isfield(ct->info)) {
781 sct = ctype_rawchild(cts, ct);
782 if (ctype_isfp(sct->info)) {
783 r |= sct->size;
784 if (!isu) n++; else if (n == 0) n = 1;
785 } else if (ctype_iscomplex(sct->info)) {
786 r |= (sct->size >> 1);
787 if (!isu) n += 2; else if (n < 2) n = 2;
788 } else if (ctype_isstruct(sct->info)) {
789 goto substruct;
790 } else {
791 goto noth;
792 }
793 } else if (ctype_isbitfield(ct->info)) {
794 goto noth;
795 } else if (ctype_isxattrib(ct->info, CTA_SUBTYPE)) {
796 sct = ctype_rawchild(cts, ct);
797 substruct:
798 if (sct->size > 0) {
799 unsigned int s = ccall_classify_struct(cts, sct);
800 if (s <= 1) goto noth;
801 r |= (s & 255);
802 if (!isu) n += (s >> 8); else if (n < (s >>8)) n = (s >> 8);
803 }
804 }
805 }
806 if ((r == 4 || r == 8) && n <= 4)
807 return r + (n << 8);
808noth: /* Not a homogeneous float/double aggregate. */
809 return (sz <= 16); /* Return structs of size <= 16 in GPRs. */
810}
811
812#endif
813
814/* -- MIPS64 ABI struct classification ---------------------------- */
815
816#if LJ_TARGET_MIPS64
817
818#define FTYPE_FLOAT 1
819#define FTYPE_DOUBLE 2
820
821/* Classify FP fields (max. 2) and their types. */
822static unsigned int ccall_classify_struct(CTState *cts, CType *ct, CType *ctf)
823{
824 int n = 0, ft = 0;
825 if ((ctf->info & CTF_VARARG) || (ct->info & CTF_UNION))
826 goto noth;
827 while (ct->sib) {
828 CType *sct;
829 ct = ctype_get(cts, ct->sib);
830 if (n == 2) {
831 goto noth;
832 } else if (ctype_isfield(ct->info)) {
833 sct = ctype_rawchild(cts, ct);
834 if (ctype_isfp(sct->info)) {
835 ft |= (sct->size == 4 ? FTYPE_FLOAT : FTYPE_DOUBLE) << 2*n;
836 n++;
837 } else {
838 goto noth;
839 }
840 } else if (ctype_isbitfield(ct->info) ||
841 ctype_isxattrib(ct->info, CTA_SUBTYPE)) {
842 goto noth;
843 }
844 }
845 if (n <= 2)
846 return ft;
847noth: /* Not a homogeneous float/double aggregate. */
848 return 0; /* Struct is in GPRs. */
849}
850
851static void ccall_copy_struct(CCallState *cc, CType *ctr, void *dp, void *sp,
852 int ft)
853{
854 if (LJ_ABI_SOFTFP ? ft :
855 ((ft & 3) == FTYPE_FLOAT || (ft >> 2) == FTYPE_FLOAT)) {
856 int i, ofs = 0;
857 for (i = 0; ft != 0; i++, ft >>= 2) {
858 if ((ft & 3) == FTYPE_FLOAT) {
859#if LJ_ABI_SOFTFP
860 /* The 2nd FP struct result is in CARG1 (gpr[2]) and not CRET2. */
861 memcpy((uint8_t *)dp + ofs,
862 (uint8_t *)&cc->gpr[2*i] + LJ_ENDIAN_SELECT(0, 4), 4);
863#else
864 *(float *)((uint8_t *)dp + ofs) = cc->fpr[i].f;
865#endif
866 ofs += 4;
867 } else {
868 ofs = (ofs + 7) & ~7; /* 64 bit alignment. */
869#if LJ_ABI_SOFTFP
870 *(intptr_t *)((uint8_t *)dp + ofs) = cc->gpr[2*i];
871#else
872 *(double *)((uint8_t *)dp + ofs) = cc->fpr[i].d;
873#endif
874 ofs += 8;
875 }
876 }
877 } else {
878#if !LJ_ABI_SOFTFP
879 if (ft) sp = (uint8_t *)&cc->fpr[0];
880#endif
881 memcpy(dp, sp, ctr->size);
882 }
883}
884
885#endif
886
624/* -- Common C call handling ---------------------------------------------- */ 887/* -- Common C call handling ---------------------------------------------- */
625 888
626/* Infer the destination CTypeID for a vararg argument. */ 889/* Infer the destination CTypeID for a vararg argument. */
@@ -788,6 +1051,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 : 1051 *(int32_t *)dp = d->size == 1 ? (int32_t)*(int8_t *)dp :
789 (int32_t)*(int16_t *)dp; 1052 (int32_t)*(int16_t *)dp;
790 } 1053 }
1054#if LJ_TARGET_ARM64 && LJ_BE
1055 if (isfp && d->size == sizeof(float))
1056 ((float *)dp)[1] = ((float *)dp)[0]; /* Floats occupy high slot. */
1057#endif
1058#if LJ_TARGET_MIPS64 || (LJ_TARGET_ARM64 && LJ_BE)
1059 if ((ctype_isinteger_or_bool(d->info) || ctype_isenum(d->info)
1060#if LJ_TARGET_MIPS64
1061 || (isfp && nsp == 0)
1062#endif
1063 ) && d->size <= 4) {
1064 *(int64_t *)dp = (int64_t)*(int32_t *)dp; /* Sign-extend to 64 bit. */
1065 }
1066#endif
791#if LJ_TARGET_X64 && LJ_ABI_WIN 1067#if LJ_TARGET_X64 && LJ_ABI_WIN
792 if (isva) { /* Windows/x64 mirrors varargs in both register sets. */ 1068 if (isva) { /* Windows/x64 mirrors varargs in both register sets. */
793 if (nfpr == ngpr) 1069 if (nfpr == ngpr)
@@ -803,13 +1079,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. */ 1079 cc->fpr[nfpr-1].d[0] = cc->fpr[nfpr-2].d[1]; /* Split complex double. */
804 cc->fpr[nfpr-2].d[1] = 0; 1080 cc->fpr[nfpr-2].d[1] = 0;
805 } 1081 }
1082#elif LJ_TARGET_ARM64 || (LJ_TARGET_MIPS64 && !LJ_ABI_SOFTFP)
1083 if (isfp == 2 && (uint8_t *)dp < (uint8_t *)cc->stack) {
1084 /* Split float HFA or complex float into separate registers. */
1085 CTSize i = (sz >> 2) - 1;
1086 do { ((uint64_t *)dp)[i] = ((uint32_t *)dp)[i]; } while (i--);
1087 }
806#else 1088#else
807 UNUSED(isfp); 1089 UNUSED(isfp);
808#endif 1090#endif
809 } 1091 }
810 if (fid) lj_err_caller(L, LJ_ERR_FFI_NUMARG); /* Too few arguments. */ 1092 if (fid) lj_err_caller(L, LJ_ERR_FFI_NUMARG); /* Too few arguments. */
811 1093
812#if LJ_TARGET_X64 || LJ_TARGET_PPC 1094#if LJ_TARGET_X64 || (LJ_TARGET_PPC && !LJ_ABI_SOFTFP)
813 cc->nfpr = nfpr; /* Required for vararg functions. */ 1095 cc->nfpr = nfpr; /* Required for vararg functions. */
814#endif 1096#endif
815 cc->nsp = nsp; 1097 cc->nsp = nsp;
@@ -844,7 +1126,8 @@ static int ccall_get_results(lua_State *L, CTState *cts, CType *ct,
844 CCALL_HANDLE_COMPLEXRET2 1126 CCALL_HANDLE_COMPLEXRET2
845 return 1; /* One GC step. */ 1127 return 1; /* One GC step. */
846 } 1128 }
847 if (LJ_BE && ctype_isinteger_or_bool(ctr->info) && ctr->size < CTSIZE_PTR) 1129 if (LJ_BE && ctr->size < CTSIZE_PTR &&
1130 (ctype_isinteger_or_bool(ctr->info) || ctype_isenum(ctr->info)))
848 sp += (CTSIZE_PTR - ctr->size); 1131 sp += (CTSIZE_PTR - ctr->size);
849#if CCALL_NUM_FPR 1132#if CCALL_NUM_FPR
850 if (ctype_isfp(ctr->info) || ctype_isvector(ctr->info)) 1133 if (ctype_isfp(ctr->info) || ctype_isvector(ctr->info))