summaryrefslogtreecommitdiff
path: root/src/lj_ccall.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lj_ccall.c')
-rw-r--r--src/lj_ccall.c116
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. */
523static 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);
555noth: /* 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. */