static void copy_hfa_to_reg_or_stack (void *memory, ffi_type *ty, struct call_context *context, unsigned char *stack, struct arg_state *state) { unsigned elems = element_count (ty); if (available_v (state) < elems) { /* There are insufficient V registers. Further V register allocations are prevented, the NSAA is adjusted (by allocate_to_stack ()) and the argument is copied to memory at the adjusted NSAA. */ state->nsrn = N_V_ARG_REG; memcpy (allocate_to_stack (state, stack, ty->alignment, ty->size), memory, ty->size); } else { int i; unsigned short type = get_homogeneous_type (ty); for (i = 0; i < elems; i++) { void *reg = allocate_to_v (context, state); copy_basic_type (reg, memory, type); memory += get_basic_type_size (type); } } }
static int is_hfa (ffi_type *ty) { if (ty->type == FFI_TYPE_STRUCT && ty->elements[0] && is_floating_type (get_homogeneous_type (ty))) { unsigned n = element_count (ty); return n >= 1 && n <= 4; } return 0; }
static unsigned element_count (ffi_type *ty) { if (ty->type == FFI_TYPE_STRUCT && ty->elements) { unsigned n; unsigned elems = 0; for (n = 0; ty->elements[n]; n++) { if (ty->elements[n]->type == FFI_TYPE_STRUCT && ty->elements[n]->elements) elems += element_count (ty->elements[n]); else elems++; } return elems; } return 0; }
void FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *closure, struct call_context *context, void *stack) { ffi_cif *cif = closure->cif; void **avalue = (void**) alloca (cif->nargs * sizeof (void*)); void *rvalue = NULL; int i; struct arg_state state; arg_init (&state, ALIGN(cif->bytes, 16)); for (i = 0; i < cif->nargs; i++) { ffi_type *ty = cif->arg_types[i]; switch (ty->type) { case FFI_TYPE_VOID: FFI_ASSERT (0); break; case FFI_TYPE_UINT8: case FFI_TYPE_SINT8: case FFI_TYPE_UINT16: case FFI_TYPE_SINT16: case FFI_TYPE_UINT32: case FFI_TYPE_SINT32: case FFI_TYPE_INT: case FFI_TYPE_POINTER: case FFI_TYPE_UINT64: case FFI_TYPE_SINT64: case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: #if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE case FFI_TYPE_LONGDOUBLE: avalue[i] = allocate_to_register_or_stack (context, stack, &state, ty->type); break; #endif case FFI_TYPE_STRUCT: if (is_hfa (ty)) { unsigned n = element_count (ty); if (available_v (&state) < n) { state.nsrn = N_V_ARG_REG; avalue[i] = allocate_to_stack (&state, stack, ty->alignment, ty->size); } else { switch (get_homogeneous_type (ty)) { case FFI_TYPE_FLOAT: { /* Eeek! We need a pointer to the structure, however the homogeneous float elements are being passed in individual S registers, therefore the structure is not represented as a contiguous sequence of bytes in our saved register context. We need to fake up a copy of the structure laid out in memory correctly. The fake can be tossed once the closure function has returned hence alloca() is sufficient. */ int j; UINT32 *p = avalue[i] = alloca (ty->size); for (j = 0; j < element_count (ty); j++) memcpy (&p[j], allocate_to_s (context, &state), sizeof (*p)); break; } case FFI_TYPE_DOUBLE: { /* Eeek! We need a pointer to the structure, however the homogeneous float elements are being passed in individual S registers, therefore the structure is not represented as a contiguous sequence of bytes in our saved register context. We need to fake up a copy of the structure laid out in memory correctly. The fake can be tossed once the closure function has returned hence alloca() is sufficient. */ int j; UINT64 *p = avalue[i] = alloca (ty->size); for (j = 0; j < element_count (ty); j++) memcpy (&p[j], allocate_to_d (context, &state), sizeof (*p)); break; } #if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE case FFI_TYPE_LONGDOUBLE: memcpy (&avalue[i], allocate_to_v (context, &state), sizeof (*avalue)); break; #endif default: FFI_ASSERT (0); break; } } } else if (ty->size > 16) { /* Replace Composite type of size greater than 16 with a pointer. */ memcpy (&avalue[i], allocate_to_register_or_stack (context, stack, &state, FFI_TYPE_POINTER), sizeof (avalue[i])); } else if (available_x (&state) >= (ty->size + 7) / 8) { avalue[i] = get_x_addr (context, state.ngrn); state.ngrn += (ty->size + 7) / 8; } else { state.ngrn = N_X_ARG_REG; avalue[i] = allocate_to_stack (&state, stack, ty->alignment, ty->size); } break; default: FFI_ASSERT (0); break; } } /* Figure out where the return value will be passed, either in registers or in a memory block allocated by the caller and passed in x8. */ if (is_register_candidate (cif->rtype)) { /* Register candidates are *always* returned in registers. */ /* Allocate a scratchpad for the return value, we will let the callee scrible the result into the scratch pad then move the contents into the appropriate return value location for the call convention. */ rvalue = alloca (cif->rtype->size); (closure->fun) (cif, rvalue, avalue, closure->user_data); /* Copy the return value into the call context so that it is returned as expected to our caller. */ switch (cif->rtype->type) { case FFI_TYPE_VOID: break; case FFI_TYPE_UINT8: case FFI_TYPE_UINT16: case FFI_TYPE_UINT32: case FFI_TYPE_POINTER: case FFI_TYPE_UINT64: case FFI_TYPE_SINT8: case FFI_TYPE_SINT16: case FFI_TYPE_INT: case FFI_TYPE_SINT32: case FFI_TYPE_SINT64: case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: #if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE case FFI_TYPE_LONGDOUBLE: #endif { void *addr = get_basic_type_addr (cif->rtype->type, context, 0); copy_basic_type (addr, rvalue, cif->rtype->type); break; } case FFI_TYPE_STRUCT: if (is_hfa (cif->rtype)) { int j; unsigned short type = get_homogeneous_type (cif->rtype); unsigned elems = element_count (cif->rtype); for (j = 0; j < elems; j++) { void *reg = get_basic_type_addr (type, context, j); copy_basic_type (reg, rvalue, type); rvalue += get_basic_type_size (type); } } else if ((cif->rtype->size + 7) / 8 < N_X_ARG_REG) { size_t size = ALIGN (cif->rtype->size, sizeof (UINT64)) ; memcpy (get_x_addr (context, 0), rvalue, size); } else { FFI_ASSERT (0); } break; default: FFI_ASSERT (0); break; } } else { memcpy (&rvalue, get_x_addr (context, 8), sizeof (UINT64)); (closure->fun) (cif, rvalue, avalue, closure->user_data); } }
/* Call a function with the provided arguments and capture the return value. */ void ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) { extended_cif ecif; ecif.cif = cif; ecif.avalue = avalue; ecif.rvalue = rvalue; switch (cif->abi) { case FFI_SYSV: { struct call_context context; size_t stack_bytes; /* Figure out the total amount of stack space we need, the above call frame space needs to be 16 bytes aligned to ensure correct alignment of the first object inserted in that space hence the ALIGN applied to cif->bytes.*/ stack_bytes = ALIGN(cif->bytes, 16); memset (&context, 0, sizeof (context)); if (is_register_candidate (cif->rtype)) { ffi_call_SYSV (aarch64_prep_args, &context, &ecif, stack_bytes, fn); switch (cif->rtype->type) { case FFI_TYPE_VOID: case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: #if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE case FFI_TYPE_LONGDOUBLE: #endif case FFI_TYPE_UINT8: case FFI_TYPE_SINT8: case FFI_TYPE_UINT16: case FFI_TYPE_SINT16: case FFI_TYPE_UINT32: case FFI_TYPE_SINT32: case FFI_TYPE_POINTER: case FFI_TYPE_UINT64: case FFI_TYPE_INT: case FFI_TYPE_SINT64: { void *addr = get_basic_type_addr (cif->rtype->type, &context, 0); copy_basic_type (rvalue, addr, cif->rtype->type); break; } case FFI_TYPE_STRUCT: if (is_hfa (cif->rtype)) { int j; unsigned short type = get_homogeneous_type (cif->rtype); unsigned elems = element_count (cif->rtype); for (j = 0; j < elems; j++) { void *reg = get_basic_type_addr (type, &context, j); copy_basic_type (rvalue, reg, type); rvalue += get_basic_type_size (type); } } else if ((cif->rtype->size + 7) / 8 < N_X_ARG_REG) { size_t size = ALIGN (cif->rtype->size, sizeof (UINT64)); memcpy (rvalue, get_x_addr (&context, 0), size); } else { FFI_ASSERT (0); } break; default: FFI_ASSERT (0); break; } } else { memcpy (get_x_addr (&context, 8), &rvalue, sizeof (UINT64)); ffi_call_SYSV (aarch64_prep_args, &context, &ecif, stack_bytes, fn); } break; } default: FFI_ASSERT (0); break; } }
int get_face_count(FILE *fp) { return element_count(fp, 'f'); }
int get_vertex_count(FILE *fp) { return element_count(fp, 'v'); }