aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMike Pall <mike>2023-08-29 02:21:51 +0200
committerMike Pall <mike>2023-08-29 02:21:51 +0200
commit83954100dba9fc0cf5eeaf122f007df35ec9a604 (patch)
tree49b738b500e50dbd96f9959c4cb50492bbc69114 /src
parentcf903edb30e0cbd620ebd4bac02d4e2b4410fd02 (diff)
downloadluajit-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.h75
-rw-r--r--src/lj_ccall.c11
-rw-r--r--src/lj_ccall.h6
-rw-r--r--src/lj_crecord.c27
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)
419static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args) 419static 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. */
1977static Reg asm_setup_call_slots(ASMState *as, IRIns *ir, const CCallInfo *ci) 2000static 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
79typedef intptr_t GPRArg; 82typedef intptr_t GPRArg;
80typedef union FPRArg { 83typedef 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 }