]> git.ipfire.org Git - thirdparty/LuaJIT.git/commitdiff
FFI: Various ABI and calling convention fixes.
authorMike Pall <mike>
Sun, 24 May 2026 23:15:29 +0000 (01:15 +0200)
committerMike Pall <mike>
Sun, 24 May 2026 23:15:29 +0000 (01:15 +0200)
Thanks to Sergey Kaplun. #1455

src/lj_ccall.c
src/lj_cparse.c
src/lj_ctype.h

index f5379e9603a37e2f7c4f402e59e7372334a200ea..2446ed13253203017297ad7c589e955de52d3b07 100644 (file)
     if (ccall_struct_arg(cc, cts, d, rcl, o, narg)) goto err_nyi; \
     nsp = cc->nsp; ngpr = cc->ngpr; nfpr = cc->nfpr; \
     continue; \
-  }  /* Pass all other structs by value on stack. */
+  } else {  /* Pass all other structs by value on stack. */ \
+    onstack = 1; \
+  }
 
 #define CCALL_HANDLE_COMPLEXARG \
   isfp = 2;  /* Pass complex in FPRs or on stack. Needs postprocessing. */
     } \
   } else {  /* Try to pass argument in GPRs. */ \
     /* Note that reordering is explicitly allowed in the x64 ABI. */ \
-    if (n <= 2 && ngpr + n <= maxgpr) { \
+    if (!onstack && n <= 2 && ngpr + n <= maxgpr) { \
       dp = &cc->gpr[ngpr]; \
       ngpr += n; \
       goto done; \
       nfpr = CCALL_NARG_FPR;  /* Prevent reordering. */ \
     } \
   } else {  /* Try to pass argument in GPRs. */ \
-    if (!LJ_TARGET_OSX && (d->info & CTF_ALIGN) > CTALIGN_PTR) \
+    if (!LJ_TARGET_OSX && !rp && ccall_struct_align(cts, d) > CTALIGN_PTR) \
       ngpr = (ngpr + 1u) & ~1u;  /* Align to regpair. */ \
     if (ngpr + n <= maxgpr) { \
       dp = &cc->gpr[ngpr]; \
@@ -661,7 +663,7 @@ static int ccall_classify_struct(CTState *cts, CType *ct, int *rcl, CTSize ofs)
     fofs = ofs+ct->size;
     if (ctype_isfield(ct->info))
       ccall_classify_ct(cts, ctype_rawchild(cts, ct), rcl, fofs);
-    else if (ctype_isbitfield(ct->info))
+    else if (ctype_isbitfield(ct->info) && ctype_bitbsz(ct->info))
       rcl[(fofs >= 8)] |= CCALL_RCL_INT;  /* NYI: unaligned bitfields? */
     else if (ctype_isxattrib(ct->info, CTA_SUBTYPE))
       ccall_classify_struct(cts, ctype_rawchild(cts, ct), rcl, fofs);
@@ -700,8 +702,11 @@ static int ccall_struct_arg(CCallState *cc, CTState *cts, CType *d, int *rcl,
   if (ccall_struct_reg(cc, cts, dp, rcl)) {
     /* Register overflow? Pass on stack. */
     MSize nsp = cc->nsp, sz = rcl[1] ? 2*CTSIZE_PTR : CTSIZE_PTR;
+    MSize align = (1u << ctype_align(d->info)) - 1;
     if (nsp + sz > CCALL_SIZE_STACK)
       return 1;  /* Too many arguments. */
+    if (CCALL_ALIGN_STACKARG && align > CTSIZE_PTR-1)
+      nsp = (nsp + align) & ~align;  /* Align argument on stack. */
     cc->nsp = nsp + sz;
     memcpy((uint8_t *)cc->stack + nsp, dp, sz);
   }
@@ -776,6 +781,31 @@ noth:  /* Not a homogeneous float/double aggregate. */
 
 #if LJ_TARGET_ARM64
 
+#if !LJ_TARGET_OSX
+/* Alignment of pass-by-value structs: 8 or 16. */
+static CTInfo ccall_struct_align_arm64(CTState *cts, CType *ct)
+{
+  CTSize sz;
+  if (ct->sib) {
+    while (ct->sib) {
+      ct = ctype_get(cts, ct->sib);
+      if (ctype_isfield(ct->info)) {
+       if ((ct->info & CTF_ALIGN) > CTALIGN_PTR) return CTALIGN(4);
+      } else if (ctype_isxattrib(ct->info, CTA_SUBTYPE)) {
+       CType *sct = ctype_rawchild(cts, ct);
+       CTInfo info = lj_ctype_info(cts, ctype_typeid(cts, sct), &sz);
+       if ((info & CTF_ALIGN) > CTALIGN_PTR) return CTALIGN(4);
+      }
+    }
+  } else  {
+    CTInfo info = lj_ctype_info(cts, ctype_typeid(cts, ct), &sz);
+    if ((info & CTF_ALIGN) > CTALIGN_PTR) return CTALIGN(4);
+  }
+  return CTALIGN_PTR;
+}
+#define ccall_struct_align(cts, ct)    ccall_struct_align_arm64((cts), (ct))
+#endif
+
 /* Classify a struct based on its fields. */
 static unsigned int ccall_classify_struct(CTState *cts, CType *ct)
 {
@@ -787,10 +817,10 @@ static unsigned int ccall_classify_struct(CTState *cts, CType *ct)
     ct = ctype_get(cts, ct->sib);
     if (ctype_isfield(ct->info)) {
       sct = ctype_rawchild(cts, ct);
-      if (ctype_isarray(sct->info)) {
+      if (ctype_isarray(sct->info) && !sct->size) goto noth;
+      while (ctype_isarray(sct->info)) {
        CType *cct = ctype_rawchild(cts, sct);
-       if (!cct->size) continue;
-       m = sct->size / cct->size;
+       m *= sct->size / cct->size;
        sct = cct;
       }
       if (ctype_isfp(sct->info)) {
@@ -804,7 +834,7 @@ static unsigned int ccall_classify_struct(CTState *cts, CType *ct)
       } else {
        goto noth;
       }
-    } else if (ctype_isbitfield(ct->info)) {
+    } else if (ctype_isbitfield(ct->info) && ctype_bitbsz(ct->info)) {
       goto noth;
     } else if (ctype_isxattrib(ct->info, CTA_SUBTYPE)) {
       sct = ctype_rawchild(cts, ct);
@@ -899,6 +929,11 @@ static void ccall_copy_struct(CCallState *cc, CType *ctr, void *dp, void *sp,
 
 #endif
 
+#ifndef ccall_struct_align
+/* Alignment of pass-by-value structs. */
+#define ccall_struct_align(cts, ct)    ((ct)->info & CTF_ALIGN)
+#endif
+
 /* -- Common C call handling ---------------------------------------------- */
 
 /* Infer the destination CTypeID for a vararg argument.
@@ -1013,6 +1048,9 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct,
     CTSize sz;
     MSize n, isfp = 0, isva = 0;
     void *dp, *rp = NULL;
+#if LJ_TARGET_X64 && !LJ_ABI_WIN
+    int onstack = 0;
+#endif
 
     if (fid) {  /* Get argument type from field. */
       CType *ctf = ctype_get(cts, fid);
@@ -1051,7 +1089,10 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct,
 
     /* Otherwise pass argument on stack. */
     if (CCALL_ALIGN_STACKARG) {  /* Align argument on stack. */
-      MSize align = (1u << ctype_align(d->info)) - 1;
+      MSize align = (1u << ctype_align(ccall_struct_align(cts, d))) - 1;
+#if LJ_TARGET_ARM64 && LJ_TARGET_OSX
+      isva = 1;
+#endif
       if (rp || (CCALL_PACK_STACKARG && isva && align < CTSIZE_PTR-1))
        align = CTSIZE_PTR-1;
       nsp = (nsp + align) & ~align;
index a1361a128ae67ba7836af1d6bbe6d1ba10f1ad22..56e3e8491f05c6a6d800a6709388f1444cb3a912 100644 (file)
@@ -1309,14 +1309,16 @@ static void cp_struct_layout(CPState *cp, CTypeID sid, CTInfo sattr)
        align = ctype_align(attr);
       if (cp->packstack[cp->curpack] < align)
        align = cp->packstack[cp->curpack];
-      if (align > maxalign) maxalign = align;
+      bsz = ctype_bitcsz(ct->info);  /* Bitfield size (temp.). */
+      if (align > maxalign && bsz) maxalign = align;
       amask = (8u << align) - 1;
 
-      bsz = ctype_bitcsz(ct->info);  /* Bitfield size (temp.). */
       if (bsz == CTBSZ_FIELD || !ctype_isfield(ct->info)) {
        bsz = csz;  /* Regular fields or subtypes always fill the container. */
        bofs = (bofs + amask) & ~amask;  /* Start new aligned field. */
        ct->size = (bofs >> 3);  /* Store field offset. */
+       if (ctype_isfield(ct->info))
+         ct->info = CTINFO(CT_FIELD, ctype_cid(ct->info)) + CTALIGN(align);
       } else {  /* Bitfield. */
        if (bsz == 0 || (attr & CTFP_ALIGNED) ||
            (!((attr|sattr) & CTFP_PACKED) && (bofs & amask) + bsz > csz))
@@ -1324,7 +1326,8 @@ static void cp_struct_layout(CPState *cp, CTypeID sid, CTInfo sattr)
 
        /* Prefer regular field over bitfield. */
        if (bsz == csz && (bofs & amask) == 0) {
-         ct->info = CTINFO(CT_FIELD, ctype_cid(ct->info));
+         ct->info = CTINFO(CT_FIELD, ctype_cid(ct->info)) +
+                    CTALIGN(lj_fls(sz));
          ct->size = (bofs >> 3);  /* Store field offset. */
        } else {
          if (csz > amask+1 && bsz <= amask+1)
index 912fe2152bd3561dd6c65823c19545f2dd58aa46..43d507b14cab58de29cbb2fc9d24553d03af3a16 100644 (file)
@@ -51,7 +51,7 @@ LJ_STATIC_ASSERT(((int)CT_STRUCT & (int)CT_ARRAY) == CT_STRUCT);
 ** |FUNC      ....VS.. cc   cid | nargs  | field | name? | name? |
 ** |TYPEDEF                 cid |        |       | name  | name  |
 ** |ATTRIB        attrnum   cid | attr   | sib?  | type? |       |
-** |FIELD                   cid | offset | field |       | name? |
+** |FIELD               A   cid | offset | field |       | name? |
 ** |BITFIELD  B.cvU csz bsz pos | offset | field |       | name? |
 ** |CONSTVAL    c           cid | value  | const | name  | name  |
 ** |EXTERN                  cid |        | sib?  | name  | name  |