1457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/* -----------------------------------------------------------------------
2457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   ffi.c - Copyright (c) 1998, 2007, 2008, 2012 Red Hat, Inc.
3457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	   Copyright (c) 2000 Hewlett Packard Company
4457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	   Copyright (c) 2011 Anthony Green
5457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
6457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   IA64 Foreign Function Interface
7457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
8457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   Permission is hereby granted, free of charge, to any person obtaining
9457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   a copy of this software and associated documentation files (the
10457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   ``Software''), to deal in the Software without restriction, including
11457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   without limitation the rights to use, copy, modify, merge, publish,
12457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   distribute, sublicense, and/or sell copies of the Software, and to
13457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   permit persons to whom the Software is furnished to do so, subject to
14457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   the following conditions:
15457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
16457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   The above copyright notice and this permission notice shall be included
17457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   in all copies or substantial portions of the Software.
18457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
19457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
20457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   DEALINGS IN THE SOFTWARE.
27457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   ----------------------------------------------------------------------- */
28457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
29457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique#include <ffi.h>
30457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique#include <ffi_common.h>
31457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
32457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique#include <stdlib.h>
33457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique#include <stdbool.h>
34457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique#include <float.h>
35457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
36457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique#include "ia64_flags.h"
37457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
38457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/* A 64-bit pointer value.  In LP64 mode, this is effectively a plain
39457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   pointer.  In ILP32 mode, it's a pointer that's been extended to
40457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   64 bits by "addp4".  */
41457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piquetypedef void *PTR64 __attribute__((mode(DI)));
42457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
43457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/* Memory image of fp register contents.  This is the implementation
44457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   specific format used by ldf.fill/stf.spill.  All we care about is
45457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   that it wants a 16 byte aligned slot.  */
46457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piquetypedef struct
47457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique{
48457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  UINT64 x[2] __attribute__((aligned(16)));
49457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique} fpreg;
50457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
51457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
52457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/* The stack layout given to ffi_call_unix and ffi_closure_unix_inner.  */
53457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
54457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piquestruct ia64_args
55457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique{
56457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  fpreg fp_regs[8];	/* Contents of 8 fp arg registers.  */
57457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  UINT64 gp_regs[8];	/* Contents of 8 gp arg registers.  */
58457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  UINT64 other_args[];	/* Arguments passed on stack, variable size.  */
59457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique};
60457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
61457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
62457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/* Adjust ADDR, a pointer to an 8 byte slot, to point to the low LEN bytes.  */
63457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
64457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piquestatic inline void *
65457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piqueendian_adjust (void *addr, size_t len)
66457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique{
67457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique#ifdef __BIG_ENDIAN__
68457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  return addr + (8 - len);
69457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique#else
70457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  return addr;
71457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique#endif
72457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique}
73457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
74457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/* Store VALUE to ADDR in the current cpu implementation's fp spill format.
75457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   This is a macro instead of a function, so that it works for all 3 floating
76457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   point types without type conversions.  Type conversion to long double breaks
77457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   the denorm support.  */
78457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
79457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique#define stf_spill(addr, value)	\
80457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  asm ("stf.spill %0 = %1%P0" : "=m" (*addr) : "f"(value));
81457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
82457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/* Load a value from ADDR, which is in the current cpu implementation's
83457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   fp spill format.  As above, this must also be a macro.  */
84457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
85457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique#define ldf_fill(result, addr)	\
86457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  asm ("ldf.fill %0 = %1%P1" : "=f"(result) : "m"(*addr));
87457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
88457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/* Return the size of the C type associated with with TYPE.  Which will
89457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   be one of the FFI_IA64_TYPE_HFA_* values.  */
90457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
91457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piquestatic size_t
92457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piquehfa_type_size (int type)
93457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique{
94457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  switch (type)
95457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    {
96457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    case FFI_IA64_TYPE_HFA_FLOAT:
97457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      return sizeof(float);
98457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    case FFI_IA64_TYPE_HFA_DOUBLE:
99457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      return sizeof(double);
100457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    case FFI_IA64_TYPE_HFA_LDOUBLE:
101457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      return sizeof(__float80);
102457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    default:
103457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      abort ();
104457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    }
105457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique}
106457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
107457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/* Load from ADDR a value indicated by TYPE.  Which will be one of
108457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   the FFI_IA64_TYPE_HFA_* values.  */
109457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
110457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piquestatic void
111457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piquehfa_type_load (fpreg *fpaddr, int type, void *addr)
112457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique{
113457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  switch (type)
114457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    {
115457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    case FFI_IA64_TYPE_HFA_FLOAT:
116457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      stf_spill (fpaddr, *(float *) addr);
117457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      return;
118457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    case FFI_IA64_TYPE_HFA_DOUBLE:
119457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      stf_spill (fpaddr, *(double *) addr);
120457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      return;
121457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    case FFI_IA64_TYPE_HFA_LDOUBLE:
122457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      stf_spill (fpaddr, *(__float80 *) addr);
123457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      return;
124457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    default:
125457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      abort ();
126457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    }
127457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique}
128457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
129457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/* Load VALUE into ADDR as indicated by TYPE.  Which will be one of
130457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   the FFI_IA64_TYPE_HFA_* values.  */
131457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
132457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piquestatic void
133457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piquehfa_type_store (int type, void *addr, fpreg *fpaddr)
134457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique{
135457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  switch (type)
136457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    {
137457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    case FFI_IA64_TYPE_HFA_FLOAT:
138457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      {
139457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	float result;
140457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	ldf_fill (result, fpaddr);
141457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	*(float *) addr = result;
142457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	break;
143457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      }
144457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    case FFI_IA64_TYPE_HFA_DOUBLE:
145457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      {
146457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	double result;
147457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	ldf_fill (result, fpaddr);
148457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	*(double *) addr = result;
149457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	break;
150457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      }
151457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    case FFI_IA64_TYPE_HFA_LDOUBLE:
152457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      {
153457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	__float80 result;
154457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	ldf_fill (result, fpaddr);
155457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	*(__float80 *) addr = result;
156457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	break;
157457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      }
158457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    default:
159457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      abort ();
160457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    }
161457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique}
162457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
163457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/* Is TYPE a struct containing floats, doubles, or extended doubles,
164457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   all of the same fp type?  If so, return the element type.  Return
165457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   FFI_TYPE_VOID if not.  */
166457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
167457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piquestatic int
168457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piquehfa_element_type (ffi_type *type, int nested)
169457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique{
170457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  int element = FFI_TYPE_VOID;
171457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
172457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  switch (type->type)
173457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    {
174457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    case FFI_TYPE_FLOAT:
175457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      /* We want to return VOID for raw floating-point types, but the
176457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	 synthetic HFA type if we're nested within an aggregate.  */
177457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      if (nested)
178457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	element = FFI_IA64_TYPE_HFA_FLOAT;
179457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      break;
180457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
181457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    case FFI_TYPE_DOUBLE:
182457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      /* Similarly.  */
183457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      if (nested)
184457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	element = FFI_IA64_TYPE_HFA_DOUBLE;
185457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      break;
186457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
187457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    case FFI_TYPE_LONGDOUBLE:
188457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      /* Similarly, except that that HFA is true for double extended,
189457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	 but not quad precision.  Both have sizeof == 16, so tell the
190457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	 difference based on the precision.  */
191457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      if (LDBL_MANT_DIG == 64 && nested)
192457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	element = FFI_IA64_TYPE_HFA_LDOUBLE;
193457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      break;
194457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
195457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    case FFI_TYPE_STRUCT:
196457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      {
197457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	ffi_type **ptr = &type->elements[0];
198457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
199457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	for (ptr = &type->elements[0]; *ptr ; ptr++)
200457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  {
201457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    int sub_element = hfa_element_type (*ptr, 1);
202457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    if (sub_element == FFI_TYPE_VOID)
203457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      return FFI_TYPE_VOID;
204457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
205457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    if (element == FFI_TYPE_VOID)
206457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      element = sub_element;
207457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    else if (element != sub_element)
208457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      return FFI_TYPE_VOID;
209457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  }
210457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      }
211457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      break;
212457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
213457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    default:
214457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      return FFI_TYPE_VOID;
215457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    }
216457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
217457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  return element;
218457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique}
219457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
220457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
221457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/* Perform machine dependent cif processing. */
222457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
223457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piqueffi_status
224457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piqueffi_prep_cif_machdep(ffi_cif *cif)
225457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique{
226457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  int flags;
227457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
228457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  /* Adjust cif->bytes to include space for the bits of the ia64_args frame
229457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique     that precedes the integer register portion.  The estimate that the
230457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique     generic bits did for the argument space required is good enough for the
231457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique     integer component.  */
232457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  cif->bytes += offsetof(struct ia64_args, gp_regs[0]);
233457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  if (cif->bytes < sizeof(struct ia64_args))
234457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    cif->bytes = sizeof(struct ia64_args);
235457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
236457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  /* Set the return type flag. */
237457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  flags = cif->rtype->type;
238457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  switch (cif->rtype->type)
239457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    {
240457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    case FFI_TYPE_LONGDOUBLE:
241457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      /* Leave FFI_TYPE_LONGDOUBLE as meaning double extended precision,
242457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	 and encode quad precision as a two-word integer structure.  */
243457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      if (LDBL_MANT_DIG != 64)
244457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	flags = FFI_IA64_TYPE_SMALL_STRUCT | (16 << 8);
245457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      break;
246457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
247457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    case FFI_TYPE_STRUCT:
248457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      {
249457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        size_t size = cif->rtype->size;
250457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  	int hfa_type = hfa_element_type (cif->rtype, 0);
251457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
252457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	if (hfa_type != FFI_TYPE_VOID)
253457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  {
254457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    size_t nelts = size / hfa_type_size (hfa_type);
255457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    if (nelts <= 8)
256457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      flags = hfa_type | (size << 8);
257457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  }
258457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	else
259457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  {
260457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    if (size <= 32)
261457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      flags = FFI_IA64_TYPE_SMALL_STRUCT | (size << 8);
262457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  }
263457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      }
264457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      break;
265457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
266457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    default:
267457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      break;
268457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    }
269457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  cif->flags = flags;
270457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
271457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  return FFI_OK;
272457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique}
273457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
274457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piqueextern int ffi_call_unix (struct ia64_args *, PTR64, void (*)(void), UINT64);
275457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
276457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piquevoid
277457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piqueffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
278457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique{
279457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  struct ia64_args *stack;
280457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  long i, avn, gpcount, fpcount;
281457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  ffi_type **p_arg;
282457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
283457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  FFI_ASSERT (cif->abi == FFI_UNIX);
284457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
285457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  /* If we have no spot for a return value, make one.  */
286457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  if (rvalue == NULL && cif->rtype->type != FFI_TYPE_VOID)
287457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    rvalue = alloca (cif->rtype->size);
288457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
289457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  /* Allocate the stack frame.  */
290457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  stack = alloca (cif->bytes);
291457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
292457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  gpcount = fpcount = 0;
293457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  avn = cif->nargs;
294457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
295457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    {
296457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      switch ((*p_arg)->type)
297457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	{
298457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_SINT8:
299457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  stack->gp_regs[gpcount++] = *(SINT8 *)avalue[i];
300457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  break;
301457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_UINT8:
302457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  stack->gp_regs[gpcount++] = *(UINT8 *)avalue[i];
303457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  break;
304457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_SINT16:
305457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  stack->gp_regs[gpcount++] = *(SINT16 *)avalue[i];
306457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  break;
307457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_UINT16:
308457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  stack->gp_regs[gpcount++] = *(UINT16 *)avalue[i];
309457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  break;
310457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_SINT32:
311457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  stack->gp_regs[gpcount++] = *(SINT32 *)avalue[i];
312457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  break;
313457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_UINT32:
314457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  stack->gp_regs[gpcount++] = *(UINT32 *)avalue[i];
315457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  break;
316457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_SINT64:
317457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_UINT64:
318457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  stack->gp_regs[gpcount++] = *(UINT64 *)avalue[i];
319457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  break;
320457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
321457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_POINTER:
322457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  stack->gp_regs[gpcount++] = (UINT64)(PTR64) *(void **)avalue[i];
323457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  break;
324457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
325457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_FLOAT:
326457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  if (gpcount < 8 && fpcount < 8)
327457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    stf_spill (&stack->fp_regs[fpcount++], *(float *)avalue[i]);
328457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  {
329457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    UINT32 tmp;
330457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    memcpy (&tmp, avalue[i], sizeof (UINT32));
331457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    stack->gp_regs[gpcount++] = tmp;
332457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  }
333457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  break;
334457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
335457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_DOUBLE:
336457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  if (gpcount < 8 && fpcount < 8)
337457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    stf_spill (&stack->fp_regs[fpcount++], *(double *)avalue[i]);
338457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  memcpy (&stack->gp_regs[gpcount++], avalue[i], sizeof (UINT64));
339457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  break;
340457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
341457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_LONGDOUBLE:
342457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  if (gpcount & 1)
343457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    gpcount++;
344457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
345457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    stf_spill (&stack->fp_regs[fpcount++], *(__float80 *)avalue[i]);
346457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  memcpy (&stack->gp_regs[gpcount], avalue[i], 16);
347457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  gpcount += 2;
348457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  break;
349457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
350457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_STRUCT:
351457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  {
352457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    size_t size = (*p_arg)->size;
353457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    size_t align = (*p_arg)->alignment;
354457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    int hfa_type = hfa_element_type (*p_arg, 0);
355457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
356457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    FFI_ASSERT (align <= 16);
357457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    if (align == 16 && (gpcount & 1))
358457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      gpcount++;
359457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
360457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    if (hfa_type != FFI_TYPE_VOID)
361457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      {
362457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		size_t hfa_size = hfa_type_size (hfa_type);
363457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		size_t offset = 0;
364457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		size_t gp_offset = gpcount * 8;
365457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
366457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		while (fpcount < 8
367457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		       && offset < size
368457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		       && gp_offset < 8 * 8)
369457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		  {
370457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		    hfa_type_load (&stack->fp_regs[fpcount], hfa_type,
371457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique				   avalue[i] + offset);
372457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		    offset += hfa_size;
373457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		    gp_offset += hfa_size;
374457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		    fpcount += 1;
375457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		  }
376457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      }
377457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
378457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    memcpy (&stack->gp_regs[gpcount], avalue[i], size);
379457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    gpcount += (size + 7) / 8;
380457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  }
381457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  break;
382457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
383457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	default:
384457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  abort ();
385457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	}
386457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    }
387457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
388457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  ffi_call_unix (stack, rvalue, fn, cif->flags);
389457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique}
390457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
391457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/* Closures represent a pair consisting of a function pointer, and
392457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   some user data.  A closure is invoked by reinterpreting the closure
393457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   as a function pointer, and branching to it.  Thus we can make an
394457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   interpreted function callable as a C function: We turn the
395457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   interpreter itself, together with a pointer specifying the
396457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   interpreted procedure, into a closure.
397457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
398457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   For IA64, function pointer are already pairs consisting of a code
399457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   pointer, and a gp pointer.  The latter is needed to access global
400457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   variables.  Here we set up such a pair as the first two words of
401457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   the closure (in the "trampoline" area), but we replace the gp
402457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   pointer with a pointer to the closure itself.  We also add the real
403457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   gp pointer to the closure.  This allows the function entry code to
404457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   both retrieve the user data, and to restore the correct gp pointer.  */
405457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
406457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piqueextern void ffi_closure_unix ();
407457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
408457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piqueffi_status
409457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piqueffi_prep_closure_loc (ffi_closure* closure,
410457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		      ffi_cif* cif,
411457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		      void (*fun)(ffi_cif*,void*,void**,void*),
412457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		      void *user_data,
413457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		      void *codeloc)
414457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique{
415457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  /* The layout of a function descriptor.  A C function pointer really
416457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique     points to one of these.  */
417457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  struct ia64_fd
418457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  {
419457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    UINT64 code_pointer;
420457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    UINT64 gp;
421457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  };
422457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
423457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  struct ffi_ia64_trampoline_struct
424457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  {
425457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    UINT64 code_pointer;	/* Pointer to ffi_closure_unix.  */
426457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    UINT64 fake_gp;		/* Pointer to closure, installed as gp.  */
427457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    UINT64 real_gp;		/* Real gp value.  */
428457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  };
429457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
430457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  struct ffi_ia64_trampoline_struct *tramp;
431457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  struct ia64_fd *fd;
432457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
433457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  if (cif->abi != FFI_UNIX)
434457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    return FFI_BAD_ABI;
435457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
436457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  tramp = (struct ffi_ia64_trampoline_struct *)closure->tramp;
437457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  fd = (struct ia64_fd *)(void *)ffi_closure_unix;
438457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
439457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  tramp->code_pointer = fd->code_pointer;
440457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  tramp->real_gp = fd->gp;
441457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  tramp->fake_gp = (UINT64)(PTR64)codeloc;
442457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  closure->cif = cif;
443457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  closure->user_data = user_data;
444457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  closure->fun = fun;
445457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
446457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  return FFI_OK;
447457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique}
448457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
449457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
450457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd PiqueUINT64
451457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piqueffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
452457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique			void *rvalue, void *r8)
453457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique{
454457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  ffi_cif *cif;
455457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  void **avalue;
456457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  ffi_type **p_arg;
457457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  long i, avn, gpcount, fpcount;
458457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
459457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  cif = closure->cif;
460457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  avn = cif->nargs;
461457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  avalue = alloca (avn * sizeof (void *));
462457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
463457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  /* If the structure return value is passed in memory get that location
464457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique     from r8 so as to pass the value directly back to the caller.  */
465457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  if (cif->flags == FFI_TYPE_STRUCT)
466457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    rvalue = r8;
467457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
468457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  gpcount = fpcount = 0;
469457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
470457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    {
471457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      switch ((*p_arg)->type)
472457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	{
473457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_SINT8:
474457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_UINT8:
475457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 1);
476457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  break;
477457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_SINT16:
478457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_UINT16:
479457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 2);
480457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  break;
481457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_SINT32:
482457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_UINT32:
483457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 4);
484457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  break;
485457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_SINT64:
486457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_UINT64:
487457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  avalue[i] = &stack->gp_regs[gpcount++];
488457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  break;
489457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_POINTER:
490457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], sizeof(void*));
491457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  break;
492457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
493457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_FLOAT:
494457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  if (gpcount < 8 && fpcount < 8)
495457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    {
496457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      fpreg *addr = &stack->fp_regs[fpcount++];
497457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      float result;
498457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      avalue[i] = addr;
499457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      ldf_fill (result, addr);
500457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      *(float *)addr = result;
501457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    }
502457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  else
503457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    avalue[i] = endian_adjust(&stack->gp_regs[gpcount], 4);
504457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  gpcount++;
505457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  break;
506457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
507457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_DOUBLE:
508457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  if (gpcount < 8 && fpcount < 8)
509457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    {
510457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      fpreg *addr = &stack->fp_regs[fpcount++];
511457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      double result;
512457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      avalue[i] = addr;
513457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      ldf_fill (result, addr);
514457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      *(double *)addr = result;
515457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    }
516457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  else
517457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    avalue[i] = &stack->gp_regs[gpcount];
518457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  gpcount++;
519457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  break;
520457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
521457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_LONGDOUBLE:
522457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  if (gpcount & 1)
523457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    gpcount++;
524457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
525457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    {
526457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      fpreg *addr = &stack->fp_regs[fpcount++];
527457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      __float80 result;
528457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      avalue[i] = addr;
529457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      ldf_fill (result, addr);
530457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      *(__float80 *)addr = result;
531457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    }
532457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  else
533457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    avalue[i] = &stack->gp_regs[gpcount];
534457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  gpcount += 2;
535457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  break;
536457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
537457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	case FFI_TYPE_STRUCT:
538457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  {
539457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    size_t size = (*p_arg)->size;
540457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    size_t align = (*p_arg)->alignment;
541457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    int hfa_type = hfa_element_type (*p_arg, 0);
542457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
543457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    FFI_ASSERT (align <= 16);
544457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    if (align == 16 && (gpcount & 1))
545457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      gpcount++;
546457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
547457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    if (hfa_type != FFI_TYPE_VOID)
548457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      {
549457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		size_t hfa_size = hfa_type_size (hfa_type);
550457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		size_t offset = 0;
551457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		size_t gp_offset = gpcount * 8;
552457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		void *addr = alloca (size);
553457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
554457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		avalue[i] = addr;
555457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
556457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		while (fpcount < 8
557457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		       && offset < size
558457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		       && gp_offset < 8 * 8)
559457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		  {
560457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		    hfa_type_store (hfa_type, addr + offset,
561457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique				    &stack->fp_regs[fpcount]);
562457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		    offset += hfa_size;
563457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		    gp_offset += hfa_size;
564457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		    fpcount += 1;
565457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		  }
566457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
567457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		if (offset < size)
568457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique		  memcpy (addr + offset, (char *)stack->gp_regs + gp_offset,
569457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique			  size - offset);
570457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      }
571457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    else
572457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	      avalue[i] = &stack->gp_regs[gpcount];
573457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
574457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	    gpcount += (size + 7) / 8;
575457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  }
576457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  break;
577457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
578457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	default:
579457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	  abort ();
580457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique	}
581457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    }
582457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
583457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  closure->fun (cif, rvalue, avalue, closure->user_data);
584457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
585457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  return cif->flags;
586457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique}
587