diff options
Diffstat (limited to 'src/lj_ccall.c')
-rw-r--r-- | src/lj_ccall.c | 116 |
1 files changed, 112 insertions, 4 deletions
diff --git a/src/lj_ccall.c b/src/lj_ccall.c index c3eb25f6..71331f39 100644 --- a/src/lj_ccall.c +++ b/src/lj_ccall.c | |||
@@ -168,6 +168,8 @@ | |||
168 | #elif LJ_TARGET_ARM | 168 | #elif LJ_TARGET_ARM |
169 | /* -- ARM calling conventions --------------------------------------------- */ | 169 | /* -- ARM calling conventions --------------------------------------------- */ |
170 | 170 | ||
171 | #if LJ_ABI_SOFTFP | ||
172 | |||
171 | #define CCALL_HANDLE_STRUCTRET \ | 173 | #define CCALL_HANDLE_STRUCTRET \ |
172 | /* Return structs of size <= 4 in a GPR. */ \ | 174 | /* Return structs of size <= 4 in a GPR. */ \ |
173 | cc->retref = !(sz <= 4); \ | 175 | cc->retref = !(sz <= 4); \ |
@@ -186,13 +188,70 @@ | |||
186 | #define CCALL_HANDLE_COMPLEXARG \ | 188 | #define CCALL_HANDLE_COMPLEXARG \ |
187 | /* Pass complex by value in 2 or 4 GPRs. */ | 189 | /* Pass complex by value in 2 or 4 GPRs. */ |
188 | 190 | ||
189 | /* ARM has a softfp ABI. */ | 191 | #define CCALL_HANDLE_REGARG_FP1 |
192 | #define CCALL_HANDLE_REGARG_FP2 | ||
193 | |||
194 | #else | ||
195 | |||
196 | #define CCALL_HANDLE_STRUCTRET \ | ||
197 | cc->retref = !ccall_classify_struct(cts, ctr, ct); \ | ||
198 | if (cc->retref) cc->gpr[ngpr++] = (GPRArg)dp; | ||
199 | |||
200 | #define CCALL_HANDLE_STRUCTRET2 \ | ||
201 | if (ccall_classify_struct(cts, ctr, ct) > 1) sp = (uint8_t *)&cc->fpr[0]; \ | ||
202 | memcpy(dp, sp, ctr->size); | ||
203 | |||
204 | #define CCALL_HANDLE_COMPLEXRET \ | ||
205 | if (!(ct->info & CTF_VARARG)) cc->retref = 0; /* Return complex in FPRs. */ | ||
206 | |||
207 | #define CCALL_HANDLE_COMPLEXRET2 \ | ||
208 | if (!(ct->info & CTF_VARARG)) memcpy(dp, &cc->fpr[0], ctr->size); | ||
209 | |||
210 | #define CCALL_HANDLE_STRUCTARG \ | ||
211 | isfp = (ccall_classify_struct(cts, d, ct) > 1); | ||
212 | /* Pass all structs by value in registers and/or on the stack. */ | ||
213 | |||
214 | #define CCALL_HANDLE_COMPLEXARG \ | ||
215 | isfp = 1; /* Pass complex by value in FPRs or on stack. */ | ||
216 | |||
217 | #define CCALL_HANDLE_REGARG_FP1 \ | ||
218 | if (isfp && !(ct->info & CTF_VARARG)) { \ | ||
219 | if ((d->info & CTF_ALIGN) > CTALIGN_PTR) { \ | ||
220 | if (nfpr + (n >> 1) <= CCALL_NARG_FPR) { \ | ||
221 | dp = &cc->fpr[nfpr]; \ | ||
222 | nfpr += (n >> 1); \ | ||
223 | goto done; \ | ||
224 | } \ | ||
225 | } else { \ | ||
226 | if (sz > 1 && fprodd != nfpr) fprodd = 0; \ | ||
227 | if (fprodd) { \ | ||
228 | if (2*nfpr+n <= 2*CCALL_NARG_FPR+1) { \ | ||
229 | dp = (void *)&cc->fpr[fprodd-1].f[1]; \ | ||
230 | nfpr += (n >> 1); \ | ||
231 | if ((n & 1)) fprodd = 0; else fprodd = nfpr-1; \ | ||
232 | goto done; \ | ||
233 | } \ | ||
234 | } else { \ | ||
235 | if (2*nfpr+n <= 2*CCALL_NARG_FPR) { \ | ||
236 | dp = (void *)&cc->fpr[nfpr]; \ | ||
237 | nfpr += (n >> 1); \ | ||
238 | if ((n & 1)) fprodd = ++nfpr; else fprodd = 0; \ | ||
239 | goto done; \ | ||
240 | } \ | ||
241 | } \ | ||
242 | } \ | ||
243 | fprodd = 0; /* No reordering after the first FP value is on stack. */ \ | ||
244 | } else { | ||
245 | |||
246 | #define CCALL_HANDLE_REGARG_FP2 } | ||
247 | |||
248 | #endif | ||
249 | |||
190 | #define CCALL_HANDLE_REGARG \ | 250 | #define CCALL_HANDLE_REGARG \ |
251 | CCALL_HANDLE_REGARG_FP1 \ | ||
191 | if ((d->info & CTF_ALIGN) > CTALIGN_PTR) { \ | 252 | if ((d->info & CTF_ALIGN) > CTALIGN_PTR) { \ |
192 | if (ngpr < maxgpr) \ | 253 | if (ngpr < maxgpr) \ |
193 | ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \ | 254 | ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \ |
194 | else \ | ||
195 | nsp = (nsp + 1u) & ~1u; /* Align argument on stack. */ \ | ||
196 | } \ | 255 | } \ |
197 | if (ngpr < maxgpr) { \ | 256 | if (ngpr < maxgpr) { \ |
198 | dp = &cc->gpr[ngpr]; \ | 257 | dp = &cc->gpr[ngpr]; \ |
@@ -204,7 +263,10 @@ | |||
204 | ngpr += n; \ | 263 | ngpr += n; \ |
205 | } \ | 264 | } \ |
206 | goto done; \ | 265 | goto done; \ |
207 | } | 266 | } CCALL_HANDLE_REGARG_FP2 |
267 | |||
268 | #define CCALL_HANDLE_RET \ | ||
269 | if ((ct->info & CTF_VARARG)) sp = (uint8_t *)&cc->gpr[0]; | ||
208 | 270 | ||
209 | #elif LJ_TARGET_PPC | 271 | #elif LJ_TARGET_PPC |
210 | /* -- PPC calling conventions --------------------------------------------- */ | 272 | /* -- PPC calling conventions --------------------------------------------- */ |
@@ -453,6 +515,49 @@ static void ccall_struct_ret(CCallState *cc, int *rcl, uint8_t *dp, CTSize sz) | |||
453 | } | 515 | } |
454 | #endif | 516 | #endif |
455 | 517 | ||
518 | /* -- ARM hard-float ABI struct classification ---------------------------- */ | ||
519 | |||
520 | #if LJ_TARGET_ARM && !LJ_ABI_SOFTFP | ||
521 | |||
522 | /* Classify a struct based on its fields. */ | ||
523 | static unsigned int ccall_classify_struct(CTState *cts, CType *ct, CType *ctf) | ||
524 | { | ||
525 | CTSize sz = ct->size; | ||
526 | unsigned int r = 0, n = 0, isu = (ct->info & CTF_UNION); | ||
527 | if ((ctf->info & CTF_VARARG)) goto noth; | ||
528 | while (ct->sib) { | ||
529 | ct = ctype_get(cts, ct->sib); | ||
530 | if (ctype_isfield(ct->info)) { | ||
531 | CType *sct = ctype_rawchild(cts, ct); | ||
532 | if (ctype_isfp(sct->info)) { | ||
533 | r |= sct->size; | ||
534 | if (!isu) n++; else if (n == 0) n = 1; | ||
535 | } else if (ctype_iscomplex(sct->info)) { | ||
536 | r |= (sct->size >> 1); | ||
537 | if (!isu) n += 2; else if (n < 2) n = 2; | ||
538 | } else { | ||
539 | goto noth; | ||
540 | } | ||
541 | } else if (ctype_isbitfield(ct->info)) { | ||
542 | goto noth; | ||
543 | } else if (ctype_isxattrib(ct->info, CTA_SUBTYPE)) { | ||
544 | CType *sct = ctype_child(cts, ct); | ||
545 | if (sct->size > 0) { | ||
546 | unsigned int s = ccall_classify_struct(cts, sct, ctf); | ||
547 | if (s <= 1) goto noth; | ||
548 | r |= (s & 255); | ||
549 | if (!isu) n += (s >> 8); else if (n < (s >>8)) n = (s >> 8); | ||
550 | } | ||
551 | } | ||
552 | } | ||
553 | if ((r == 4 || r == 8) && n <= 4) | ||
554 | return r + (n << 8); | ||
555 | noth: /* Not a homogeneous float/double aggregate. */ | ||
556 | return (sz <= 4); /* Return structs of size <= 4 in a GPR. */ | ||
557 | } | ||
558 | |||
559 | #endif | ||
560 | |||
456 | /* -- Common C call handling ---------------------------------------------- */ | 561 | /* -- Common C call handling ---------------------------------------------- */ |
457 | 562 | ||
458 | /* Infer the destination CTypeID for a vararg argument. */ | 563 | /* Infer the destination CTypeID for a vararg argument. */ |
@@ -494,6 +599,9 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct, | |||
494 | MSize maxgpr, ngpr = 0, nsp = 0, narg; | 599 | MSize maxgpr, ngpr = 0, nsp = 0, narg; |
495 | #if CCALL_NARG_FPR | 600 | #if CCALL_NARG_FPR |
496 | MSize nfpr = 0; | 601 | MSize nfpr = 0; |
602 | #if LJ_TARGET_ARM | ||
603 | MSize fprodd = 0; | ||
604 | #endif | ||
497 | #endif | 605 | #endif |
498 | 606 | ||
499 | /* Clear unused regs to get some determinism in case of misdeclaration. */ | 607 | /* Clear unused regs to get some determinism in case of misdeclaration. */ |