/* Classify a C type. */ static void ccall_classify_ct(CTState *cts, CType *ct, int *rcl, CTSize ofs) { if (ctype_isarray(ct->info)) { CType *cct = ctype_rawchild(cts, ct); CTSize eofs, esz = cct->size, asz = ct->size; for (eofs = 0; eofs < asz; eofs += esz) ccall_classify_ct(cts, cct, rcl, ofs+eofs); } else if (ctype_isstruct(ct->info)) { ccall_classify_struct(cts, ct, rcl, ofs); } else { int cl = ctype_isfp(ct->info) ? CCALL_RCL_SSE : CCALL_RCL_INT; lua_assert(ctype_hassize(ct->info)); if ((ofs & (ct->size-1))) cl = CCALL_RCL_MEM; /* Unaligned. */ rcl[(ofs >= 8)] |= cl; } }
/* Classify a struct based on its fields. */ static unsigned int ccall_classify_struct(CTState *cts, CType *ct, CType *ctf) { CTSize sz = ct->size; unsigned int r = 0, n = 0, isu = (ct->info & CTF_UNION); if ((ctf->info & CTF_VARARG)) goto noth; 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)) { r |= sct->size; if (!isu) n++; else if (n == 0) n = 1; } else if (ctype_iscomplex(sct->info)) { r |= (sct->size >> 1); if (!isu) n += 2; else if (n < 2) n = 2; } else { goto noth;
/* 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)) {
/* Infer the destination CTypeID for a vararg argument. */ static CTypeID ccall_ctid_vararg(CTState *cts, cTValue *o) { if (tvisnumber(o)) { return CTID_DOUBLE; } else if (tviscdata(o)) { CTypeID id = cdataV(o)->typeid; CType *s = ctype_get(cts, id); if (ctype_isrefarray(s->info)) { return lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|ctype_cid(s->info)), CTSIZE_PTR); } else if (ctype_isstruct(s->info) || ctype_isfunc(s->info)) { /* NYI: how to pass a struct by value in a vararg argument? */ return lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|id), CTSIZE_PTR); } if (ctype_isfp(s->info) && s->size == sizeof(float)) { return CTID_DOUBLE; } else { return id; } } else if (tvisstr(o)) {