1d4c9320412177895f598a93d73a0e654db27c351Thomas Heller/* -----------------------------------------------------------------------
246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith   ffi.c - Copyright (c) 1998, 2007, 2008, 2012 Red Hat, Inc.
3d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	   Copyright (c) 2000 Hewlett Packard Company
446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith	   Copyright (c) 2011 Anthony Green
5d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
6d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   IA64 Foreign Function Interface
7d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
8d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   Permission is hereby granted, free of charge, to any person obtaining
9d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   a copy of this software and associated documentation files (the
10d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   ``Software''), to deal in the Software without restriction, including
11d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   without limitation the rights to use, copy, modify, merge, publish,
12d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   distribute, sublicense, and/or sell copies of the Software, and to
13d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   permit persons to whom the Software is furnished to do so, subject to
14d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   the following conditions:
15d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
16d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   The above copyright notice and this permission notice shall be included
17d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   in all copies or substantial portions of the Software.
18d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
198bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
208bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
218bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
228bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
238bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
248bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
258bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
268bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller   DEALINGS IN THE SOFTWARE.
27d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   ----------------------------------------------------------------------- */
28d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
29d4c9320412177895f598a93d73a0e654db27c351Thomas Heller#include <ffi.h>
30d4c9320412177895f598a93d73a0e654db27c351Thomas Heller#include <ffi_common.h>
31d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
32d4c9320412177895f598a93d73a0e654db27c351Thomas Heller#include <stdlib.h>
33d4c9320412177895f598a93d73a0e654db27c351Thomas Heller#include <stdbool.h>
34d4c9320412177895f598a93d73a0e654db27c351Thomas Heller#include <float.h>
35d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
36d4c9320412177895f598a93d73a0e654db27c351Thomas Heller#include "ia64_flags.h"
37d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
38d4c9320412177895f598a93d73a0e654db27c351Thomas Heller/* A 64-bit pointer value.  In LP64 mode, this is effectively a plain
39d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   pointer.  In ILP32 mode, it's a pointer that's been extended to
40d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   64 bits by "addp4".  */
41d4c9320412177895f598a93d73a0e654db27c351Thomas Hellertypedef void *PTR64 __attribute__((mode(DI)));
42d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
43d4c9320412177895f598a93d73a0e654db27c351Thomas Heller/* Memory image of fp register contents.  This is the implementation
44d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   specific format used by ldf.fill/stf.spill.  All we care about is
45d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   that it wants a 16 byte aligned slot.  */
46d4c9320412177895f598a93d73a0e654db27c351Thomas Hellertypedef struct
47d4c9320412177895f598a93d73a0e654db27c351Thomas Heller{
48d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  UINT64 x[2] __attribute__((aligned(16)));
49d4c9320412177895f598a93d73a0e654db27c351Thomas Heller} fpreg;
50d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
51d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
52d4c9320412177895f598a93d73a0e654db27c351Thomas Heller/* The stack layout given to ffi_call_unix and ffi_closure_unix_inner.  */
53d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
54d4c9320412177895f598a93d73a0e654db27c351Thomas Hellerstruct ia64_args
55d4c9320412177895f598a93d73a0e654db27c351Thomas Heller{
56d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  fpreg fp_regs[8];	/* Contents of 8 fp arg registers.  */
57d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  UINT64 gp_regs[8];	/* Contents of 8 gp arg registers.  */
58d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  UINT64 other_args[];	/* Arguments passed on stack, variable size.  */
59d4c9320412177895f598a93d73a0e654db27c351Thomas Heller};
60d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
61d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
62d4c9320412177895f598a93d73a0e654db27c351Thomas Heller/* Adjust ADDR, a pointer to an 8 byte slot, to point to the low LEN bytes.  */
63d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
64d4c9320412177895f598a93d73a0e654db27c351Thomas Hellerstatic inline void *
65d4c9320412177895f598a93d73a0e654db27c351Thomas Hellerendian_adjust (void *addr, size_t len)
66d4c9320412177895f598a93d73a0e654db27c351Thomas Heller{
67d4c9320412177895f598a93d73a0e654db27c351Thomas Heller#ifdef __BIG_ENDIAN__
68d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  return addr + (8 - len);
69d4c9320412177895f598a93d73a0e654db27c351Thomas Heller#else
70d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  return addr;
71d4c9320412177895f598a93d73a0e654db27c351Thomas Heller#endif
72d4c9320412177895f598a93d73a0e654db27c351Thomas Heller}
73d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
748bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller/* Store VALUE to ADDR in the current cpu implementation's fp spill format.
758bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller   This is a macro instead of a function, so that it works for all 3 floating
768bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller   point types without type conversions.  Type conversion to long double breaks
778bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller   the denorm support.  */
78d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
798bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller#define stf_spill(addr, value)	\
80d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  asm ("stf.spill %0 = %1%P0" : "=m" (*addr) : "f"(value));
81d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
82d4c9320412177895f598a93d73a0e654db27c351Thomas Heller/* Load a value from ADDR, which is in the current cpu implementation's
838bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller   fp spill format.  As above, this must also be a macro.  */
84d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
858bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller#define ldf_fill(result, addr)	\
868bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller  asm ("ldf.fill %0 = %1%P1" : "=f"(result) : "m"(*addr));
87d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
8846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith/* Return the size of the C type associated with with TYPE.  Which will
89d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   be one of the FFI_IA64_TYPE_HFA_* values.  */
90d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
91d4c9320412177895f598a93d73a0e654db27c351Thomas Hellerstatic size_t
92d4c9320412177895f598a93d73a0e654db27c351Thomas Hellerhfa_type_size (int type)
93d4c9320412177895f598a93d73a0e654db27c351Thomas Heller{
94d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  switch (type)
95d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    {
96d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    case FFI_IA64_TYPE_HFA_FLOAT:
97d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      return sizeof(float);
98d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    case FFI_IA64_TYPE_HFA_DOUBLE:
99d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      return sizeof(double);
100d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    case FFI_IA64_TYPE_HFA_LDOUBLE:
101d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      return sizeof(__float80);
102d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    default:
103d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      abort ();
104d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    }
105d4c9320412177895f598a93d73a0e654db27c351Thomas Heller}
106d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
107d4c9320412177895f598a93d73a0e654db27c351Thomas Heller/* Load from ADDR a value indicated by TYPE.  Which will be one of
108d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   the FFI_IA64_TYPE_HFA_* values.  */
109d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
1108bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Hellerstatic void
1118bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Hellerhfa_type_load (fpreg *fpaddr, int type, void *addr)
112d4c9320412177895f598a93d73a0e654db27c351Thomas Heller{
113d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  switch (type)
114d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    {
115d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    case FFI_IA64_TYPE_HFA_FLOAT:
1168bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller      stf_spill (fpaddr, *(float *) addr);
1178bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller      return;
118d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    case FFI_IA64_TYPE_HFA_DOUBLE:
1198bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller      stf_spill (fpaddr, *(double *) addr);
1208bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller      return;
121d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    case FFI_IA64_TYPE_HFA_LDOUBLE:
1228bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller      stf_spill (fpaddr, *(__float80 *) addr);
1238bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller      return;
124d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    default:
125d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      abort ();
126d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    }
127d4c9320412177895f598a93d73a0e654db27c351Thomas Heller}
128d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
129d4c9320412177895f598a93d73a0e654db27c351Thomas Heller/* Load VALUE into ADDR as indicated by TYPE.  Which will be one of
130d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   the FFI_IA64_TYPE_HFA_* values.  */
131d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
132d4c9320412177895f598a93d73a0e654db27c351Thomas Hellerstatic void
1338bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Hellerhfa_type_store (int type, void *addr, fpreg *fpaddr)
134d4c9320412177895f598a93d73a0e654db27c351Thomas Heller{
135d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  switch (type)
136d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    {
137d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    case FFI_IA64_TYPE_HFA_FLOAT:
1388bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller      {
1398bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller	float result;
1408bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller	ldf_fill (result, fpaddr);
1418bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller	*(float *) addr = result;
1428bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller	break;
1438bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller      }
144d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    case FFI_IA64_TYPE_HFA_DOUBLE:
1458bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller      {
1468bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller	double result;
1478bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller	ldf_fill (result, fpaddr);
1488bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller	*(double *) addr = result;
1498bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller	break;
1508bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller      }
151d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    case FFI_IA64_TYPE_HFA_LDOUBLE:
1528bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller      {
1538bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller	__float80 result;
1548bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller	ldf_fill (result, fpaddr);
1558bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller	*(__float80 *) addr = result;
1568bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller	break;
1578bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller      }
158d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    default:
159d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      abort ();
160d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    }
161d4c9320412177895f598a93d73a0e654db27c351Thomas Heller}
162d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
163d4c9320412177895f598a93d73a0e654db27c351Thomas Heller/* Is TYPE a struct containing floats, doubles, or extended doubles,
164d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   all of the same fp type?  If so, return the element type.  Return
165d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   FFI_TYPE_VOID if not.  */
166d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
167d4c9320412177895f598a93d73a0e654db27c351Thomas Hellerstatic int
168d4c9320412177895f598a93d73a0e654db27c351Thomas Hellerhfa_element_type (ffi_type *type, int nested)
169d4c9320412177895f598a93d73a0e654db27c351Thomas Heller{
170d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  int element = FFI_TYPE_VOID;
171d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
172d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  switch (type->type)
173d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    {
174d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    case FFI_TYPE_FLOAT:
175d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      /* We want to return VOID for raw floating-point types, but the
176d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	 synthetic HFA type if we're nested within an aggregate.  */
177d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      if (nested)
178d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	element = FFI_IA64_TYPE_HFA_FLOAT;
179d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      break;
180d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
181d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    case FFI_TYPE_DOUBLE:
182d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      /* Similarly.  */
183d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      if (nested)
184d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	element = FFI_IA64_TYPE_HFA_DOUBLE;
185d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      break;
186d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
187d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    case FFI_TYPE_LONGDOUBLE:
18846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith      /* Similarly, except that that HFA is true for double extended,
189d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	 but not quad precision.  Both have sizeof == 16, so tell the
190d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	 difference based on the precision.  */
191d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      if (LDBL_MANT_DIG == 64 && nested)
192d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	element = FFI_IA64_TYPE_HFA_LDOUBLE;
193d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      break;
194d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
195d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    case FFI_TYPE_STRUCT:
196d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      {
197d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	ffi_type **ptr = &type->elements[0];
198d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
199d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	for (ptr = &type->elements[0]; *ptr ; ptr++)
200d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  {
201d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    int sub_element = hfa_element_type (*ptr, 1);
202d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    if (sub_element == FFI_TYPE_VOID)
203d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	      return FFI_TYPE_VOID;
204d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
205d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    if (element == FFI_TYPE_VOID)
206d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	      element = sub_element;
207d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    else if (element != sub_element)
208d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	      return FFI_TYPE_VOID;
209d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  }
210d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      }
211d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      break;
212d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
213d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    default:
214d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      return FFI_TYPE_VOID;
215d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    }
216d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
217d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  return element;
218d4c9320412177895f598a93d73a0e654db27c351Thomas Heller}
219d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
220d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
221d4c9320412177895f598a93d73a0e654db27c351Thomas Heller/* Perform machine dependent cif processing. */
222d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
223d4c9320412177895f598a93d73a0e654db27c351Thomas Hellerffi_status
224d4c9320412177895f598a93d73a0e654db27c351Thomas Hellerffi_prep_cif_machdep(ffi_cif *cif)
225d4c9320412177895f598a93d73a0e654db27c351Thomas Heller{
226d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  int flags;
227d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
228d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  /* Adjust cif->bytes to include space for the bits of the ia64_args frame
22946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith     that precedes the integer register portion.  The estimate that the
230d4c9320412177895f598a93d73a0e654db27c351Thomas Heller     generic bits did for the argument space required is good enough for the
231d4c9320412177895f598a93d73a0e654db27c351Thomas Heller     integer component.  */
232d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  cif->bytes += offsetof(struct ia64_args, gp_regs[0]);
233d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  if (cif->bytes < sizeof(struct ia64_args))
234d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    cif->bytes = sizeof(struct ia64_args);
235d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
236d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  /* Set the return type flag. */
237d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  flags = cif->rtype->type;
238d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  switch (cif->rtype->type)
239d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    {
240d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    case FFI_TYPE_LONGDOUBLE:
241d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      /* Leave FFI_TYPE_LONGDOUBLE as meaning double extended precision,
242d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	 and encode quad precision as a two-word integer structure.  */
243d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      if (LDBL_MANT_DIG != 64)
244d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	flags = FFI_IA64_TYPE_SMALL_STRUCT | (16 << 8);
245d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      break;
246d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
247d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    case FFI_TYPE_STRUCT:
248d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      {
249d4c9320412177895f598a93d73a0e654db27c351Thomas Heller        size_t size = cif->rtype->size;
250d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  	int hfa_type = hfa_element_type (cif->rtype, 0);
251d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
252d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	if (hfa_type != FFI_TYPE_VOID)
253d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  {
254d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    size_t nelts = size / hfa_type_size (hfa_type);
255d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    if (nelts <= 8)
256d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	      flags = hfa_type | (size << 8);
257d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  }
258d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	else
259d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  {
260d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    if (size <= 32)
261d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	      flags = FFI_IA64_TYPE_SMALL_STRUCT | (size << 8);
262d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  }
263d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      }
264d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      break;
265d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
266d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    default:
267d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      break;
268d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    }
269d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  cif->flags = flags;
270d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
271d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  return FFI_OK;
272d4c9320412177895f598a93d73a0e654db27c351Thomas Heller}
273d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
274c740d834eee532f15c758c41fba08974cd300f9eNeal Norwitzextern int ffi_call_unix (struct ia64_args *, PTR64, void (*)(void), UINT64);
275d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
276d4c9320412177895f598a93d73a0e654db27c351Thomas Hellervoid
277c740d834eee532f15c758c41fba08974cd300f9eNeal Norwitzffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
278d4c9320412177895f598a93d73a0e654db27c351Thomas Heller{
279d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  struct ia64_args *stack;
280d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  long i, avn, gpcount, fpcount;
281d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  ffi_type **p_arg;
282d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
283d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  FFI_ASSERT (cif->abi == FFI_UNIX);
284d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
285d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  /* If we have no spot for a return value, make one.  */
286d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  if (rvalue == NULL && cif->rtype->type != FFI_TYPE_VOID)
287d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    rvalue = alloca (cif->rtype->size);
288d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
289d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  /* Allocate the stack frame.  */
290d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  stack = alloca (cif->bytes);
291d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
292d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  gpcount = fpcount = 0;
293d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  avn = cif->nargs;
294d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
295d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    {
296d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      switch ((*p_arg)->type)
297d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	{
298d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_SINT8:
299d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  stack->gp_regs[gpcount++] = *(SINT8 *)avalue[i];
300d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  break;
301d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_UINT8:
302d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  stack->gp_regs[gpcount++] = *(UINT8 *)avalue[i];
303d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  break;
304d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_SINT16:
305d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  stack->gp_regs[gpcount++] = *(SINT16 *)avalue[i];
306d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  break;
307d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_UINT16:
308d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  stack->gp_regs[gpcount++] = *(UINT16 *)avalue[i];
309d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  break;
310d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_SINT32:
311d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  stack->gp_regs[gpcount++] = *(SINT32 *)avalue[i];
312d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  break;
313d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_UINT32:
314d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  stack->gp_regs[gpcount++] = *(UINT32 *)avalue[i];
315d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  break;
316d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_SINT64:
317d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_UINT64:
318d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  stack->gp_regs[gpcount++] = *(UINT64 *)avalue[i];
319d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  break;
320d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
321d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_POINTER:
322d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  stack->gp_regs[gpcount++] = (UINT64)(PTR64) *(void **)avalue[i];
323d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  break;
324d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
325d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_FLOAT:
326d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  if (gpcount < 8 && fpcount < 8)
327d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    stf_spill (&stack->fp_regs[fpcount++], *(float *)avalue[i]);
32846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith	  {
32946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith	    UINT32 tmp;
33046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith	    memcpy (&tmp, avalue[i], sizeof (UINT32));
33146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith	    stack->gp_regs[gpcount++] = tmp;
33246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith	  }
333d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  break;
334d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
335d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_DOUBLE:
336d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  if (gpcount < 8 && fpcount < 8)
337d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    stf_spill (&stack->fp_regs[fpcount++], *(double *)avalue[i]);
33846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith	  memcpy (&stack->gp_regs[gpcount++], avalue[i], sizeof (UINT64));
339d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  break;
340d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
341d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_LONGDOUBLE:
342d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  if (gpcount & 1)
343d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    gpcount++;
344d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
345d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    stf_spill (&stack->fp_regs[fpcount++], *(__float80 *)avalue[i]);
346d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  memcpy (&stack->gp_regs[gpcount], avalue[i], 16);
347d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  gpcount += 2;
348d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  break;
349d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
350d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_STRUCT:
351d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  {
352d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    size_t size = (*p_arg)->size;
353d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    size_t align = (*p_arg)->alignment;
354d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    int hfa_type = hfa_element_type (*p_arg, 0);
355d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
356d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    FFI_ASSERT (align <= 16);
357d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    if (align == 16 && (gpcount & 1))
358d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	      gpcount++;
359d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
360d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    if (hfa_type != FFI_TYPE_VOID)
361d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	      {
362d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		size_t hfa_size = hfa_type_size (hfa_type);
363d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		size_t offset = 0;
364d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		size_t gp_offset = gpcount * 8;
365d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
366d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		while (fpcount < 8
367d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		       && offset < size
368d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		       && gp_offset < 8 * 8)
369d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		  {
3708bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller		    hfa_type_load (&stack->fp_regs[fpcount], hfa_type,
3718bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller				   avalue[i] + offset);
372d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		    offset += hfa_size;
373d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		    gp_offset += hfa_size;
374d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		    fpcount += 1;
375d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		  }
376d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	      }
377d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
378d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    memcpy (&stack->gp_regs[gpcount], avalue[i], size);
379d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    gpcount += (size + 7) / 8;
380d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  }
381d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  break;
382d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
383d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	default:
384d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  abort ();
385d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	}
386d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    }
387d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
388d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  ffi_call_unix (stack, rvalue, fn, cif->flags);
389d4c9320412177895f598a93d73a0e654db27c351Thomas Heller}
390d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
391d4c9320412177895f598a93d73a0e654db27c351Thomas Heller/* Closures represent a pair consisting of a function pointer, and
392d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   some user data.  A closure is invoked by reinterpreting the closure
393d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   as a function pointer, and branching to it.  Thus we can make an
394d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   interpreted function callable as a C function: We turn the
395d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   interpreter itself, together with a pointer specifying the
396d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   interpreted procedure, into a closure.
397d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
398d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   For IA64, function pointer are already pairs consisting of a code
399d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   pointer, and a gp pointer.  The latter is needed to access global
400d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   variables.  Here we set up such a pair as the first two words of
401d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   the closure (in the "trampoline" area), but we replace the gp
402d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   pointer with a pointer to the closure itself.  We also add the real
403d4c9320412177895f598a93d73a0e654db27c351Thomas Heller   gp pointer to the closure.  This allows the function entry code to
404baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   both retrieve the user data, and to restore the correct gp pointer.  */
405d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
4068bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Hellerextern void ffi_closure_unix ();
407d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
408d4c9320412177895f598a93d73a0e654db27c351Thomas Hellerffi_status
4098bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Hellerffi_prep_closure_loc (ffi_closure* closure,
4108bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller		      ffi_cif* cif,
4118bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller		      void (*fun)(ffi_cif*,void*,void**,void*),
4128bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller		      void *user_data,
4138bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller		      void *codeloc)
414d4c9320412177895f598a93d73a0e654db27c351Thomas Heller{
415d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  /* The layout of a function descriptor.  A C function pointer really
416d4c9320412177895f598a93d73a0e654db27c351Thomas Heller     points to one of these.  */
417d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  struct ia64_fd
418d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  {
419d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    UINT64 code_pointer;
420d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    UINT64 gp;
421d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  };
422d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
423d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  struct ffi_ia64_trampoline_struct
424d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  {
425d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    UINT64 code_pointer;	/* Pointer to ffi_closure_unix.  */
426d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    UINT64 fake_gp;		/* Pointer to closure, installed as gp.  */
427d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    UINT64 real_gp;		/* Real gp value.  */
428d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  };
429d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
430d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  struct ffi_ia64_trampoline_struct *tramp;
431d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  struct ia64_fd *fd;
432d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
43346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith  if (cif->abi != FFI_UNIX)
43446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith    return FFI_BAD_ABI;
435d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
436d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  tramp = (struct ffi_ia64_trampoline_struct *)closure->tramp;
437d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  fd = (struct ia64_fd *)(void *)ffi_closure_unix;
438d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
439d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  tramp->code_pointer = fd->code_pointer;
440d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  tramp->real_gp = fd->gp;
4418bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller  tramp->fake_gp = (UINT64)(PTR64)codeloc;
442d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  closure->cif = cif;
443d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  closure->user_data = user_data;
444d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  closure->fun = fun;
445d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
446d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  return FFI_OK;
447d4c9320412177895f598a93d73a0e654db27c351Thomas Heller}
448d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
449d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
450d4c9320412177895f598a93d73a0e654db27c351Thomas HellerUINT64
451d4c9320412177895f598a93d73a0e654db27c351Thomas Hellerffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
452d4c9320412177895f598a93d73a0e654db27c351Thomas Heller			void *rvalue, void *r8)
453d4c9320412177895f598a93d73a0e654db27c351Thomas Heller{
454d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  ffi_cif *cif;
455d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  void **avalue;
456d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  ffi_type **p_arg;
457d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  long i, avn, gpcount, fpcount;
458d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
459d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  cif = closure->cif;
460d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  avn = cif->nargs;
461d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  avalue = alloca (avn * sizeof (void *));
462d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
463d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  /* If the structure return value is passed in memory get that location
464d4c9320412177895f598a93d73a0e654db27c351Thomas Heller     from r8 so as to pass the value directly back to the caller.  */
465d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  if (cif->flags == FFI_TYPE_STRUCT)
466d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    rvalue = r8;
467d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
468d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  gpcount = fpcount = 0;
469d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
470d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    {
471d4c9320412177895f598a93d73a0e654db27c351Thomas Heller      switch ((*p_arg)->type)
472d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	{
473d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_SINT8:
474d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_UINT8:
475d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 1);
476d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  break;
477d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_SINT16:
478d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_UINT16:
479d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 2);
480d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  break;
481d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_SINT32:
482d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_UINT32:
483d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 4);
484d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  break;
485d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_SINT64:
486d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_UINT64:
487d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  avalue[i] = &stack->gp_regs[gpcount++];
488d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  break;
489d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_POINTER:
490d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], sizeof(void*));
491d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  break;
492d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
493d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_FLOAT:
494d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  if (gpcount < 8 && fpcount < 8)
495d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    {
4968bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller	      fpreg *addr = &stack->fp_regs[fpcount++];
4978bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller	      float result;
498d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	      avalue[i] = addr;
4998bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller	      ldf_fill (result, addr);
5008bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller	      *(float *)addr = result;
501d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    }
502d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  else
503d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    avalue[i] = endian_adjust(&stack->gp_regs[gpcount], 4);
504d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  gpcount++;
505d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  break;
506d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
507d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_DOUBLE:
508d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  if (gpcount < 8 && fpcount < 8)
509d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    {
5108bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller	      fpreg *addr = &stack->fp_regs[fpcount++];
5118bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller	      double result;
512d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	      avalue[i] = addr;
5138bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller	      ldf_fill (result, addr);
5148bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller	      *(double *)addr = result;
515d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    }
516d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  else
517d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    avalue[i] = &stack->gp_regs[gpcount];
518d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  gpcount++;
519d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  break;
520d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
521d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_LONGDOUBLE:
522d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  if (gpcount & 1)
523d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    gpcount++;
524d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
525d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    {
5268bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller	      fpreg *addr = &stack->fp_regs[fpcount++];
5278bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller	      __float80 result;
528d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	      avalue[i] = addr;
5298bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller	      ldf_fill (result, addr);
5308bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller	      *(__float80 *)addr = result;
531d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    }
532d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  else
533d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    avalue[i] = &stack->gp_regs[gpcount];
534d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  gpcount += 2;
535d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  break;
536d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
537d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	case FFI_TYPE_STRUCT:
538d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  {
539d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    size_t size = (*p_arg)->size;
540d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    size_t align = (*p_arg)->alignment;
541d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    int hfa_type = hfa_element_type (*p_arg, 0);
542d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
543d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    FFI_ASSERT (align <= 16);
544d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    if (align == 16 && (gpcount & 1))
545d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	      gpcount++;
546d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
547d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    if (hfa_type != FFI_TYPE_VOID)
548d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	      {
549d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		size_t hfa_size = hfa_type_size (hfa_type);
550d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		size_t offset = 0;
551d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		size_t gp_offset = gpcount * 8;
552d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		void *addr = alloca (size);
553d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
554d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		avalue[i] = addr;
555d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
556d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		while (fpcount < 8
557d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		       && offset < size
558d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		       && gp_offset < 8 * 8)
559d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		  {
5608bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller		    hfa_type_store (hfa_type, addr + offset,
5618bdf81d2df388ce06088193f95c992a7ee1eb553Thomas Heller				    &stack->fp_regs[fpcount]);
562d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		    offset += hfa_size;
563d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		    gp_offset += hfa_size;
564d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		    fpcount += 1;
565d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		  }
566d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
567d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		if (offset < size)
568d4c9320412177895f598a93d73a0e654db27c351Thomas Heller		  memcpy (addr + offset, (char *)stack->gp_regs + gp_offset,
569d4c9320412177895f598a93d73a0e654db27c351Thomas Heller			  size - offset);
570d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	      }
571d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    else
572d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	      avalue[i] = &stack->gp_regs[gpcount];
573d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
574d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	    gpcount += (size + 7) / 8;
575d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  }
576d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  break;
577d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
578d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	default:
579d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	  abort ();
580d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	}
581d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    }
582d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
583d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  closure->fun (cif, rvalue, avalue, closure->user_data);
584d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
585d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  return cif->flags;
586d4c9320412177895f598a93d73a0e654db27c351Thomas Heller}
587