diff options
Diffstat (limited to 'src/lj_ccall.c')
-rw-r--r-- | src/lj_ccall.c | 377 |
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. */ | ||
773 | static 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); | ||
808 | noth: /* 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. */ | ||
822 | static 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; | ||
847 | noth: /* Not a homogeneous float/double aggregate. */ | ||
848 | return 0; /* Struct is in GPRs. */ | ||
849 | } | ||
850 | |||
851 | static 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)) |