+#ifdef HAVE_LONG_DOUBLE
+ case PSI_T_LONG_DOUBLE:
+ return &ffi_type_longdouble;
+#endif
+ case PSI_T_POINTER:
+ case PSI_T_FUNCTION:
+ return &ffi_type_pointer;
+ }
+}
+static inline ffi_type *psi_ffi_impl_type(token_t impl_type) {
+ switch (impl_type) {
+ case PSI_T_BOOL:
+ return &ffi_type_sint8;
+ case PSI_T_INT:
+ return &ffi_type_sint64;
+ case PSI_T_STRING:
+ return &ffi_type_pointer;
+ case PSI_T_FLOAT:
+ case PSI_T_DOUBLE:
+ return &ffi_type_double;
+ EMPTY_SWITCH_DEFAULT_CASE();
+ }
+ return NULL;
+}
+static void psi_ffi_struct_type_dtor(void *type) {
+ ffi_type *strct = type;
+
+ if (strct->elements) {
+ ffi_type **ptr;
+
+ for (ptr = strct->elements; *ptr; ++ptr) {
+ free(*ptr);
+ }
+ free(strct->elements);
+ }
+ free(strct);
+}
+
+static size_t psi_ffi_struct_type_pad(ffi_type **els, size_t padding) {
+ size_t i;
+
+ for (i = 0; i < padding; ++i) {
+ ffi_type *pad = malloc(sizeof(*pad));
+
+ memcpy(pad, &ffi_type_schar, sizeof(*pad));
+ *els++ = pad;
+ }
+
+ return padding;
+}
+
+static ffi_type **psi_ffi_struct_type_elements(struct psi_decl_struct *strct) {
+ size_t i = 0, argc, nels = 0, offset = 0, maxalign = 0, last_arg_pos = -1;
+ ffi_type **tmp, **els;
+ struct psi_decl_arg *darg;
+
+ argc = psi_plist_count(strct->args);
+ els = calloc(argc + 1, sizeof(*els));
+
+ while (psi_plist_get(strct->args, i++, &darg)) {
+ ffi_type *type;
+ size_t padding;
+
+ if (darg->layout->pos == last_arg_pos) {
+ /* skip bit fields */
+ continue;
+ }
+ last_arg_pos = darg->layout->pos;
+
+ type = malloc(sizeof(*type));
+ *type = *psi_ffi_decl_arg_type(darg);
+
+ if (type->alignment > maxalign) {
+ maxalign = type->alignment;
+ }
+
+ assert(type->size == darg->layout->len);
+ if ((padding = psi_offset_padding(darg->layout->pos - offset, type->alignment))) {
+ if (nels + padding + 1 > argc) {
+ argc += padding;
+ tmp = realloc(els, (argc + 1) * sizeof(*els));
+ if (tmp) {
+ els = tmp;
+ } else {
+ free(els);
+ return NULL;
+ }
+ els[argc] = NULL;
+ }
+ psi_ffi_struct_type_pad(&els[nels], padding);
+ nels += padding;
+ offset += padding;
+ }
+ assert(offset == darg->layout->pos);
+
+ offset = (offset + darg->layout->len + type->alignment - 1) & ~(type->alignment - 1);
+ els[nels++] = type;