diff options
author | Mike Pall <mike> | 2016-05-28 05:10:55 +0200 |
---|---|---|
committer | Mike Pall <mike> | 2016-05-28 05:10:55 +0200 |
commit | d9986fbadb6c50b826e39e5f690bcf0b4cd6a20b (patch) | |
tree | c89961a1a8949c19872aa39269c2408dd6595733 /src/lj_ccall.c | |
parent | e3c4c9af0f07a114fb754fed6ac358a102f49e2f (diff) | |
download | luajit-d9986fbadb6c50b826e39e5f690bcf0b4cd6a20b.tar.gz luajit-d9986fbadb6c50b826e39e5f690bcf0b4cd6a20b.tar.bz2 luajit-d9986fbadb6c50b826e39e5f690bcf0b4cd6a20b.zip |
MIPS64, part 1: Add MIPS64 support to interpreter.
Contributed by Djordje Kovacevic and Stefan Pejic from RT-RK.com.
Sponsored by Cisco Systems, Inc.
Diffstat (limited to 'src/lj_ccall.c')
-rw-r--r-- | src/lj_ccall.c | 159 |
1 files changed, 155 insertions, 4 deletions
diff --git a/src/lj_ccall.c b/src/lj_ccall.c index eb7c1ee0..b599be33 100644 --- a/src/lj_ccall.c +++ b/src/lj_ccall.c | |||
@@ -407,8 +407,8 @@ | |||
407 | if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \ | 407 | if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \ |
408 | ctr = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */ | 408 | ctr = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */ |
409 | 409 | ||
410 | #elif LJ_TARGET_MIPS | 410 | #elif LJ_TARGET_MIPS32 |
411 | /* -- MIPS calling conventions -------------------------------------------- */ | 411 | /* -- MIPS o32 calling conventions ---------------------------------------- */ |
412 | 412 | ||
413 | #define CCALL_HANDLE_STRUCTRET \ | 413 | #define CCALL_HANDLE_STRUCTRET \ |
414 | cc->retref = 1; /* Return all structs by reference. */ \ | 414 | cc->retref = 1; /* Return all structs by reference. */ \ |
@@ -483,6 +483,78 @@ | |||
483 | sp = (uint8_t *)&cc->fpr[0].f; | 483 | sp = (uint8_t *)&cc->fpr[0].f; |
484 | #endif | 484 | #endif |
485 | 485 | ||
486 | #elif LJ_TARGET_MIPS64 | ||
487 | /* -- MIPS n64 calling conventions ---------------------------------------- */ | ||
488 | |||
489 | #define CCALL_HANDLE_STRUCTRET \ | ||
490 | cc->retref = !(sz <= 16); \ | ||
491 | if (cc->retref) cc->gpr[ngpr++] = (GPRArg)dp; | ||
492 | |||
493 | #define CCALL_HANDLE_STRUCTRET2 \ | ||
494 | ccall_copy_struct(cc, ctr, dp, sp, ccall_classify_struct(cts, ctr, ct)); | ||
495 | |||
496 | #define CCALL_HANDLE_COMPLEXRET \ | ||
497 | /* Complex values are returned in 1 or 2 FPRs. */ \ | ||
498 | cc->retref = 0; | ||
499 | |||
500 | #if LJ_ABI_SOFTFP /* MIPS64 soft-float */ | ||
501 | |||
502 | #define CCALL_HANDLE_COMPLEXRET2 \ | ||
503 | if (ctr->size == 2*sizeof(float)) { /* Copy complex float from GPRs. */ \ | ||
504 | ((intptr_t *)dp)[0] = cc->gpr[0]; \ | ||
505 | } else { /* Copy complex double from GPRs. */ \ | ||
506 | ((intptr_t *)dp)[0] = cc->gpr[0]; \ | ||
507 | ((intptr_t *)dp)[1] = cc->gpr[1]; \ | ||
508 | } | ||
509 | |||
510 | #define CCALL_HANDLE_COMPLEXARG \ | ||
511 | /* Pass complex by value in 2 or 4 GPRs. */ | ||
512 | |||
513 | /* Position of soft-float 'float' return value depends on endianess. */ | ||
514 | #define CCALL_HANDLE_RET \ | ||
515 | if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \ | ||
516 | sp = (uint8_t *)cc->gpr + LJ_ENDIAN_SELECT(0, 4); | ||
517 | |||
518 | #else /* MIPS64 hard-float */ | ||
519 | |||
520 | #define CCALL_HANDLE_COMPLEXRET2 \ | ||
521 | if (ctr->size == 2*sizeof(float)) { /* Copy complex float from FPRs. */ \ | ||
522 | ((float *)dp)[0] = cc->fpr[0].f; \ | ||
523 | ((float *)dp)[1] = cc->fpr[1].f; \ | ||
524 | } else { /* Copy complex double from FPRs. */ \ | ||
525 | ((double *)dp)[0] = cc->fpr[0].d; \ | ||
526 | ((double *)dp)[1] = cc->fpr[1].d; \ | ||
527 | } | ||
528 | |||
529 | #define CCALL_HANDLE_COMPLEXARG \ | ||
530 | if (sz == 2*sizeof(float)) { \ | ||
531 | isfp = 2; \ | ||
532 | if (ngpr < maxgpr) \ | ||
533 | sz *= 2; \ | ||
534 | } | ||
535 | |||
536 | #define CCALL_HANDLE_RET \ | ||
537 | if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \ | ||
538 | sp = (uint8_t *)&cc->fpr[0].f; | ||
539 | |||
540 | #endif | ||
541 | |||
542 | #define CCALL_HANDLE_STRUCTARG \ | ||
543 | /* Pass all structs by value in registers and/or on the stack. */ | ||
544 | |||
545 | #define CCALL_HANDLE_REGARG \ | ||
546 | if (ngpr < maxgpr) { \ | ||
547 | dp = &cc->gpr[ngpr]; \ | ||
548 | if (ngpr + n > maxgpr) { \ | ||
549 | nsp += ngpr + n - maxgpr; /* Assumes contiguous gpr/stack fields. */ \ | ||
550 | if (nsp > CCALL_MAXSTACK) goto err_nyi; /* Too many arguments. */ \ | ||
551 | ngpr = maxgpr; \ | ||
552 | } else { \ | ||
553 | ngpr += n; \ | ||
554 | } \ | ||
555 | goto done; \ | ||
556 | } | ||
557 | |||
486 | #else | 558 | #else |
487 | #error "Missing calling convention definitions for this architecture" | 559 | #error "Missing calling convention definitions for this architecture" |
488 | #endif | 560 | #endif |
@@ -722,6 +794,78 @@ noth: /* Not a homogeneous float/double aggregate. */ | |||
722 | 794 | ||
723 | #endif | 795 | #endif |
724 | 796 | ||
797 | /* -- MIPS64 ABI struct classification ---------------------------- */ | ||
798 | |||
799 | #if LJ_TARGET_MIPS64 | ||
800 | |||
801 | #define FTYPE_FLOAT 1 | ||
802 | #define FTYPE_DOUBLE 2 | ||
803 | |||
804 | /* Classify FP fields (max. 2) and their types. */ | ||
805 | static unsigned int ccall_classify_struct(CTState *cts, CType *ct, CType *ctf) | ||
806 | { | ||
807 | int n = 0, ft = 0; | ||
808 | if ((ctf->info & CTF_VARARG) || (ct->info & CTF_UNION)) | ||
809 | goto noth; | ||
810 | while (ct->sib) { | ||
811 | CType *sct; | ||
812 | ct = ctype_get(cts, ct->sib); | ||
813 | if (n == 2) { | ||
814 | goto noth; | ||
815 | } else if (ctype_isfield(ct->info)) { | ||
816 | sct = ctype_rawchild(cts, ct); | ||
817 | if (ctype_isfp(sct->info)) { | ||
818 | ft |= (sct->size == 4 ? FTYPE_FLOAT : FTYPE_DOUBLE) << 2*n; | ||
819 | n++; | ||
820 | } else { | ||
821 | goto noth; | ||
822 | } | ||
823 | } else if (ctype_isbitfield(ct->info) || | ||
824 | ctype_isxattrib(ct->info, CTA_SUBTYPE)) { | ||
825 | goto noth; | ||
826 | } | ||
827 | } | ||
828 | if (n <= 2) | ||
829 | return ft; | ||
830 | noth: /* Not a homogeneous float/double aggregate. */ | ||
831 | return 0; /* Struct is in GPRs. */ | ||
832 | } | ||
833 | |||
834 | void ccall_copy_struct(CCallState *cc, CType *ctr, void *dp, void *sp, int ft) | ||
835 | { | ||
836 | if (LJ_ABI_SOFTFP ? ft : | ||
837 | ((ft & 3) == FTYPE_FLOAT || (ft >> 2) == FTYPE_FLOAT)) { | ||
838 | int i, ofs = 0; | ||
839 | for (i = 0; ft != 0; i++, ft >>= 2) { | ||
840 | if ((ft & 3) == FTYPE_FLOAT) { | ||
841 | #if LJ_ABI_SOFTFP | ||
842 | /* The 2nd FP struct result is in CARG1 (gpr[2]) and not CRET2. */ | ||
843 | memcpy((uint8_t *)dp + ofs, | ||
844 | (uint8_t *)&cc->gpr[2*i] + LJ_ENDIAN_SELECT(0, 4), 4); | ||
845 | #else | ||
846 | *(float *)((uint8_t *)dp + ofs) = cc->fpr[i].f; | ||
847 | #endif | ||
848 | ofs += 4; | ||
849 | } else { | ||
850 | ofs = (ofs + 7) & ~7; /* 64 bit alignment. */ | ||
851 | #if LJ_ABI_SOFTFP | ||
852 | *(intptr_t *)((uint8_t *)dp + ofs) = cc->gpr[2*i]; | ||
853 | #else | ||
854 | *(double *)((uint8_t *)dp + ofs) = cc->fpr[i].d; | ||
855 | #endif | ||
856 | ofs += 8; | ||
857 | } | ||
858 | } | ||
859 | } else { | ||
860 | #if !LJ_ABI_SOFTFP | ||
861 | if (ft) sp = (uint8_t *)&cc->fpr[0]; | ||
862 | #endif | ||
863 | memcpy(dp, sp, ctr->size); | ||
864 | } | ||
865 | } | ||
866 | |||
867 | #endif | ||
868 | |||
725 | /* -- Common C call handling ---------------------------------------------- */ | 869 | /* -- Common C call handling ---------------------------------------------- */ |
726 | 870 | ||
727 | /* Infer the destination CTypeID for a vararg argument. */ | 871 | /* Infer the destination CTypeID for a vararg argument. */ |
@@ -889,6 +1033,12 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct, | |||
889 | *(int32_t *)dp = d->size == 1 ? (int32_t)*(int8_t *)dp : | 1033 | *(int32_t *)dp = d->size == 1 ? (int32_t)*(int8_t *)dp : |
890 | (int32_t)*(int16_t *)dp; | 1034 | (int32_t)*(int16_t *)dp; |
891 | } | 1035 | } |
1036 | #if LJ_TARGET_MIPS64 | ||
1037 | if ((ctype_isinteger_or_bool(d->info) || ctype_isenum(d->info) || | ||
1038 | (isfp && nsp == 0)) && d->size <= 4) { | ||
1039 | *(int64_t *)dp = (int64_t)*(int32_t *)dp; /* Sign-extend to 64 bit. */ | ||
1040 | } | ||
1041 | #endif | ||
892 | #if LJ_TARGET_X64 && LJ_ABI_WIN | 1042 | #if LJ_TARGET_X64 && LJ_ABI_WIN |
893 | if (isva) { /* Windows/x64 mirrors varargs in both register sets. */ | 1043 | if (isva) { /* Windows/x64 mirrors varargs in both register sets. */ |
894 | if (nfpr == ngpr) | 1044 | if (nfpr == ngpr) |
@@ -904,7 +1054,7 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct, | |||
904 | cc->fpr[nfpr-1].d[0] = cc->fpr[nfpr-2].d[1]; /* Split complex double. */ | 1054 | cc->fpr[nfpr-1].d[0] = cc->fpr[nfpr-2].d[1]; /* Split complex double. */ |
905 | cc->fpr[nfpr-2].d[1] = 0; | 1055 | cc->fpr[nfpr-2].d[1] = 0; |
906 | } | 1056 | } |
907 | #elif LJ_TARGET_ARM64 | 1057 | #elif LJ_TARGET_ARM64 || (LJ_TARGET_MIPS64 && !LJ_ABI_SOFTFP) |
908 | if (isfp == 2 && (uint8_t *)dp < (uint8_t *)cc->stack) { | 1058 | if (isfp == 2 && (uint8_t *)dp < (uint8_t *)cc->stack) { |
909 | /* Split float HFA or complex float into separate registers. */ | 1059 | /* Split float HFA or complex float into separate registers. */ |
910 | CTSize i = (sz >> 2) - 1; | 1060 | CTSize i = (sz >> 2) - 1; |
@@ -951,7 +1101,8 @@ static int ccall_get_results(lua_State *L, CTState *cts, CType *ct, | |||
951 | CCALL_HANDLE_COMPLEXRET2 | 1101 | CCALL_HANDLE_COMPLEXRET2 |
952 | return 1; /* One GC step. */ | 1102 | return 1; /* One GC step. */ |
953 | } | 1103 | } |
954 | if (LJ_BE && ctype_isinteger_or_bool(ctr->info) && ctr->size < CTSIZE_PTR) | 1104 | if (LJ_BE && ctr->size < CTSIZE_PTR && |
1105 | (ctype_isinteger_or_bool(ctr->info) || ctype_isenum(ctr->info))) | ||
955 | sp += (CTSIZE_PTR - ctr->size); | 1106 | sp += (CTSIZE_PTR - ctr->size); |
956 | #if CCALL_NUM_FPR | 1107 | #if CCALL_NUM_FPR |
957 | if (ctype_isfp(ctr->info) || ctype_isvector(ctr->info)) | 1108 | if (ctype_isfp(ctr->info) || ctype_isvector(ctr->info)) |