1baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com/* -----------------------------------------------------------------------
2baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   ffi_linux64.c - Copyright (C) 2013 IBM
3baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com                   Copyright (C) 2011 Anthony Green
4baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com                   Copyright (C) 2011 Kyle Moffett
5baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com                   Copyright (C) 2008 Red Hat, Inc
6baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com                   Copyright (C) 2007, 2008 Free Software Foundation, Inc
7baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com                   Copyright (c) 1998 Geoffrey Keating
8baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
9baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   PowerPC Foreign Function Interface
10baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
11baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   Permission is hereby granted, free of charge, to any person obtaining
12baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   a copy of this software and associated documentation files (the
13baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   ``Software''), to deal in the Software without restriction, including
14baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   without limitation the rights to use, copy, modify, merge, publish,
15baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   distribute, sublicense, and/or sell copies of the Software, and to
16baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   permit persons to whom the Software is furnished to do so, subject to
17baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   the following conditions:
18baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
19baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   The above copyright notice and this permission notice shall be included
20baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   in all copies or substantial portions of the Software.
21baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
22baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
23baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
26baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
27baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   OTHER DEALINGS IN THE SOFTWARE.
29baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   ----------------------------------------------------------------------- */
30baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
31baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#include "ffi.h"
32baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
33baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#ifdef POWERPC64
34baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#include "ffi_common.h"
35baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#include "ffi_powerpc.h"
36baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
37baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
38baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com/* About the LINUX64 ABI.  */
39baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comenum {
40baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  NUM_GPR_ARG_REGISTERS64 = 8,
41baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  NUM_FPR_ARG_REGISTERS64 = 13
42baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com};
43baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comenum { ASM_NEEDS_REGISTERS64 = 4 };
44baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
45baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
46baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#if HAVE_LONG_DOUBLE_VARIANT && FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
47baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com/* Adjust size of ffi_type_longdouble.  */
48baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comvoid FFI_HIDDEN
49baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comffi_prep_types_linux64 (ffi_abi abi)
50baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com{
51baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  if ((abi & (FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128)) == FFI_LINUX)
52baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    {
53baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      ffi_type_longdouble.size = 8;
54baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      ffi_type_longdouble.alignment = 8;
55baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    }
56baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  else
57baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    {
58baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      ffi_type_longdouble.size = 16;
59baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      ffi_type_longdouble.alignment = 16;
60baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    }
61baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com}
62baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
63baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
64baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
65baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#if _CALL_ELF == 2
66baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comstatic unsigned int
67baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comdiscover_homogeneous_aggregate (const ffi_type *t, unsigned int *elnum)
68baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com{
69baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  switch (t->type)
70baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    {
71baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    case FFI_TYPE_FLOAT:
72baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    case FFI_TYPE_DOUBLE:
73baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      *elnum = 1;
74baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      return (int) t->type;
75baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
76baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    case FFI_TYPE_STRUCT:;
77baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      {
78baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	unsigned int base_elt = 0, total_elnum = 0;
79baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	ffi_type **el = t->elements;
80baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	while (*el)
81baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  {
82baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    unsigned int el_elt, el_elnum = 0;
83baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    el_elt = discover_homogeneous_aggregate (*el, &el_elnum);
84baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    if (el_elt == 0
85baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		|| (base_elt && base_elt != el_elt))
86baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      return 0;
87baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    base_elt = el_elt;
88baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    total_elnum += el_elnum;
89baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    if (total_elnum > 8)
90baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      return 0;
91baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    el++;
92baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  }
93baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	*elnum = total_elnum;
94baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	return base_elt;
95baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      }
96baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
97baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    default:
98baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      return 0;
99baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    }
100baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com}
101baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
102baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
103baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
104baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com/* Perform machine dependent cif processing */
105baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comstatic ffi_status
106baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comffi_prep_cif_linux64_core (ffi_cif *cif)
107baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com{
108baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  ffi_type **ptr;
109baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  unsigned bytes;
110baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  unsigned i, fparg_count = 0, intarg_count = 0;
111baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  unsigned flags = cif->flags;
112baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#if _CALL_ELF == 2
113baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  unsigned int elt, elnum;
114baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
115baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
116baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#if FFI_TYPE_LONGDOUBLE == FFI_TYPE_DOUBLE
117baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* If compiled without long double support..  */
118baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
119baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    return FFI_BAD_ABI;
120baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
121baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
122baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* The machine-independent calculation of cif->bytes doesn't work
123baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com     for us.  Redo the calculation.  */
124baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#if _CALL_ELF == 2
125baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* Space for backchain, CR, LR, TOC and the asm's temp regs.  */
126baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  bytes = (4 + ASM_NEEDS_REGISTERS64) * sizeof (long);
127baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
128baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* Space for the general registers.  */
129baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  bytes += NUM_GPR_ARG_REGISTERS64 * sizeof (long);
130baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#else
131baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* Space for backchain, CR, LR, cc/ld doubleword, TOC and the asm's temp
132baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com     regs.  */
133baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  bytes = (6 + ASM_NEEDS_REGISTERS64) * sizeof (long);
134baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
135baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* Space for the mandatory parm save area and general registers.  */
136baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  bytes += 2 * NUM_GPR_ARG_REGISTERS64 * sizeof (long);
137baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
138baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
139baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* Return value handling.  */
140baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  switch (cif->rtype->type)
141baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    {
142baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
143baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    case FFI_TYPE_LONGDOUBLE:
144baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
145baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	flags |= FLAG_RETURNS_128BITS;
146baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      /* Fall through.  */
147baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
148baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    case FFI_TYPE_DOUBLE:
149baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      flags |= FLAG_RETURNS_64BITS;
150baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      /* Fall through.  */
151baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    case FFI_TYPE_FLOAT:
152baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      flags |= FLAG_RETURNS_FP;
153baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      break;
154baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
155baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    case FFI_TYPE_UINT128:
156baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      flags |= FLAG_RETURNS_128BITS;
157baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      /* Fall through.  */
158baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    case FFI_TYPE_UINT64:
159baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    case FFI_TYPE_SINT64:
160baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      flags |= FLAG_RETURNS_64BITS;
161baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      break;
162baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
163baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    case FFI_TYPE_STRUCT:
164baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#if _CALL_ELF == 2
165baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      elt = discover_homogeneous_aggregate (cif->rtype, &elnum);
166baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      if (elt)
167baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	{
168baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  if (elt == FFI_TYPE_DOUBLE)
169baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    flags |= FLAG_RETURNS_64BITS;
170baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  flags |= FLAG_RETURNS_FP | FLAG_RETURNS_SMST;
171baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  break;
172baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	}
173baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      if (cif->rtype->size <= 16)
174baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	{
175baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  flags |= FLAG_RETURNS_SMST;
176baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  break;
177baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	}
178baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
179baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      intarg_count++;
180baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      flags |= FLAG_RETVAL_REFERENCE;
181baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      /* Fall through.  */
182baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    case FFI_TYPE_VOID:
183baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      flags |= FLAG_RETURNS_NOTHING;
184baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      break;
185baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
186baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    default:
187baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      /* Returns 32-bit integer, or similar.  Nothing to do here.  */
188baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      break;
189baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    }
190baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
191baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
192baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    {
193baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      unsigned int align;
194baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
195baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      switch ((*ptr)->type)
196baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	{
197baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
198baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_LONGDOUBLE:
199baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
200baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    {
201baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      fparg_count++;
202baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      intarg_count++;
203baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    }
204baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  /* Fall through.  */
205baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
206baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_DOUBLE:
207baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_FLOAT:
208baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  fparg_count++;
209baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  intarg_count++;
210baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  if (fparg_count > NUM_FPR_ARG_REGISTERS64)
211baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    flags |= FLAG_ARG_NEEDS_PSAVE;
212baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  break;
213baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
214baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_STRUCT:
215baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  if ((cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0)
216baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    {
217baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      align = (*ptr)->alignment;
218baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      if (align > 16)
219baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		align = 16;
220baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      align = align / 8;
221baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      if (align > 1)
222baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		intarg_count = ALIGN (intarg_count, align);
223baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    }
224baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  intarg_count += ((*ptr)->size + 7) / 8;
225baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#if _CALL_ELF == 2
226baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  elt = discover_homogeneous_aggregate (*ptr, &elnum);
227baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  if (elt)
228baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    {
229baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      fparg_count += elnum;
230baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      if (fparg_count > NUM_FPR_ARG_REGISTERS64)
231baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		flags |= FLAG_ARG_NEEDS_PSAVE;
232baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    }
233baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  else
234baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
235baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    {
236baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      if (intarg_count > NUM_GPR_ARG_REGISTERS64)
237baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		flags |= FLAG_ARG_NEEDS_PSAVE;
238baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    }
239baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  break;
240baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
241baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_POINTER:
242baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_UINT64:
243baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_SINT64:
244baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_INT:
245baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_UINT32:
246baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_SINT32:
247baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_UINT16:
248baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_SINT16:
249baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_UINT8:
250baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_SINT8:
251baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  /* Everything else is passed as a 8-byte word in a GPR, either
252baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	     the object itself or a pointer to it.  */
253baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  intarg_count++;
254baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  if (intarg_count > NUM_GPR_ARG_REGISTERS64)
255baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    flags |= FLAG_ARG_NEEDS_PSAVE;
256baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  break;
257baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	default:
258baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  FFI_ASSERT (0);
259baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	}
260baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    }
261baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
262baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  if (fparg_count != 0)
263baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    flags |= FLAG_FP_ARGUMENTS;
264baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  if (intarg_count > 4)
265baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    flags |= FLAG_4_GPR_ARGUMENTS;
266baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
267baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* Space for the FPR registers, if needed.  */
268baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  if (fparg_count != 0)
269baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    bytes += NUM_FPR_ARG_REGISTERS64 * sizeof (double);
270baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
271baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* Stack space.  */
272baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#if _CALL_ELF == 2
273baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  if ((flags & FLAG_ARG_NEEDS_PSAVE) != 0)
274baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    bytes += intarg_count * sizeof (long);
275baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#else
276baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  if (intarg_count > NUM_GPR_ARG_REGISTERS64)
277baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    bytes += (intarg_count - NUM_GPR_ARG_REGISTERS64) * sizeof (long);
278baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
279baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
280baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* The stack space allocated needs to be a multiple of 16 bytes.  */
281baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  bytes = (bytes + 15) & ~0xF;
282baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
283baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  cif->flags = flags;
284baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  cif->bytes = bytes;
285baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
286baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  return FFI_OK;
287baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com}
288baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
289baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comffi_status FFI_HIDDEN
290baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comffi_prep_cif_linux64 (ffi_cif *cif)
291baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com{
292baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  if ((cif->abi & FFI_LINUX) != 0)
293baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    cif->nfixedargs = cif->nargs;
294baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#if _CALL_ELF != 2
295baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  else if (cif->abi == FFI_COMPAT_LINUX64)
296baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    {
297baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      /* This call is from old code.  Don't touch cif->nfixedargs
298baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	 since old code will be using a smaller cif.  */
299baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      cif->flags |= FLAG_COMPAT;
300baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      /* Translate to new abi value.  */
301baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      cif->abi = FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128;
302baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    }
303baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
304baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  else
305baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    return FFI_BAD_ABI;
306baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  return ffi_prep_cif_linux64_core (cif);
307baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com}
308baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
309baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comffi_status FFI_HIDDEN
310baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comffi_prep_cif_linux64_var (ffi_cif *cif,
311baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			  unsigned int nfixedargs,
312baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			  unsigned int ntotalargs MAYBE_UNUSED)
313baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com{
314baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  if ((cif->abi & FFI_LINUX) != 0)
315baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    cif->nfixedargs = nfixedargs;
316baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#if _CALL_ELF != 2
317baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  else if (cif->abi == FFI_COMPAT_LINUX64)
318baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    {
319baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      /* This call is from old code.  Don't touch cif->nfixedargs
320baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	 since old code will be using a smaller cif.  */
321baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      cif->flags |= FLAG_COMPAT;
322baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      /* Translate to new abi value.  */
323baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      cif->abi = FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128;
324baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    }
325baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
326baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  else
327baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    return FFI_BAD_ABI;
328baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#if _CALL_ELF == 2
329baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  cif->flags |= FLAG_ARG_NEEDS_PSAVE;
330baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
331baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  return ffi_prep_cif_linux64_core (cif);
332baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com}
333baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
334baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
335baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com/* ffi_prep_args64 is called by the assembly routine once stack space
336baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   has been allocated for the function's arguments.
337baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
338baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   The stack layout we want looks like this:
339baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
340baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |   Ret addr from ffi_call_LINUX64	8bytes	|	higher addresses
341baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |--------------------------------------------|
342baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |   CR save area			8bytes	|
343baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |--------------------------------------------|
344baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |   Previous backchain pointer	8	|	stack pointer here
345baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |--------------------------------------------|<+ <<<	on entry to
346baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |   Saved r28-r31			4*8	| |	ffi_call_LINUX64
347baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |--------------------------------------------| |
348baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |   GPR registers r3-r10		8*8	| |
349baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |--------------------------------------------| |
350baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |   FPR registers f1-f13 (optional)	13*8	| |
351baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |--------------------------------------------| |
352baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |   Parameter save area		        | |
353baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |--------------------------------------------| |
354baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |   TOC save area			8	| |
355baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |--------------------------------------------| |	stack	|
356baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |   Linker doubleword		8	| |	grows	|
357baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |--------------------------------------------| |	down	V
358baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |   Compiler doubleword		8	| |
359baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |--------------------------------------------| |	lower addresses
360baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |   Space for callee's LR		8	| |
361baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |--------------------------------------------| |
362baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |   CR save area			8	| |
363baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |--------------------------------------------| |	stack pointer here
364baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |   Current backchain pointer	8	|-/	during
365baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   |--------------------------------------------|   <<<	ffi_call_LINUX64
366baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
367baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com*/
368baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
369baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comvoid FFI_HIDDEN
370baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
371baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com{
372baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  const unsigned long bytes = ecif->cif->bytes;
373baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  const unsigned long flags = ecif->cif->flags;
374baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
375baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  typedef union
376baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  {
377baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    char *c;
378baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    unsigned long *ul;
379baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    float *f;
380baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    double *d;
381baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    size_t p;
382baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  } valp;
383baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
384baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* 'stacktop' points at the previous backchain pointer.  */
385baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  valp stacktop;
386baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
387baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* 'next_arg' points at the space for gpr3, and grows upwards as
388baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com     we use GPR registers, then continues at rest.  */
389baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  valp gpr_base;
390baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  valp gpr_end;
391baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  valp rest;
392baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  valp next_arg;
393baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
394baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* 'fpr_base' points at the space for fpr3, and grows upwards as
395baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com     we use FPR registers.  */
396baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  valp fpr_base;
397baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  unsigned int fparg_count;
398baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
399baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  unsigned int i, words, nargs, nfixedargs;
400baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  ffi_type **ptr;
401baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  double double_tmp;
402baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  union
403baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  {
404baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    void **v;
405baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    char **c;
406baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    signed char **sc;
407baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    unsigned char **uc;
408baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    signed short **ss;
409baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    unsigned short **us;
410baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    signed int **si;
411baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    unsigned int **ui;
412baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    unsigned long **ul;
413baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    float **f;
414baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    double **d;
415baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  } p_argv;
416baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  unsigned long gprvalue;
417baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  unsigned long align;
418baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
419baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  stacktop.c = (char *) stack + bytes;
420baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  gpr_base.ul = stacktop.ul - ASM_NEEDS_REGISTERS64 - NUM_GPR_ARG_REGISTERS64;
421baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  gpr_end.ul = gpr_base.ul + NUM_GPR_ARG_REGISTERS64;
422baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#if _CALL_ELF == 2
423baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  rest.ul = stack + 4 + NUM_GPR_ARG_REGISTERS64;
424baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#else
425baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  rest.ul = stack + 6 + NUM_GPR_ARG_REGISTERS64;
426baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
427baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS64;
428baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  fparg_count = 0;
429baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  next_arg.ul = gpr_base.ul;
430baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
431baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* Check that everything starts aligned properly.  */
432baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  FFI_ASSERT (((unsigned long) (char *) stack & 0xF) == 0);
433baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  FFI_ASSERT (((unsigned long) stacktop.c & 0xF) == 0);
434baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  FFI_ASSERT ((bytes & 0xF) == 0);
435baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
436baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* Deal with return values that are actually pass-by-reference.  */
437baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  if (flags & FLAG_RETVAL_REFERENCE)
438baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    *next_arg.ul++ = (unsigned long) (char *) ecif->rvalue;
439baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
440baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* Now for the arguments.  */
441baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  p_argv.v = ecif->avalue;
442baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  nargs = ecif->cif->nargs;
443baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#if _CALL_ELF != 2
444baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  nfixedargs = (unsigned) -1;
445baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  if ((flags & FLAG_COMPAT) == 0)
446baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
447baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    nfixedargs = ecif->cif->nfixedargs;
448baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  for (ptr = ecif->cif->arg_types, i = 0;
449baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com       i < nargs;
450baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com       i++, ptr++, p_argv.v++)
451baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    {
452baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#if _CALL_ELF == 2
453baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      unsigned int elt, elnum;
454baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
455baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
456baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      switch ((*ptr)->type)
457baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	{
458baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
459baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_LONGDOUBLE:
460baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  if ((ecif->cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
461baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    {
462baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      double_tmp = (*p_argv.d)[0];
463baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
464baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		{
465baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  *fpr_base.d++ = double_tmp;
466baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com# if _CALL_ELF != 2
467baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  if ((flags & FLAG_COMPAT) != 0)
468baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		    *next_arg.d = double_tmp;
469baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com# endif
470baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		}
471baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      else
472baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		*next_arg.d = double_tmp;
473baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      if (++next_arg.ul == gpr_end.ul)
474baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		next_arg.ul = rest.ul;
475baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      fparg_count++;
476baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      double_tmp = (*p_argv.d)[1];
477baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
478baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		{
479baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  *fpr_base.d++ = double_tmp;
480baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com# if _CALL_ELF != 2
481baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  if ((flags & FLAG_COMPAT) != 0)
482baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		    *next_arg.d = double_tmp;
483baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com# endif
484baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		}
485baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      else
486baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		*next_arg.d = double_tmp;
487baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      if (++next_arg.ul == gpr_end.ul)
488baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		next_arg.ul = rest.ul;
489baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      fparg_count++;
490baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      FFI_ASSERT (__LDBL_MANT_DIG__ == 106);
491baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
492baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      break;
493baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    }
494baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  /* Fall through.  */
495baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
496baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_DOUBLE:
497baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  double_tmp = **p_argv.d;
498baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
499baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    {
500baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      *fpr_base.d++ = double_tmp;
501baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#if _CALL_ELF != 2
502baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      if ((flags & FLAG_COMPAT) != 0)
503baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		*next_arg.d = double_tmp;
504baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
505baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    }
506baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  else
507baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    *next_arg.d = double_tmp;
508baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  if (++next_arg.ul == gpr_end.ul)
509baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    next_arg.ul = rest.ul;
510baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  fparg_count++;
511baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
512baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  break;
513baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
514baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_FLOAT:
515baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  double_tmp = **p_argv.f;
516baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
517baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    {
518baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      *fpr_base.d++ = double_tmp;
519baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#if _CALL_ELF != 2
520baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      if ((flags & FLAG_COMPAT) != 0)
521baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		*next_arg.f = (float) double_tmp;
522baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
523baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    }
524baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  else
525baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    *next_arg.f = (float) double_tmp;
526baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  if (++next_arg.ul == gpr_end.ul)
527baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    next_arg.ul = rest.ul;
528baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  fparg_count++;
529baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
530baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  break;
531baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
532baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_STRUCT:
533baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  if ((ecif->cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0)
534baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    {
535baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      align = (*ptr)->alignment;
536baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      if (align > 16)
537baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		align = 16;
538baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      if (align > 1)
539baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		next_arg.p = ALIGN (next_arg.p, align);
540baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    }
541baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#if _CALL_ELF == 2
542baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  elt = discover_homogeneous_aggregate (*ptr, &elnum);
543baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  if (elt)
544baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    {
545baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      union {
546baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		void *v;
547baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		float *f;
548baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		double *d;
549baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      } arg;
550baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
551baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      arg.v = *p_argv.v;
552baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      if (elt == FFI_TYPE_FLOAT)
553baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		{
554baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  do
555baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		    {
556baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		      double_tmp = *arg.f++;
557baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		      if (fparg_count < NUM_FPR_ARG_REGISTERS64
558baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			  && i < nfixedargs)
559baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			*fpr_base.d++ = double_tmp;
560baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		      else
561baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			*next_arg.f = (float) double_tmp;
562baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		      if (++next_arg.f == gpr_end.f)
563baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			next_arg.f = rest.f;
564baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		      fparg_count++;
565baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		    }
566baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  while (--elnum != 0);
567baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  if ((next_arg.p & 3) != 0)
568baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		    {
569baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		      if (++next_arg.f == gpr_end.f)
570baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			next_arg.f = rest.f;
571baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		    }
572baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		}
573baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      else
574baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		do
575baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  {
576baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		    double_tmp = *arg.d++;
577baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		    if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
578baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		      *fpr_base.d++ = double_tmp;
579baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		    else
580baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		      *next_arg.d = double_tmp;
581baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		    if (++next_arg.d == gpr_end.d)
582baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		      next_arg.d = rest.d;
583baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		    fparg_count++;
584baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  }
585baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		while (--elnum != 0);
586baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    }
587baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  else
588baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
589baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    {
590baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      words = ((*ptr)->size + 7) / 8;
591baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      if (next_arg.ul >= gpr_base.ul && next_arg.ul + words > gpr_end.ul)
592baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		{
593baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  size_t first = gpr_end.c - next_arg.c;
594baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  memcpy (next_arg.c, *p_argv.c, first);
595baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  memcpy (rest.c, *p_argv.c + first, (*ptr)->size - first);
596baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  next_arg.c = rest.c + words * 8 - first;
597baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		}
598baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      else
599baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		{
600baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  char *where = next_arg.c;
601baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
602baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#ifndef __LITTLE_ENDIAN__
603baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  /* Structures with size less than eight bytes are passed
604baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		     left-padded.  */
605baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  if ((*ptr)->size < 8)
606baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		    where += 8 - (*ptr)->size;
607baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
608baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  memcpy (where, *p_argv.c, (*ptr)->size);
609baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  next_arg.ul += words;
610baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  if (next_arg.ul == gpr_end.ul)
611baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		    next_arg.ul = rest.ul;
612baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		}
613baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    }
614baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  break;
615baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
616baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_UINT8:
617baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  gprvalue = **p_argv.uc;
618baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  goto putgpr;
619baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_SINT8:
620baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  gprvalue = **p_argv.sc;
621baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  goto putgpr;
622baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_UINT16:
623baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  gprvalue = **p_argv.us;
624baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  goto putgpr;
625baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_SINT16:
626baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  gprvalue = **p_argv.ss;
627baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  goto putgpr;
628baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_UINT32:
629baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  gprvalue = **p_argv.ui;
630baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  goto putgpr;
631baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_INT:
632baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_SINT32:
633baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  gprvalue = **p_argv.si;
634baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  goto putgpr;
635baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
636baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_UINT64:
637baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_SINT64:
638baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_POINTER:
639baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  gprvalue = **p_argv.ul;
640baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	putgpr:
641baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  *next_arg.ul++ = gprvalue;
642baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  if (next_arg.ul == gpr_end.ul)
643baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    next_arg.ul = rest.ul;
644baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  break;
645baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	}
646baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    }
647baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
648baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS
649baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      || (next_arg.ul >= gpr_base.ul
650baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  && next_arg.ul <= gpr_base.ul + 4));
651baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com}
652baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
653baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
654baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#if _CALL_ELF == 2
655baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#define MIN_CACHE_LINE_SIZE 8
656baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
657baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comstatic void
658baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comflush_icache (char *wraddr, char *xaddr, int size)
659baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com{
660baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  int i;
661baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE)
662baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;"
663baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		      : : "r" (xaddr + i), "r" (wraddr + i) : "memory");
664baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;" "sync;" "isync;"
665baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		    : : "r"(xaddr + size - 1), "r"(wraddr + size - 1)
666baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		    : "memory");
667baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com}
668baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
669baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
670baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comffi_status
671baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comffi_prep_closure_loc_linux64 (ffi_closure *closure,
672baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			      ffi_cif *cif,
673baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			      void (*fun) (ffi_cif *, void *, void **, void *),
674baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			      void *user_data,
675baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			      void *codeloc)
676baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com{
677baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#if _CALL_ELF == 2
678baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  unsigned int *tramp = (unsigned int *) &closure->tramp[0];
679baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
680baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  if (cif->abi < FFI_LINUX || cif->abi >= FFI_LAST_ABI)
681baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    return FFI_BAD_ABI;
682baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
683baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  tramp[0] = 0xe96c0018;	/* 0:	ld	11,2f-0b(12)	*/
684baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  tramp[1] = 0xe98c0010;	/*	ld	12,1f-0b(12)	*/
685baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  tramp[2] = 0x7d8903a6;	/*	mtctr	12		*/
686baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  tramp[3] = 0x4e800420;	/*	bctr			*/
687baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com				/* 1:	.quad	function_addr	*/
688baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com				/* 2:	.quad	context		*/
689baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  *(void **) &tramp[4] = (void *) ffi_closure_LINUX64;
690baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  *(void **) &tramp[6] = codeloc;
691baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  flush_icache ((char *)tramp, (char *)codeloc, FFI_TRAMPOLINE_SIZE);
692baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#else
693baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  void **tramp = (void **) &closure->tramp[0];
694baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
695baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  if (cif->abi < FFI_LINUX || cif->abi >= FFI_LAST_ABI)
696baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    return FFI_BAD_ABI;
697baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
698baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* Copy function address and TOC from ffi_closure_LINUX64.  */
699baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  memcpy (tramp, (char *) ffi_closure_LINUX64, 16);
700baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  tramp[2] = tramp[1];
701baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  tramp[1] = codeloc;
702baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
703baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
704baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  closure->cif = cif;
705baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  closure->fun = fun;
706baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  closure->user_data = user_data;
707baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
708baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  return FFI_OK;
709baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com}
710baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
711baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
712baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comint FFI_HIDDEN
713baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue,
714baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			    unsigned long *pst, ffi_dblfl *pfr)
715baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com{
716baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* rvalue is the pointer to space for return value in closure assembly */
717baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* pst is the pointer to parameter save area
718baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com     (r3-r10 are stored into its first 8 slots by ffi_closure_LINUX64) */
719baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* pfr is the pointer to where f1-f13 are stored in ffi_closure_LINUX64 */
720baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
721baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  void **avalue;
722baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  ffi_type **arg_types;
723baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  unsigned long i, avn, nfixedargs;
724baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  ffi_cif *cif;
725baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64;
726baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  unsigned long align;
727baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
728baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  cif = closure->cif;
729baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  avalue = alloca (cif->nargs * sizeof (void *));
730baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
731baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* Copy the caller's structure return value address so that the
732baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com     closure returns the data directly to the caller.  */
733baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  if (cif->rtype->type == FFI_TYPE_STRUCT
734baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      && (cif->flags & FLAG_RETURNS_SMST) == 0)
735baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    {
736baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      rvalue = (void *) *pst;
737baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      pst++;
738baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    }
739baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
740baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  i = 0;
741baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  avn = cif->nargs;
742baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#if _CALL_ELF != 2
743baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  nfixedargs = (unsigned) -1;
744baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  if ((cif->flags & FLAG_COMPAT) == 0)
745baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
746baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    nfixedargs = cif->nfixedargs;
747baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  arg_types = cif->arg_types;
748baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
749baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* Grab the addresses of the arguments from the stack frame.  */
750baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  while (i < avn)
751baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    {
752baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      unsigned int elt, elnum;
753baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
754baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      switch (arg_types[i]->type)
755baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	{
756baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_SINT8:
757baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_UINT8:
758baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#ifndef __LITTLE_ENDIAN__
759baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  avalue[i] = (char *) pst + 7;
760baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  pst++;
761baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  break;
762baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
763baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
764baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_SINT16:
765baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_UINT16:
766baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#ifndef __LITTLE_ENDIAN__
767baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  avalue[i] = (char *) pst + 6;
768baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  pst++;
769baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  break;
770baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
771baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
772baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_SINT32:
773baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_UINT32:
774baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#ifndef __LITTLE_ENDIAN__
775baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  avalue[i] = (char *) pst + 4;
776baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  pst++;
777baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  break;
778baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
779baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
780baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_SINT64:
781baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_UINT64:
782baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_POINTER:
783baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  avalue[i] = pst;
784baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  pst++;
785baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  break;
786baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
787baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_STRUCT:
788baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  if ((cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0)
789baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    {
790baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      align = arg_types[i]->alignment;
791baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      if (align > 16)
792baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		align = 16;
793baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      if (align > 1)
794baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		pst = (unsigned long *) ALIGN ((size_t) pst, align);
795baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    }
796baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  elt = 0;
797baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#if _CALL_ELF == 2
798baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  elt = discover_homogeneous_aggregate (arg_types[i], &elnum);
799baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
800baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  if (elt)
801baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    {
802baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      union {
803baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		void *v;
804baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		unsigned long *ul;
805baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		float *f;
806baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		double *d;
807baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		size_t p;
808baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      } to, from;
809baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
810baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      /* Repackage the aggregate from its parts.  The
811baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		 aggregate size is not greater than the space taken by
812baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		 the registers so store back to the register/parameter
813baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		 save arrays.  */
814baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      if (pfr + elnum <= end_pfr)
815baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		to.v = pfr;
816baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      else
817baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		to.v = pst;
818baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
819baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      avalue[i] = to.v;
820baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      from.ul = pst;
821baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      if (elt == FFI_TYPE_FLOAT)
822baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		{
823baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  do
824baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		    {
825baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		      if (pfr < end_pfr && i < nfixedargs)
826baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			{
827baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			  *to.f = (float) pfr->d;
828baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			  pfr++;
829baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			}
830baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		      else
831baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			*to.f = *from.f;
832baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		      to.f++;
833baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		      from.f++;
834baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		    }
835baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  while (--elnum != 0);
836baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		}
837baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      else
838baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		{
839baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  do
840baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		    {
841baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		      if (pfr < end_pfr && i < nfixedargs)
842baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			{
843baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			  *to.d = pfr->d;
844baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			  pfr++;
845baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			}
846baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		      else
847baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			*to.d = *from.d;
848baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		      to.d++;
849baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		      from.d++;
850baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		    }
851baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  while (--elnum != 0);
852baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		}
853baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    }
854baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  else
855baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    {
856baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#ifndef __LITTLE_ENDIAN__
857baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      /* Structures with size less than eight bytes are passed
858baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		 left-padded.  */
859baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      if (arg_types[i]->size < 8)
860baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		avalue[i] = (char *) pst + 8 - arg_types[i]->size;
861baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      else
862baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
863baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		avalue[i] = pst;
864baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    }
865baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  pst += (arg_types[i]->size + 7) / 8;
866baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  break;
867baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
868baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
869baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_LONGDOUBLE:
870baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
871baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    {
872baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      if (pfr + 1 < end_pfr && i + 1 < nfixedargs)
873baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		{
874baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  avalue[i] = pfr;
875baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  pfr += 2;
876baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		}
877baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      else
878baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		{
879baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  if (pfr < end_pfr && i < nfixedargs)
880baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		    {
881baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		      /* Passed partly in f13 and partly on the stack.
882baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			 Move it all to the stack.  */
883baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		      *pst = *(unsigned long *) pfr;
884baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		      pfr++;
885baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		    }
886baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		  avalue[i] = pst;
887baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		}
888baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      pst += 2;
889baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      break;
890baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    }
891baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  /* Fall through.  */
892baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
893baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_DOUBLE:
894baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  /* On the outgoing stack all values are aligned to 8 */
895baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  /* there are 13 64bit floating point registers */
896baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
897baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  if (pfr < end_pfr && i < nfixedargs)
898baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    {
899baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      avalue[i] = pfr;
900baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      pfr++;
901baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    }
902baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  else
903baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    avalue[i] = pst;
904baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  pst++;
905baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  break;
906baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
907baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	case FFI_TYPE_FLOAT:
908baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  if (pfr < end_pfr && i < nfixedargs)
909baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    {
910baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      /* Float values are stored as doubles in the
911baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		 ffi_closure_LINUX64 code.  Fix them here.  */
912baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      pfr->f = (float) pfr->d;
913baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      avalue[i] = pfr;
914baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      pfr++;
915baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    }
916baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  else
917baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    avalue[i] = pst;
918baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  pst++;
919baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  break;
920baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
921baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	default:
922baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  FFI_ASSERT (0);
923baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	}
924baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
925baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      i++;
926baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    }
927baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
928baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
929baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  (closure->fun) (cif, rvalue, avalue, closure->user_data);
930baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
931baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* Tell ffi_closure_LINUX64 how to perform return type promotions.  */
932baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  if ((cif->flags & FLAG_RETURNS_SMST) != 0)
933baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    {
934baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      if ((cif->flags & FLAG_RETURNS_FP) == 0)
935baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	return FFI_V2_TYPE_SMALL_STRUCT + cif->rtype->size - 1;
936baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      else if ((cif->flags & FLAG_RETURNS_64BITS) != 0)
937baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	return FFI_V2_TYPE_DOUBLE_HOMOG;
938baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      else
939baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	return FFI_V2_TYPE_FLOAT_HOMOG;
940baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    }
941baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  return cif->rtype->type;
942baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com}
943baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#endif
944