static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args)
{
uint32_t n, nargs = CCI_XNARGS(ci);
- int32_t ofs = 0;
+ int32_t spofs = 0, spalign = LJ_HASFFI && LJ_TARGET_OSX ? 0 : 7;
Reg gpr, fpr = REGARG_FIRSTFPR;
if (ci->func)
emit_call(as, ci->func);
fpr++;
} else {
Reg r = ra_alloc1(as, ref, RSET_FPR);
- emit_spstore(as, ir, r, ofs + ((LJ_BE && !irt_isnum(ir->t)) ? 4 : 0));
- ofs += 8;
+ int32_t al = spalign;
+#if LJ_HASFFI && LJ_TARGET_OSX
+ al |= irt_isnum(ir->t) ? 7 : 3;
+#endif
+ spofs = (spofs + al) & ~al;
+ if (LJ_BE && al >= 7 && !irt_isnum(ir->t)) spofs += 4, al -= 4;
+ emit_spstore(as, ir, r, spofs);
+ spofs += al + 1;
}
} else {
if (gpr <= REGARG_LASTGPR) {
gpr++;
} else {
Reg r = ra_alloc1(as, ref, RSET_GPR);
- emit_spstore(as, ir, r, ofs + ((LJ_BE && !irt_is64(ir->t)) ? 4 : 0));
- ofs += 8;
+ int32_t al = spalign;
+#if LJ_HASFFI && LJ_TARGET_OSX
+ al |= irt_size(ir->t) - 1;
+#endif
+ spofs = (spofs + al) & ~al;
+ if (al >= 3) {
+ if (LJ_BE && al >= 7 && !irt_is64(ir->t)) spofs += 4, al -= 4;
+ emit_spstore(as, ir, r, spofs);
+ } else {
+ lj_assertA(al == 0 || al == 1, "size %d unexpected", al + 1);
+ emit_lso(as, al ? A64I_STRH : A64I_STRB, r, RID_SP, spofs);
+ }
+ spofs += al + 1;
}
}
+#if LJ_HASFFI && LJ_TARGET_OSX
+ } else { /* Marker for start of varargs. */
+ gpr = REGARG_LASTGPR+1;
+ fpr = REGARG_LASTFPR+1;
+ spalign = 7;
+#endif
}
}
}
/* Ensure there are enough stack slots for call arguments. */
static Reg asm_setup_call_slots(ASMState *as, IRIns *ir, const CCallInfo *ci)
{
- IRRef args[CCI_NARGS_MAX*2];
+#if LJ_HASFFI
uint32_t i, nargs = CCI_XNARGS(ci);
- int nslots = 0, ngpr = REGARG_NUMGPR, nfpr = REGARG_NUMFPR;
- asm_collectargs(as, ir, ci, args);
- for (i = 0; i < nargs; i++) {
- if (args[i] && irt_isfp(IR(args[i])->t)) {
- if (nfpr > 0) nfpr--; else nslots += 2;
- } else {
- if (ngpr > 0) ngpr--; else nslots += 2;
+ if (nargs > (REGARG_NUMGPR < REGARG_NUMFPR ? REGARG_NUMGPR : REGARG_NUMFPR) ||
+ (LJ_TARGET_OSX && (ci->flags & CCI_VARARG))) {
+ IRRef args[CCI_NARGS_MAX*2];
+ int ngpr = REGARG_NUMGPR, nfpr = REGARG_NUMFPR;
+ int spofs = 0, spalign = LJ_TARGET_OSX ? 0 : 7, nslots;
+ asm_collectargs(as, ir, ci, args);
+ for (i = 0; i < nargs; i++) {
+ int al = spalign;
+ if (!args[i]) {
+#if LJ_TARGET_OSX
+ /* Marker for start of varaargs. */
+ nfpr = 0;
+ ngpr = 0;
+ spalign = 7;
+#endif
+ } else if (irt_isfp(IR(args[i])->t)) {
+ if (nfpr > 0) { nfpr--; continue; }
+#if LJ_TARGET_OSX
+ al |= irt_isnum(IR(args[i])->t) ? 7 : 3;
+#endif
+ } else {
+ if (ngpr > 0) { ngpr--; continue; }
+#if LJ_TARGET_OSX
+ al |= irt_size(IR(args[i])->t) - 1;
+#endif
+ }
+ spofs = (spofs + 2*al+1) & ~al; /* Align and bump stack pointer. */
}
+ nslots = (spofs + 3) >> 2;
+ if (nslots > as->evenspill) /* Leave room for args in stack slots. */
+ as->evenspill = nslots;
}
- if (nslots > as->evenspill) /* Leave room for args in stack slots. */
- as->evenspill = nslots;
+#endif
return REGSP_HINT(RID_RET);
}
goto done; \
} else { \
nfpr = CCALL_NARG_FPR; /* Prevent reordering. */ \
- if (LJ_TARGET_OSX && d->size < 8) goto err_nyi; \
} \
} else { /* Try to pass argument in GPRs. */ \
if (!LJ_TARGET_OSX && (d->info & CTF_ALIGN) > CTALIGN_PTR) \
goto done; \
} else { \
ngpr = maxgpr; /* Prevent reordering. */ \
- if (LJ_TARGET_OSX && d->size < 8) goto err_nyi; \
} \
}
CCALL_HANDLE_STRUCTARG
} else if (ctype_iscomplex(d->info)) {
CCALL_HANDLE_COMPLEXARG
- } else {
+ } else if (!(CCALL_PACK_STACKARG && ctype_isenum(d->info))) {
sz = CTSIZE_PTR;
}
n = (sz + CTSIZE_PTR-1) / CTSIZE_PTR; /* Number of GPRs or stack slots needed. */
/* Otherwise pass argument on stack. */
if (CCALL_ALIGN_STACKARG) { /* Align argument on stack. */
MSize align = (1u << ctype_align(d->info)) - 1;
- if (rp)
+ if (rp || (CCALL_PACK_STACKARG && isva && align < CTSIZE_PTR-1))
align = CTSIZE_PTR-1;
nsp = (nsp + align) & ~align;
}
dp = ((uint8_t *)cc->stack) + nsp;
- nsp += n * CTSIZE_PTR;
+ nsp += CCALL_PACK_STACKARG ? sz : n * CTSIZE_PTR;
if (nsp > CCALL_SIZE_STACK) { /* Too many arguments. */
err_nyi:
lj_err_caller(L, LJ_ERR_FFI_NYICALL);
}
lj_cconv_ct_tv(cts, d, (uint8_t *)dp, o, CCF_ARG(narg));
/* Extend passed integers to 32 bits at least. */
- if (ctype_isinteger_or_bool(d->info) && d->size < 4) {
+ if (ctype_isinteger_or_bool(d->info) && d->size < 4 &&
+ (!CCALL_PACK_STACKARG || !((uintptr_t)dp & 3))) { /* Assumes LJ_LE. */
if (d->info & CTF_UNSIGNED)
*(uint32_t *)dp = d->size == 1 ? (uint32_t)*(uint8_t *)dp :
(uint32_t)*(uint16_t *)dp;
ngpr = 1;
else if (ctype_cconv(ct->info) == CTCC_FASTCALL)
ngpr = 2;
+#elif LJ_TARGET_ARM64
+#if LJ_ABI_WIN
+#error "NYI: ARM64 Windows ABI calling conventions"
+#elif LJ_TARGET_OSX
+ int ngpr = CCALL_NARG_GPR;
+#endif
#endif
/* Skip initial attributes. */
} else {
if (!(ct->info & CTF_VARARG))
lj_trace_err(J, LJ_TRERR_NYICALL); /* Too many arguments. */
+#if LJ_TARGET_ARM64 && LJ_TARGET_OSX
+ if (ngpr >= 0) {
+ ngpr = -1;
+ args[n++] = TREF_NIL; /* Marker for start of varargs. */
+ if (n >= CCI_NARGS_MAX)
+ lj_trace_err(J, LJ_TRERR_NYICALL);
+ }
+#endif
did = lj_ccall_ctid_vararg(cts, o); /* Infer vararg type. */
}
d = ctype_raw(cts, did);
lj_trace_err(J, LJ_TRERR_NYICALL);
tr = crec_ct_tv(J, d, 0, *base, o);
if (ctype_isinteger_or_bool(d->info)) {
+#if LJ_TARGET_ARM64 && LJ_TARGET_OSX
+ if (!ngpr) {
+ /* Fixed args passed on the stack use their unpromoted size. */
+ if (d->size != lj_ir_type_size[tref_type(tr)]) {
+ lj_assertJ(d->size == 1 || d->size==2, "unexpected size %d", d->size);
+ tr = emitconv(tr, d->size==1 ? IRT_U8 : IRT_U16, tref_type(tr), 0);
+ }
+ } else
+#endif
if (d->size < 4) {
if ((d->info & CTF_UNSIGNED))
tr = emitconv(tr, IRT_INT, d->size==1 ? IRT_U8 : IRT_U16, 0);
}
}
#endif
+#elif LJ_TARGET_ARM64 && LJ_TARGET_OSX
+ if (!ctype_isfp(d->info) && ngpr) {
+ ngpr--;
+ }
#endif
args[n] = tr;
}