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