From 5dabdb2e70799bdd9973495e0e00946e4495eece Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Thu, 16 May 2013 14:35:00 +0200 Subject: [PATCH] FFI: Fix calling conventions for 32 bit OSX and iOS simulator. OSX uses -freg-struct-return, which returns small structs in regs. Thanks to Adriano Bertucci. --- src/lj_ccall.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/lj_ccall.c b/src/lj_ccall.c index 92c52252..29909891 100644 --- a/src/lj_ccall.c +++ b/src/lj_ccall.c @@ -32,6 +32,26 @@ #else +#if LJ_TARGET_OSX + +#define CCALL_HANDLE_STRUCTRET \ + /* Return structs of size 1, 2, 4 or 8 in registers. */ \ + cc->retref = !(sz == 1 || sz == 2 || sz == 4 || sz == 8); \ + if (cc->retref) { \ + if (ngpr < maxgpr) \ + cc->gpr[ngpr++] = (GPRArg)dp; \ + else \ + cc->stack[nsp++] = (GPRArg)dp; \ + } else { /* Struct with single FP field ends up in FPR. */ \ + cc->resx87 = ccall_classify_struct(cts, ctr); \ + } + +#define CCALL_HANDLE_STRUCTRET2 \ + if (cc->resx87) sp = (uint8_t *)&cc->fpr[0]; \ + memcpy(dp, sp, ctr->size); + +#else + #define CCALL_HANDLE_STRUCTRET \ cc->retref = 1; /* Return all structs by reference (in reg or on stack). */ \ if (ngpr < maxgpr) \ @@ -39,6 +59,8 @@ else \ cc->stack[nsp++] = (GPRArg)dp; +#endif + #define CCALL_HANDLE_COMPLEXRET \ /* Return complex float in GPRs and complex double by reference. */ \ cc->retref = (sz > 8); \ @@ -414,6 +436,42 @@ memcpy(dp, sp, ctr->size); /* Copy struct return value from GPRs. */ #endif +/* -- x86 OSX ABI struct classification ----------------------------------- */ + +#if LJ_TARGET_X86 && LJ_TARGET_OSX + +/* Check for struct with single FP field. */ +static int ccall_classify_struct(CTState *cts, CType *ct) +{ + CTSize sz = ct->size; + if (!(sz == sizeof(float) || sz == sizeof(double))) return 0; + if ((ct->info & CTF_UNION)) return 0; + while (ct->sib) { + ct = ctype_get(cts, ct->sib); + if (ctype_isfield(ct->info)) { + CType *sct = ctype_rawchild(cts, ct); + if (ctype_isfp(sct->info)) { + if (sct->size == sz) + return (sz >> 2); /* Return 1 for float or 2 for double. */ + } else if (ctype_isstruct(sct->info)) { + if (sct->size) + return ccall_classify_struct(cts, sct); + } else { + break; + } + } else if (ctype_isbitfield(ct->info)) { + break; + } else if (ctype_isxattrib(ct->info, CTA_SUBTYPE)) { + CType *sct = ctype_rawchild(cts, ct); + if (sct->size) + return ccall_classify_struct(cts, sct); + } + } + return 0; +} + +#endif + /* -- x64 struct classification ------------------------------------------- */ #if LJ_TARGET_X64 && !LJ_ABI_WIN