diff options
author | Mike Pall <mike> | 2023-08-29 02:21:51 +0200 |
---|---|---|
committer | Mike Pall <mike> | 2023-08-29 02:21:51 +0200 |
commit | 83954100dba9fc0cf5eeaf122f007df35ec9a604 (patch) | |
tree | 49b738b500e50dbd96f9959c4cb50492bbc69114 /src | |
parent | cf903edb30e0cbd620ebd4bac02d4e2b4410fd02 (diff) | |
download | luajit-83954100dba9fc0cf5eeaf122f007df35ec9a604.tar.gz luajit-83954100dba9fc0cf5eeaf122f007df35ec9a604.tar.bz2 luajit-83954100dba9fc0cf5eeaf122f007df35ec9a604.zip |
FFI/ARM64/OSX: Handle non-standard OSX C calling conventions.
Contributed by Peter Cawley. #205
Diffstat (limited to 'src')
-rw-r--r-- | src/lj_asm_arm64.h | 75 | ||||
-rw-r--r-- | src/lj_ccall.c | 11 | ||||
-rw-r--r-- | src/lj_ccall.h | 6 | ||||
-rw-r--r-- | src/lj_crecord.c | 27 |
4 files changed, 98 insertions, 21 deletions
diff --git a/src/lj_asm_arm64.h b/src/lj_asm_arm64.h index 1d5cca4f..3889883d 100644 --- a/src/lj_asm_arm64.h +++ b/src/lj_asm_arm64.h | |||
@@ -419,7 +419,7 @@ static int asm_fuseorshift(ASMState *as, IRIns *ir) | |||
419 | static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args) | 419 | static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args) |
420 | { | 420 | { |
421 | uint32_t n, nargs = CCI_XNARGS(ci); | 421 | uint32_t n, nargs = CCI_XNARGS(ci); |
422 | int32_t ofs = 0; | 422 | int32_t spofs = 0, spalign = LJ_HASFFI && LJ_TARGET_OSX ? 0 : 7; |
423 | Reg gpr, fpr = REGARG_FIRSTFPR; | 423 | Reg gpr, fpr = REGARG_FIRSTFPR; |
424 | if (ci->func) | 424 | if (ci->func) |
425 | emit_call(as, ci->func); | 425 | emit_call(as, ci->func); |
@@ -438,8 +438,14 @@ static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args) | |||
438 | fpr++; | 438 | fpr++; |
439 | } else { | 439 | } else { |
440 | Reg r = ra_alloc1(as, ref, RSET_FPR); | 440 | Reg r = ra_alloc1(as, ref, RSET_FPR); |
441 | emit_spstore(as, ir, r, ofs + ((LJ_BE && !irt_isnum(ir->t)) ? 4 : 0)); | 441 | int32_t al = spalign; |
442 | ofs += 8; | 442 | #if LJ_HASFFI && LJ_TARGET_OSX |
443 | al |= irt_isnum(ir->t) ? 7 : 3; | ||
444 | #endif | ||
445 | spofs = (spofs + al) & ~al; | ||
446 | if (LJ_BE && al >= 7 && !irt_isnum(ir->t)) spofs += 4, al -= 4; | ||
447 | emit_spstore(as, ir, r, spofs); | ||
448 | spofs += al + 1; | ||
443 | } | 449 | } |
444 | } else { | 450 | } else { |
445 | if (gpr <= REGARG_LASTGPR) { | 451 | if (gpr <= REGARG_LASTGPR) { |
@@ -449,10 +455,27 @@ static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args) | |||
449 | gpr++; | 455 | gpr++; |
450 | } else { | 456 | } else { |
451 | Reg r = ra_alloc1(as, ref, RSET_GPR); | 457 | Reg r = ra_alloc1(as, ref, RSET_GPR); |
452 | emit_spstore(as, ir, r, ofs + ((LJ_BE && !irt_is64(ir->t)) ? 4 : 0)); | 458 | int32_t al = spalign; |
453 | ofs += 8; | 459 | #if LJ_HASFFI && LJ_TARGET_OSX |
460 | al |= irt_size(ir->t) - 1; | ||
461 | #endif | ||
462 | spofs = (spofs + al) & ~al; | ||
463 | if (al >= 3) { | ||
464 | if (LJ_BE && al >= 7 && !irt_is64(ir->t)) spofs += 4, al -= 4; | ||
465 | emit_spstore(as, ir, r, spofs); | ||
466 | } else { | ||
467 | lj_assertA(al == 0 || al == 1, "size %d unexpected", al + 1); | ||
468 | emit_lso(as, al ? A64I_STRH : A64I_STRB, r, RID_SP, spofs); | ||
469 | } | ||
470 | spofs += al + 1; | ||
454 | } | 471 | } |
455 | } | 472 | } |
473 | #if LJ_HASFFI && LJ_TARGET_OSX | ||
474 | } else { /* Marker for start of varargs. */ | ||
475 | gpr = REGARG_LASTGPR+1; | ||
476 | fpr = REGARG_LASTFPR+1; | ||
477 | spalign = 7; | ||
478 | #endif | ||
456 | } | 479 | } |
457 | } | 480 | } |
458 | } | 481 | } |
@@ -1976,19 +1999,41 @@ static void asm_tail_prep(ASMState *as) | |||
1976 | /* Ensure there are enough stack slots for call arguments. */ | 1999 | /* Ensure there are enough stack slots for call arguments. */ |
1977 | static Reg asm_setup_call_slots(ASMState *as, IRIns *ir, const CCallInfo *ci) | 2000 | static Reg asm_setup_call_slots(ASMState *as, IRIns *ir, const CCallInfo *ci) |
1978 | { | 2001 | { |
1979 | IRRef args[CCI_NARGS_MAX*2]; | 2002 | #if LJ_HASFFI |
1980 | uint32_t i, nargs = CCI_XNARGS(ci); | 2003 | uint32_t i, nargs = CCI_XNARGS(ci); |
1981 | int nslots = 0, ngpr = REGARG_NUMGPR, nfpr = REGARG_NUMFPR; | 2004 | if (nargs > (REGARG_NUMGPR < REGARG_NUMFPR ? REGARG_NUMGPR : REGARG_NUMFPR) || |
1982 | asm_collectargs(as, ir, ci, args); | 2005 | (LJ_TARGET_OSX && (ci->flags & CCI_VARARG))) { |
1983 | for (i = 0; i < nargs; i++) { | 2006 | IRRef args[CCI_NARGS_MAX*2]; |
1984 | if (args[i] && irt_isfp(IR(args[i])->t)) { | 2007 | int ngpr = REGARG_NUMGPR, nfpr = REGARG_NUMFPR; |
1985 | if (nfpr > 0) nfpr--; else nslots += 2; | 2008 | int spofs = 0, spalign = LJ_TARGET_OSX ? 0 : 7, nslots; |
1986 | } else { | 2009 | asm_collectargs(as, ir, ci, args); |
1987 | if (ngpr > 0) ngpr--; else nslots += 2; | 2010 | for (i = 0; i < nargs; i++) { |
2011 | int al = spalign; | ||
2012 | if (!args[i]) { | ||
2013 | #if LJ_TARGET_OSX | ||
2014 | /* Marker for start of varaargs. */ | ||
2015 | nfpr = 0; | ||
2016 | ngpr = 0; | ||
2017 | spalign = 7; | ||
2018 | #endif | ||
2019 | } else if (irt_isfp(IR(args[i])->t)) { | ||
2020 | if (nfpr > 0) { nfpr--; continue; } | ||
2021 | #if LJ_TARGET_OSX | ||
2022 | al |= irt_isnum(IR(args[i])->t) ? 7 : 3; | ||
2023 | #endif | ||
2024 | } else { | ||
2025 | if (ngpr > 0) { ngpr--; continue; } | ||
2026 | #if LJ_TARGET_OSX | ||
2027 | al |= irt_size(IR(args[i])->t) - 1; | ||
2028 | #endif | ||
2029 | } | ||
2030 | spofs = (spofs + 2*al+1) & ~al; /* Align and bump stack pointer. */ | ||
1988 | } | 2031 | } |
2032 | nslots = (spofs + 3) >> 2; | ||
2033 | if (nslots > as->evenspill) /* Leave room for args in stack slots. */ | ||
2034 | as->evenspill = nslots; | ||
1989 | } | 2035 | } |
1990 | if (nslots > as->evenspill) /* Leave room for args in stack slots. */ | 2036 | #endif |
1991 | as->evenspill = nslots; | ||
1992 | return REGSP_HINT(RID_RET); | 2037 | return REGSP_HINT(RID_RET); |
1993 | } | 2038 | } |
1994 | 2039 | ||
diff --git a/src/lj_ccall.c b/src/lj_ccall.c index 9001cb5a..00e753b9 100644 --- a/src/lj_ccall.c +++ b/src/lj_ccall.c | |||
@@ -348,7 +348,6 @@ | |||
348 | goto done; \ | 348 | goto done; \ |
349 | } else { \ | 349 | } else { \ |
350 | nfpr = CCALL_NARG_FPR; /* Prevent reordering. */ \ | 350 | nfpr = CCALL_NARG_FPR; /* Prevent reordering. */ \ |
351 | if (LJ_TARGET_OSX && d->size < 8) goto err_nyi; \ | ||
352 | } \ | 351 | } \ |
353 | } else { /* Try to pass argument in GPRs. */ \ | 352 | } else { /* Try to pass argument in GPRs. */ \ |
354 | if (!LJ_TARGET_OSX && (d->info & CTF_ALIGN) > CTALIGN_PTR) \ | 353 | if (!LJ_TARGET_OSX && (d->info & CTF_ALIGN) > CTALIGN_PTR) \ |
@@ -359,7 +358,6 @@ | |||
359 | goto done; \ | 358 | goto done; \ |
360 | } else { \ | 359 | } else { \ |
361 | ngpr = maxgpr; /* Prevent reordering. */ \ | 360 | ngpr = maxgpr; /* Prevent reordering. */ \ |
362 | if (LJ_TARGET_OSX && d->size < 8) goto err_nyi; \ | ||
363 | } \ | 361 | } \ |
364 | } | 362 | } |
365 | 363 | ||
@@ -1023,7 +1021,7 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct, | |||
1023 | CCALL_HANDLE_STRUCTARG | 1021 | CCALL_HANDLE_STRUCTARG |
1024 | } else if (ctype_iscomplex(d->info)) { | 1022 | } else if (ctype_iscomplex(d->info)) { |
1025 | CCALL_HANDLE_COMPLEXARG | 1023 | CCALL_HANDLE_COMPLEXARG |
1026 | } else { | 1024 | } else if (!(CCALL_PACK_STACKARG && ctype_isenum(d->info))) { |
1027 | sz = CTSIZE_PTR; | 1025 | sz = CTSIZE_PTR; |
1028 | } | 1026 | } |
1029 | n = (sz + CTSIZE_PTR-1) / CTSIZE_PTR; /* Number of GPRs or stack slots needed. */ | 1027 | n = (sz + CTSIZE_PTR-1) / CTSIZE_PTR; /* Number of GPRs or stack slots needed. */ |
@@ -1033,12 +1031,12 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct, | |||
1033 | /* Otherwise pass argument on stack. */ | 1031 | /* Otherwise pass argument on stack. */ |
1034 | if (CCALL_ALIGN_STACKARG) { /* Align argument on stack. */ | 1032 | if (CCALL_ALIGN_STACKARG) { /* Align argument on stack. */ |
1035 | MSize align = (1u << ctype_align(d->info)) - 1; | 1033 | MSize align = (1u << ctype_align(d->info)) - 1; |
1036 | if (rp) | 1034 | if (rp || (CCALL_PACK_STACKARG && isva && align < CTSIZE_PTR-1)) |
1037 | align = CTSIZE_PTR-1; | 1035 | align = CTSIZE_PTR-1; |
1038 | nsp = (nsp + align) & ~align; | 1036 | nsp = (nsp + align) & ~align; |
1039 | } | 1037 | } |
1040 | dp = ((uint8_t *)cc->stack) + nsp; | 1038 | dp = ((uint8_t *)cc->stack) + nsp; |
1041 | nsp += n * CTSIZE_PTR; | 1039 | nsp += CCALL_PACK_STACKARG ? sz : n * CTSIZE_PTR; |
1042 | if (nsp > CCALL_SIZE_STACK) { /* Too many arguments. */ | 1040 | if (nsp > CCALL_SIZE_STACK) { /* Too many arguments. */ |
1043 | err_nyi: | 1041 | err_nyi: |
1044 | lj_err_caller(L, LJ_ERR_FFI_NYICALL); | 1042 | lj_err_caller(L, LJ_ERR_FFI_NYICALL); |
@@ -1053,7 +1051,8 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct, | |||
1053 | } | 1051 | } |
1054 | lj_cconv_ct_tv(cts, d, (uint8_t *)dp, o, CCF_ARG(narg)); | 1052 | lj_cconv_ct_tv(cts, d, (uint8_t *)dp, o, CCF_ARG(narg)); |
1055 | /* Extend passed integers to 32 bits at least. */ | 1053 | /* Extend passed integers to 32 bits at least. */ |
1056 | if (ctype_isinteger_or_bool(d->info) && d->size < 4) { | 1054 | if (ctype_isinteger_or_bool(d->info) && d->size < 4 && |
1055 | (!CCALL_PACK_STACKARG || !((uintptr_t)dp & 3))) { /* Assumes LJ_LE. */ | ||
1057 | if (d->info & CTF_UNSIGNED) | 1056 | if (d->info & CTF_UNSIGNED) |
1058 | *(uint32_t *)dp = d->size == 1 ? (uint32_t)*(uint8_t *)dp : | 1057 | *(uint32_t *)dp = d->size == 1 ? (uint32_t)*(uint8_t *)dp : |
1059 | (uint32_t)*(uint16_t *)dp; | 1058 | (uint32_t)*(uint16_t *)dp; |
diff --git a/src/lj_ccall.h b/src/lj_ccall.h index 57300817..24646d90 100644 --- a/src/lj_ccall.h +++ b/src/lj_ccall.h | |||
@@ -75,6 +75,9 @@ typedef union FPRArg { | |||
75 | #define CCALL_NARG_FPR 8 | 75 | #define CCALL_NARG_FPR 8 |
76 | #define CCALL_NRET_FPR 4 | 76 | #define CCALL_NRET_FPR 4 |
77 | #define CCALL_SPS_FREE 0 | 77 | #define CCALL_SPS_FREE 0 |
78 | #if LJ_TARGET_OSX | ||
79 | #define CCALL_PACK_STACKARG 1 | ||
80 | #endif | ||
78 | 81 | ||
79 | typedef intptr_t GPRArg; | 82 | typedef intptr_t GPRArg; |
80 | typedef union FPRArg { | 83 | typedef union FPRArg { |
@@ -139,6 +142,9 @@ typedef union FPRArg { | |||
139 | #ifndef CCALL_ALIGN_STACKARG | 142 | #ifndef CCALL_ALIGN_STACKARG |
140 | #define CCALL_ALIGN_STACKARG 1 | 143 | #define CCALL_ALIGN_STACKARG 1 |
141 | #endif | 144 | #endif |
145 | #ifndef CCALL_PACK_STACKARG | ||
146 | #define CCALL_PACK_STACKARG 0 | ||
147 | #endif | ||
142 | #ifndef CCALL_ALIGN_CALLSTATE | 148 | #ifndef CCALL_ALIGN_CALLSTATE |
143 | #define CCALL_ALIGN_CALLSTATE 8 | 149 | #define CCALL_ALIGN_CALLSTATE 8 |
144 | #endif | 150 | #endif |
diff --git a/src/lj_crecord.c b/src/lj_crecord.c index 04bc895d..d7a522fb 100644 --- a/src/lj_crecord.c +++ b/src/lj_crecord.c | |||
@@ -1118,6 +1118,12 @@ static TRef crec_call_args(jit_State *J, RecordFFData *rd, | |||
1118 | ngpr = 1; | 1118 | ngpr = 1; |
1119 | else if (ctype_cconv(ct->info) == CTCC_FASTCALL) | 1119 | else if (ctype_cconv(ct->info) == CTCC_FASTCALL) |
1120 | ngpr = 2; | 1120 | ngpr = 2; |
1121 | #elif LJ_TARGET_ARM64 | ||
1122 | #if LJ_ABI_WIN | ||
1123 | #error "NYI: ARM64 Windows ABI calling conventions" | ||
1124 | #elif LJ_TARGET_OSX | ||
1125 | int ngpr = CCALL_NARG_GPR; | ||
1126 | #endif | ||
1121 | #endif | 1127 | #endif |
1122 | 1128 | ||
1123 | /* Skip initial attributes. */ | 1129 | /* Skip initial attributes. */ |
@@ -1143,6 +1149,14 @@ static TRef crec_call_args(jit_State *J, RecordFFData *rd, | |||
1143 | } else { | 1149 | } else { |
1144 | if (!(ct->info & CTF_VARARG)) | 1150 | if (!(ct->info & CTF_VARARG)) |
1145 | lj_trace_err(J, LJ_TRERR_NYICALL); /* Too many arguments. */ | 1151 | lj_trace_err(J, LJ_TRERR_NYICALL); /* Too many arguments. */ |
1152 | #if LJ_TARGET_ARM64 && LJ_TARGET_OSX | ||
1153 | if (ngpr >= 0) { | ||
1154 | ngpr = -1; | ||
1155 | args[n++] = TREF_NIL; /* Marker for start of varargs. */ | ||
1156 | if (n >= CCI_NARGS_MAX) | ||
1157 | lj_trace_err(J, LJ_TRERR_NYICALL); | ||
1158 | } | ||
1159 | #endif | ||
1146 | did = lj_ccall_ctid_vararg(cts, o); /* Infer vararg type. */ | 1160 | did = lj_ccall_ctid_vararg(cts, o); /* Infer vararg type. */ |
1147 | } | 1161 | } |
1148 | d = ctype_raw(cts, did); | 1162 | d = ctype_raw(cts, did); |
@@ -1151,6 +1165,15 @@ static TRef crec_call_args(jit_State *J, RecordFFData *rd, | |||
1151 | lj_trace_err(J, LJ_TRERR_NYICALL); | 1165 | lj_trace_err(J, LJ_TRERR_NYICALL); |
1152 | tr = crec_ct_tv(J, d, 0, *base, o); | 1166 | tr = crec_ct_tv(J, d, 0, *base, o); |
1153 | if (ctype_isinteger_or_bool(d->info)) { | 1167 | if (ctype_isinteger_or_bool(d->info)) { |
1168 | #if LJ_TARGET_ARM64 && LJ_TARGET_OSX | ||
1169 | if (!ngpr) { | ||
1170 | /* Fixed args passed on the stack use their unpromoted size. */ | ||
1171 | if (d->size != lj_ir_type_size[tref_type(tr)]) { | ||
1172 | lj_assertJ(d->size == 1 || d->size==2, "unexpected size %d", d->size); | ||
1173 | tr = emitconv(tr, d->size==1 ? IRT_U8 : IRT_U16, tref_type(tr), 0); | ||
1174 | } | ||
1175 | } else | ||
1176 | #endif | ||
1154 | if (d->size < 4) { | 1177 | if (d->size < 4) { |
1155 | if ((d->info & CTF_UNSIGNED)) | 1178 | if ((d->info & CTF_UNSIGNED)) |
1156 | tr = emitconv(tr, IRT_INT, d->size==1 ? IRT_U8 : IRT_U16, 0); | 1179 | tr = emitconv(tr, IRT_INT, d->size==1 ? IRT_U8 : IRT_U16, 0); |
@@ -1188,6 +1211,10 @@ static TRef crec_call_args(jit_State *J, RecordFFData *rd, | |||
1188 | } | 1211 | } |
1189 | } | 1212 | } |
1190 | #endif | 1213 | #endif |
1214 | #elif LJ_TARGET_ARM64 && LJ_TARGET_OSX | ||
1215 | if (!ctype_isfp(d->info) && ngpr) { | ||
1216 | ngpr--; | ||
1217 | } | ||
1191 | #endif | 1218 | #endif |
1192 | args[n] = tr; | 1219 | args[n] = tr; |
1193 | } | 1220 | } |