1d4c9320412177895f598a93d73a0e654db27c351Thomas Heller/* -----------------------------------------------------------------------
2029273fc903bcbdd689132f153d53004a8aee0b2Gregory P. Smith   ffi.c - Copyright (c) 1998, 2007, 2008, 2012 Red Hat, Inc.
3d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	   Copyright (c) 2000 Hewlett Packard Company
4029273fc903bcbdd689132f153d53004a8aee0b2Gregory 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
197864476afa402a0537c33ba9630e77351720baf8Christian Heimes   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
207864476afa402a0537c33ba9630e77351720baf8Christian Heimes   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
217864476afa402a0537c33ba9630e77351720baf8Christian Heimes   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
227864476afa402a0537c33ba9630e77351720baf8Christian Heimes   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
237864476afa402a0537c33ba9630e77351720baf8Christian Heimes   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
247864476afa402a0537c33ba9630e77351720baf8Christian Heimes   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
257864476afa402a0537c33ba9630e77351720baf8Christian Heimes   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
267864476afa402a0537c33ba9630e77351720baf8Christian Heimes   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
747864476afa402a0537c33ba9630e77351720baf8Christian Heimes/* Store VALUE to ADDR in the current cpu implementation's fp spill format.
757864476afa402a0537c33ba9630e77351720baf8Christian Heimes   This is a macro instead of a function, so that it works for all 3 floating
767864476afa402a0537c33ba9630e77351720baf8Christian Heimes   point types without type conversions.  Type conversion to long double breaks
777864476afa402a0537c33ba9630e77351720baf8Christian Heimes   the denorm support.  */
78d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
797864476afa402a0537c33ba9630e77351720baf8Christian Heimes#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
837864476afa402a0537c33ba9630e77351720baf8Christian Heimes   fp spill format.  As above, this must also be a macro.  */
84d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
857864476afa402a0537c33ba9630e77351720baf8Christian Heimes#define ldf_fill(result, addr)	\
867864476afa402a0537c33ba9630e77351720baf8Christian Heimes  asm ("ldf.fill %0 = %1%P1" : "=f"(result) : "m"(*addr));
87d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
88029273fc903bcbdd689132f153d53004a8aee0b2Gregory 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
1107864476afa402a0537c33ba9630e77351720baf8Christian Heimesstatic void
1117864476afa402a0537c33ba9630e77351720baf8Christian Heimeshfa_type_load (fpreg *fpaddr, int type, void *addr)
112d4c9320412177895f598a93d73a0e654db27c351Thomas Heller{
113d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  switch (type)
114d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    {
115d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    case FFI_IA64_TYPE_HFA_FLOAT:
1167864476afa402a0537c33ba9630e77351720baf8Christian Heimes      stf_spill (fpaddr, *(float *) addr);
1177864476afa402a0537c33ba9630e77351720baf8Christian Heimes      return;
118d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    case FFI_IA64_TYPE_HFA_DOUBLE:
1197864476afa402a0537c33ba9630e77351720baf8Christian Heimes      stf_spill (fpaddr, *(double *) addr);
1207864476afa402a0537c33ba9630e77351720baf8Christian Heimes      return;
121d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    case FFI_IA64_TYPE_HFA_LDOUBLE:
1227864476afa402a0537c33ba9630e77351720baf8Christian Heimes      stf_spill (fpaddr, *(__float80 *) addr);
1237864476afa402a0537c33ba9630e77351720baf8Christian Heimes      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
1337864476afa402a0537c33ba9630e77351720baf8Christian Heimeshfa_type_store (int type, void *addr, fpreg *fpaddr)
134d4c9320412177895f598a93d73a0e654db27c351Thomas Heller{
135d4c9320412177895f598a93d73a0e654db27c351Thomas Heller  switch (type)
136d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    {
137d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    case FFI_IA64_TYPE_HFA_FLOAT:
1387864476afa402a0537c33ba9630e77351720baf8Christian Heimes      {
1397864476afa402a0537c33ba9630e77351720baf8Christian Heimes	float result;
1407864476afa402a0537c33ba9630e77351720baf8Christian Heimes	ldf_fill (result, fpaddr);
1417864476afa402a0537c33ba9630e77351720baf8Christian Heimes	*(float *) addr = result;
1427864476afa402a0537c33ba9630e77351720baf8Christian Heimes	break;
1437864476afa402a0537c33ba9630e77351720baf8Christian Heimes      }
144d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    case FFI_IA64_TYPE_HFA_DOUBLE:
1457864476afa402a0537c33ba9630e77351720baf8Christian Heimes      {
1467864476afa402a0537c33ba9630e77351720baf8Christian Heimes	double result;
1477864476afa402a0537c33ba9630e77351720baf8Christian Heimes	ldf_fill (result, fpaddr);
1487864476afa402a0537c33ba9630e77351720baf8Christian Heimes	*(double *) addr = result;
1497864476afa402a0537c33ba9630e77351720baf8Christian Heimes	break;
1507864476afa402a0537c33ba9630e77351720baf8Christian Heimes      }
151d4c9320412177895f598a93d73a0e654db27c351Thomas Heller    case FFI_IA64_TYPE_HFA_LDOUBLE:
1527864476afa402a0537c33ba9630e77351720baf8Christian Heimes      {
1537864476afa402a0537c33ba9630e77351720baf8Christian Heimes	__float80 result;
1547864476afa402a0537c33ba9630e77351720baf8Christian Heimes	ldf_fill (result, fpaddr);
1557864476afa402a0537c33ba9630e77351720baf8Christian Heimes	*(__float80 *) addr = result;
1567864476afa402a0537c33ba9630e77351720baf8Christian Heimes	break;
1577864476afa402a0537c33ba9630e77351720baf8Christian Heimes      }
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:
188029273fc903bcbdd689132f153d53004a8aee0b2Gregory 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
229029273fc903bcbdd689132f153d53004a8aee0b2Gregory 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
2748ce8a784bd672ba42975dec752848392ff9a7797Guido van Rossumextern int ffi_call_unix (struct ia64_args *, PTR64, void (*)(void), UINT64);
275d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
276d4c9320412177895f598a93d73a0e654db27c351Thomas Hellervoid
2778ce8a784bd672ba42975dec752848392ff9a7797Guido van Rossumffi_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]);
328029273fc903bcbdd689132f153d53004a8aee0b2Gregory P. Smith	  {
329029273fc903bcbdd689132f153d53004a8aee0b2Gregory P. Smith	    UINT32 tmp;
330029273fc903bcbdd689132f153d53004a8aee0b2Gregory P. Smith	    memcpy (&tmp, avalue[i], sizeof (UINT32));
331029273fc903bcbdd689132f153d53004a8aee0b2Gregory P. Smith	    stack->gp_regs[gpcount++] = tmp;
332029273fc903bcbdd689132f153d53004a8aee0b2Gregory 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]);
338029273fc903bcbdd689132f153d53004a8aee0b2Gregory 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		  {
3707864476afa402a0537c33ba9630e77351720baf8Christian Heimes		    hfa_type_load (&stack->fp_regs[fpcount], hfa_type,
3717864476afa402a0537c33ba9630e77351720baf8Christian Heimes				   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
404736a9133219ec75524d90a976d2e35c76d544b6edoko@ubuntu.com   both retrieve the user data, and to restore the correct gp pointer.  */
405d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
4067864476afa402a0537c33ba9630e77351720baf8Christian Heimesextern void ffi_closure_unix ();
407d4c9320412177895f598a93d73a0e654db27c351Thomas Heller
408d4c9320412177895f598a93d73a0e654db27c351Thomas Hellerffi_status
4097864476afa402a0537c33ba9630e77351720baf8Christian Heimesffi_prep_closure_loc (ffi_closure* closure,
4107864476afa402a0537c33ba9630e77351720baf8Christian Heimes		      ffi_cif* cif,
4117864476afa402a0537c33ba9630e77351720baf8Christian Heimes		      void (*fun)(ffi_cif*,void*,void**,void*),
4127864476afa402a0537c33ba9630e77351720baf8Christian Heimes		      void *user_data,
4137864476afa402a0537c33ba9630e77351720baf8Christian Heimes		      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
433029273fc903bcbdd689132f153d53004a8aee0b2Gregory P. Smith  if (cif->abi != FFI_UNIX)
434029273fc903bcbdd689132f153d53004a8aee0b2Gregory 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;
4417864476afa402a0537c33ba9630e77351720baf8Christian Heimes  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	    {
4967864476afa402a0537c33ba9630e77351720baf8Christian Heimes	      fpreg *addr = &stack->fp_regs[fpcount++];
4977864476afa402a0537c33ba9630e77351720baf8Christian Heimes	      float result;
498d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	      avalue[i] = addr;
4997864476afa402a0537c33ba9630e77351720baf8Christian Heimes	      ldf_fill (result, addr);
5007864476afa402a0537c33ba9630e77351720baf8Christian Heimes	      *(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	    {
5107864476afa402a0537c33ba9630e77351720baf8Christian Heimes	      fpreg *addr = &stack->fp_regs[fpcount++];
5117864476afa402a0537c33ba9630e77351720baf8Christian Heimes	      double result;
512d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	      avalue[i] = addr;
5137864476afa402a0537c33ba9630e77351720baf8Christian Heimes	      ldf_fill (result, addr);
5147864476afa402a0537c33ba9630e77351720baf8Christian Heimes	      *(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	    {
5267864476afa402a0537c33ba9630e77351720baf8Christian Heimes	      fpreg *addr = &stack->fp_regs[fpcount++];
5277864476afa402a0537c33ba9630e77351720baf8Christian Heimes	      __float80 result;
528d4c9320412177895f598a93d73a0e654db27c351Thomas Heller	      avalue[i] = addr;
5297864476afa402a0537c33ba9630e77351720baf8Christian Heimes	      ldf_fill (result, addr);
5307864476afa402a0537c33ba9630e77351720baf8Christian Heimes	      *(__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		  {
5607864476afa402a0537c33ba9630e77351720baf8Christian Heimes		    hfa_type_store (hfa_type, addr + offset,
5617864476afa402a0537c33ba9630e77351720baf8Christian Heimes				    &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