diff options
Diffstat (limited to 'src/lj_ccall.c')
-rw-r--r-- | src/lj_ccall.c | 397 |
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. */ |
525 | static int ccall_struct_reg(CCallState *cc, GPRArg *dp, int *rcl) | 672 | static 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. */ | ||
778 | static 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); | ||
813 | noth: /* 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. */ | ||
827 | static 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; | ||
852 | noth: /* Not a homogeneous float/double aggregate. */ | ||
853 | return 0; /* Struct is in GPRs. */ | ||
854 | } | ||
855 | |||
856 | static 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. */ |