xref: /aosp_15_r20/external/libffi/src/powerpc/ffi_sysv.c (revision 1fd5a2e1d639cd1ddf29dd0c484c123bbd850c21)
1*1fd5a2e1SPrashanth Swaminathan /* -----------------------------------------------------------------------
2*1fd5a2e1SPrashanth Swaminathan    ffi_sysv.c - Copyright (C) 2013 IBM
3*1fd5a2e1SPrashanth Swaminathan                 Copyright (C) 2011 Anthony Green
4*1fd5a2e1SPrashanth Swaminathan                 Copyright (C) 2011 Kyle Moffett
5*1fd5a2e1SPrashanth Swaminathan                 Copyright (C) 2008 Red Hat, Inc
6*1fd5a2e1SPrashanth Swaminathan                 Copyright (C) 2007, 2008 Free Software Foundation, Inc
7*1fd5a2e1SPrashanth Swaminathan                 Copyright (c) 1998 Geoffrey Keating
8*1fd5a2e1SPrashanth Swaminathan 
9*1fd5a2e1SPrashanth Swaminathan    PowerPC Foreign Function Interface
10*1fd5a2e1SPrashanth Swaminathan 
11*1fd5a2e1SPrashanth Swaminathan    Permission is hereby granted, free of charge, to any person obtaining
12*1fd5a2e1SPrashanth Swaminathan    a copy of this software and associated documentation files (the
13*1fd5a2e1SPrashanth Swaminathan    ``Software''), to deal in the Software without restriction, including
14*1fd5a2e1SPrashanth Swaminathan    without limitation the rights to use, copy, modify, merge, publish,
15*1fd5a2e1SPrashanth Swaminathan    distribute, sublicense, and/or sell copies of the Software, and to
16*1fd5a2e1SPrashanth Swaminathan    permit persons to whom the Software is furnished to do so, subject to
17*1fd5a2e1SPrashanth Swaminathan    the following conditions:
18*1fd5a2e1SPrashanth Swaminathan 
19*1fd5a2e1SPrashanth Swaminathan    The above copyright notice and this permission notice shall be included
20*1fd5a2e1SPrashanth Swaminathan    in all copies or substantial portions of the Software.
21*1fd5a2e1SPrashanth Swaminathan 
22*1fd5a2e1SPrashanth Swaminathan    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
23*1fd5a2e1SPrashanth Swaminathan    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24*1fd5a2e1SPrashanth Swaminathan    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25*1fd5a2e1SPrashanth Swaminathan    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
26*1fd5a2e1SPrashanth Swaminathan    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
27*1fd5a2e1SPrashanth Swaminathan    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28*1fd5a2e1SPrashanth Swaminathan    OTHER DEALINGS IN THE SOFTWARE.
29*1fd5a2e1SPrashanth Swaminathan    ----------------------------------------------------------------------- */
30*1fd5a2e1SPrashanth Swaminathan 
31*1fd5a2e1SPrashanth Swaminathan #include "ffi.h"
32*1fd5a2e1SPrashanth Swaminathan 
33*1fd5a2e1SPrashanth Swaminathan #ifndef POWERPC64
34*1fd5a2e1SPrashanth Swaminathan #include "ffi_common.h"
35*1fd5a2e1SPrashanth Swaminathan #include "ffi_powerpc.h"
36*1fd5a2e1SPrashanth Swaminathan 
37*1fd5a2e1SPrashanth Swaminathan 
38*1fd5a2e1SPrashanth Swaminathan /* About the SYSV ABI.  */
39*1fd5a2e1SPrashanth Swaminathan #define ASM_NEEDS_REGISTERS 6
40*1fd5a2e1SPrashanth Swaminathan #define NUM_GPR_ARG_REGISTERS 8
41*1fd5a2e1SPrashanth Swaminathan #define NUM_FPR_ARG_REGISTERS 8
42*1fd5a2e1SPrashanth Swaminathan 
43*1fd5a2e1SPrashanth Swaminathan 
44*1fd5a2e1SPrashanth Swaminathan #if HAVE_LONG_DOUBLE_VARIANT && FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
45*1fd5a2e1SPrashanth Swaminathan /* Adjust size of ffi_type_longdouble.  */
46*1fd5a2e1SPrashanth Swaminathan void FFI_HIDDEN
ffi_prep_types_sysv(ffi_abi abi)47*1fd5a2e1SPrashanth Swaminathan ffi_prep_types_sysv (ffi_abi abi)
48*1fd5a2e1SPrashanth Swaminathan {
49*1fd5a2e1SPrashanth Swaminathan   if ((abi & (FFI_SYSV | FFI_SYSV_LONG_DOUBLE_128)) == FFI_SYSV)
50*1fd5a2e1SPrashanth Swaminathan     {
51*1fd5a2e1SPrashanth Swaminathan       ffi_type_longdouble.size = 8;
52*1fd5a2e1SPrashanth Swaminathan       ffi_type_longdouble.alignment = 8;
53*1fd5a2e1SPrashanth Swaminathan     }
54*1fd5a2e1SPrashanth Swaminathan   else
55*1fd5a2e1SPrashanth Swaminathan     {
56*1fd5a2e1SPrashanth Swaminathan       ffi_type_longdouble.size = 16;
57*1fd5a2e1SPrashanth Swaminathan       ffi_type_longdouble.alignment = 16;
58*1fd5a2e1SPrashanth Swaminathan     }
59*1fd5a2e1SPrashanth Swaminathan }
60*1fd5a2e1SPrashanth Swaminathan #endif
61*1fd5a2e1SPrashanth Swaminathan 
62*1fd5a2e1SPrashanth Swaminathan /* Transform long double, double and float to other types as per abi.  */
63*1fd5a2e1SPrashanth Swaminathan static int
translate_float(int abi,int type)64*1fd5a2e1SPrashanth Swaminathan translate_float (int abi, int type)
65*1fd5a2e1SPrashanth Swaminathan {
66*1fd5a2e1SPrashanth Swaminathan #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
67*1fd5a2e1SPrashanth Swaminathan   if (type == FFI_TYPE_LONGDOUBLE
68*1fd5a2e1SPrashanth Swaminathan       && (abi & FFI_SYSV_LONG_DOUBLE_128) == 0)
69*1fd5a2e1SPrashanth Swaminathan     type = FFI_TYPE_DOUBLE;
70*1fd5a2e1SPrashanth Swaminathan #endif
71*1fd5a2e1SPrashanth Swaminathan   if ((abi & FFI_SYSV_SOFT_FLOAT) != 0)
72*1fd5a2e1SPrashanth Swaminathan     {
73*1fd5a2e1SPrashanth Swaminathan       if (type == FFI_TYPE_FLOAT)
74*1fd5a2e1SPrashanth Swaminathan 	type = FFI_TYPE_UINT32;
75*1fd5a2e1SPrashanth Swaminathan       else if (type == FFI_TYPE_DOUBLE)
76*1fd5a2e1SPrashanth Swaminathan 	type = FFI_TYPE_UINT64;
77*1fd5a2e1SPrashanth Swaminathan #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
78*1fd5a2e1SPrashanth Swaminathan       else if (type == FFI_TYPE_LONGDOUBLE)
79*1fd5a2e1SPrashanth Swaminathan 	type = FFI_TYPE_UINT128;
80*1fd5a2e1SPrashanth Swaminathan     }
81*1fd5a2e1SPrashanth Swaminathan   else if ((abi & FFI_SYSV_IBM_LONG_DOUBLE) == 0)
82*1fd5a2e1SPrashanth Swaminathan     {
83*1fd5a2e1SPrashanth Swaminathan       if (type == FFI_TYPE_LONGDOUBLE)
84*1fd5a2e1SPrashanth Swaminathan 	type = FFI_TYPE_STRUCT;
85*1fd5a2e1SPrashanth Swaminathan #endif
86*1fd5a2e1SPrashanth Swaminathan     }
87*1fd5a2e1SPrashanth Swaminathan   return type;
88*1fd5a2e1SPrashanth Swaminathan }
89*1fd5a2e1SPrashanth Swaminathan 
90*1fd5a2e1SPrashanth Swaminathan /* Perform machine dependent cif processing */
91*1fd5a2e1SPrashanth Swaminathan static ffi_status
ffi_prep_cif_sysv_core(ffi_cif * cif)92*1fd5a2e1SPrashanth Swaminathan ffi_prep_cif_sysv_core (ffi_cif *cif)
93*1fd5a2e1SPrashanth Swaminathan {
94*1fd5a2e1SPrashanth Swaminathan   ffi_type **ptr;
95*1fd5a2e1SPrashanth Swaminathan   unsigned bytes;
96*1fd5a2e1SPrashanth Swaminathan   unsigned i, fpr_count = 0, gpr_count = 0, stack_count = 0;
97*1fd5a2e1SPrashanth Swaminathan   unsigned flags = cif->flags;
98*1fd5a2e1SPrashanth Swaminathan   unsigned struct_copy_size = 0;
99*1fd5a2e1SPrashanth Swaminathan   unsigned type = cif->rtype->type;
100*1fd5a2e1SPrashanth Swaminathan   unsigned size = cif->rtype->size;
101*1fd5a2e1SPrashanth Swaminathan 
102*1fd5a2e1SPrashanth Swaminathan   /* The machine-independent calculation of cif->bytes doesn't work
103*1fd5a2e1SPrashanth Swaminathan      for us.  Redo the calculation.  */
104*1fd5a2e1SPrashanth Swaminathan 
105*1fd5a2e1SPrashanth Swaminathan   /* Space for the frame pointer, callee's LR, and the asm's temp regs.  */
106*1fd5a2e1SPrashanth Swaminathan   bytes = (2 + ASM_NEEDS_REGISTERS) * sizeof (int);
107*1fd5a2e1SPrashanth Swaminathan 
108*1fd5a2e1SPrashanth Swaminathan   /* Space for the GPR registers.  */
109*1fd5a2e1SPrashanth Swaminathan   bytes += NUM_GPR_ARG_REGISTERS * sizeof (int);
110*1fd5a2e1SPrashanth Swaminathan 
111*1fd5a2e1SPrashanth Swaminathan   /* Return value handling.  The rules for SYSV are as follows:
112*1fd5a2e1SPrashanth Swaminathan      - 32-bit (or less) integer values are returned in gpr3;
113*1fd5a2e1SPrashanth Swaminathan      - Structures of size <= 4 bytes also returned in gpr3;
114*1fd5a2e1SPrashanth Swaminathan      - 64-bit integer values and structures between 5 and 8 bytes are returned
115*1fd5a2e1SPrashanth Swaminathan      in gpr3 and gpr4;
116*1fd5a2e1SPrashanth Swaminathan      - Larger structures are allocated space and a pointer is passed as
117*1fd5a2e1SPrashanth Swaminathan      the first argument.
118*1fd5a2e1SPrashanth Swaminathan      - Single/double FP values are returned in fpr1;
119*1fd5a2e1SPrashanth Swaminathan      - long doubles (if not equivalent to double) are returned in
120*1fd5a2e1SPrashanth Swaminathan      fpr1,fpr2 for Linux and as for large structs for SysV.  */
121*1fd5a2e1SPrashanth Swaminathan 
122*1fd5a2e1SPrashanth Swaminathan   type = translate_float (cif->abi, type);
123*1fd5a2e1SPrashanth Swaminathan 
124*1fd5a2e1SPrashanth Swaminathan   switch (type)
125*1fd5a2e1SPrashanth Swaminathan     {
126*1fd5a2e1SPrashanth Swaminathan #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
127*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_LONGDOUBLE:
128*1fd5a2e1SPrashanth Swaminathan       flags |= FLAG_RETURNS_128BITS;
129*1fd5a2e1SPrashanth Swaminathan       /* Fall through.  */
130*1fd5a2e1SPrashanth Swaminathan #endif
131*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_DOUBLE:
132*1fd5a2e1SPrashanth Swaminathan       flags |= FLAG_RETURNS_64BITS;
133*1fd5a2e1SPrashanth Swaminathan       /* Fall through.  */
134*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_FLOAT:
135*1fd5a2e1SPrashanth Swaminathan       flags |= FLAG_RETURNS_FP;
136*1fd5a2e1SPrashanth Swaminathan #ifdef __NO_FPRS__
137*1fd5a2e1SPrashanth Swaminathan       return FFI_BAD_ABI;
138*1fd5a2e1SPrashanth Swaminathan #endif
139*1fd5a2e1SPrashanth Swaminathan       break;
140*1fd5a2e1SPrashanth Swaminathan 
141*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT128:
142*1fd5a2e1SPrashanth Swaminathan       flags |= FLAG_RETURNS_128BITS;
143*1fd5a2e1SPrashanth Swaminathan       /* Fall through.  */
144*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT64:
145*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_SINT64:
146*1fd5a2e1SPrashanth Swaminathan       flags |= FLAG_RETURNS_64BITS;
147*1fd5a2e1SPrashanth Swaminathan       break;
148*1fd5a2e1SPrashanth Swaminathan 
149*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_STRUCT:
150*1fd5a2e1SPrashanth Swaminathan       /* The final SYSV ABI says that structures smaller or equal 8 bytes
151*1fd5a2e1SPrashanth Swaminathan 	 are returned in r3/r4.  A draft ABI used by linux instead
152*1fd5a2e1SPrashanth Swaminathan 	 returns them in memory.  */
153*1fd5a2e1SPrashanth Swaminathan       if ((cif->abi & FFI_SYSV_STRUCT_RET) != 0 && size <= 8)
154*1fd5a2e1SPrashanth Swaminathan 	{
155*1fd5a2e1SPrashanth Swaminathan 	  flags |= FLAG_RETURNS_SMST;
156*1fd5a2e1SPrashanth Swaminathan 	  break;
157*1fd5a2e1SPrashanth Swaminathan 	}
158*1fd5a2e1SPrashanth Swaminathan       gpr_count++;
159*1fd5a2e1SPrashanth Swaminathan       flags |= FLAG_RETVAL_REFERENCE;
160*1fd5a2e1SPrashanth Swaminathan       /* Fall through.  */
161*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_VOID:
162*1fd5a2e1SPrashanth Swaminathan       flags |= FLAG_RETURNS_NOTHING;
163*1fd5a2e1SPrashanth Swaminathan       break;
164*1fd5a2e1SPrashanth Swaminathan 
165*1fd5a2e1SPrashanth Swaminathan     default:
166*1fd5a2e1SPrashanth Swaminathan       /* Returns 32-bit integer, or similar.  Nothing to do here.  */
167*1fd5a2e1SPrashanth Swaminathan       break;
168*1fd5a2e1SPrashanth Swaminathan     }
169*1fd5a2e1SPrashanth Swaminathan 
170*1fd5a2e1SPrashanth Swaminathan   /* The first NUM_GPR_ARG_REGISTERS words of integer arguments, and the
171*1fd5a2e1SPrashanth Swaminathan      first NUM_FPR_ARG_REGISTERS fp arguments, go in registers; the rest
172*1fd5a2e1SPrashanth Swaminathan      goes on the stack.  Structures and long doubles (if not equivalent
173*1fd5a2e1SPrashanth Swaminathan      to double) are passed as a pointer to a copy of the structure.
174*1fd5a2e1SPrashanth Swaminathan      Stuff on the stack needs to keep proper alignment.  */
175*1fd5a2e1SPrashanth Swaminathan   for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
176*1fd5a2e1SPrashanth Swaminathan     {
177*1fd5a2e1SPrashanth Swaminathan       unsigned short typenum = (*ptr)->type;
178*1fd5a2e1SPrashanth Swaminathan 
179*1fd5a2e1SPrashanth Swaminathan       typenum = translate_float (cif->abi, typenum);
180*1fd5a2e1SPrashanth Swaminathan 
181*1fd5a2e1SPrashanth Swaminathan       switch (typenum)
182*1fd5a2e1SPrashanth Swaminathan 	{
183*1fd5a2e1SPrashanth Swaminathan #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
184*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_LONGDOUBLE:
185*1fd5a2e1SPrashanth Swaminathan 	  if (fpr_count >= NUM_FPR_ARG_REGISTERS - 1)
186*1fd5a2e1SPrashanth Swaminathan 	    {
187*1fd5a2e1SPrashanth Swaminathan 	      fpr_count = NUM_FPR_ARG_REGISTERS;
188*1fd5a2e1SPrashanth Swaminathan 	      /* 8-byte align long doubles.  */
189*1fd5a2e1SPrashanth Swaminathan 	      stack_count += stack_count & 1;
190*1fd5a2e1SPrashanth Swaminathan 	      stack_count += 4;
191*1fd5a2e1SPrashanth Swaminathan 	    }
192*1fd5a2e1SPrashanth Swaminathan 	  else
193*1fd5a2e1SPrashanth Swaminathan 	    fpr_count += 2;
194*1fd5a2e1SPrashanth Swaminathan #ifdef __NO_FPRS__
195*1fd5a2e1SPrashanth Swaminathan 	  return FFI_BAD_ABI;
196*1fd5a2e1SPrashanth Swaminathan #endif
197*1fd5a2e1SPrashanth Swaminathan 	  break;
198*1fd5a2e1SPrashanth Swaminathan #endif
199*1fd5a2e1SPrashanth Swaminathan 
200*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_DOUBLE:
201*1fd5a2e1SPrashanth Swaminathan 	  if (fpr_count >= NUM_FPR_ARG_REGISTERS)
202*1fd5a2e1SPrashanth Swaminathan 	    {
203*1fd5a2e1SPrashanth Swaminathan 	      /* 8-byte align doubles.  */
204*1fd5a2e1SPrashanth Swaminathan 	      stack_count += stack_count & 1;
205*1fd5a2e1SPrashanth Swaminathan 	      stack_count += 2;
206*1fd5a2e1SPrashanth Swaminathan 	    }
207*1fd5a2e1SPrashanth Swaminathan 	  else
208*1fd5a2e1SPrashanth Swaminathan 	    fpr_count += 1;
209*1fd5a2e1SPrashanth Swaminathan #ifdef __NO_FPRS__
210*1fd5a2e1SPrashanth Swaminathan 	  return FFI_BAD_ABI;
211*1fd5a2e1SPrashanth Swaminathan #endif
212*1fd5a2e1SPrashanth Swaminathan 	  break;
213*1fd5a2e1SPrashanth Swaminathan 
214*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_FLOAT:
215*1fd5a2e1SPrashanth Swaminathan 	  if (fpr_count >= NUM_FPR_ARG_REGISTERS)
216*1fd5a2e1SPrashanth Swaminathan 	    /* Yes, we don't follow the ABI, but neither does gcc.  */
217*1fd5a2e1SPrashanth Swaminathan 	    stack_count += 1;
218*1fd5a2e1SPrashanth Swaminathan 	  else
219*1fd5a2e1SPrashanth Swaminathan 	    fpr_count += 1;
220*1fd5a2e1SPrashanth Swaminathan #ifdef __NO_FPRS__
221*1fd5a2e1SPrashanth Swaminathan 	  return FFI_BAD_ABI;
222*1fd5a2e1SPrashanth Swaminathan #endif
223*1fd5a2e1SPrashanth Swaminathan 	  break;
224*1fd5a2e1SPrashanth Swaminathan 
225*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT128:
226*1fd5a2e1SPrashanth Swaminathan 	  /* A long double in FFI_LINUX_SOFT_FLOAT can use only a set
227*1fd5a2e1SPrashanth Swaminathan 	     of four consecutive gprs. If we do not have enough, we
228*1fd5a2e1SPrashanth Swaminathan 	     have to adjust the gpr_count value.  */
229*1fd5a2e1SPrashanth Swaminathan 	  if (gpr_count >= NUM_GPR_ARG_REGISTERS - 3)
230*1fd5a2e1SPrashanth Swaminathan 	    gpr_count = NUM_GPR_ARG_REGISTERS;
231*1fd5a2e1SPrashanth Swaminathan 	  if (gpr_count >= NUM_GPR_ARG_REGISTERS)
232*1fd5a2e1SPrashanth Swaminathan 	    stack_count += 4;
233*1fd5a2e1SPrashanth Swaminathan 	  else
234*1fd5a2e1SPrashanth Swaminathan 	    gpr_count += 4;
235*1fd5a2e1SPrashanth Swaminathan 	  break;
236*1fd5a2e1SPrashanth Swaminathan 
237*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT64:
238*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT64:
239*1fd5a2e1SPrashanth Swaminathan 	  /* 'long long' arguments are passed as two words, but
240*1fd5a2e1SPrashanth Swaminathan 	     either both words must fit in registers or both go
241*1fd5a2e1SPrashanth Swaminathan 	     on the stack.  If they go on the stack, they must
242*1fd5a2e1SPrashanth Swaminathan 	     be 8-byte-aligned.
243*1fd5a2e1SPrashanth Swaminathan 
244*1fd5a2e1SPrashanth Swaminathan 	     Also, only certain register pairs can be used for
245*1fd5a2e1SPrashanth Swaminathan 	     passing long long int -- specifically (r3,r4), (r5,r6),
246*1fd5a2e1SPrashanth Swaminathan 	     (r7,r8), (r9,r10).  */
247*1fd5a2e1SPrashanth Swaminathan 	  gpr_count += gpr_count & 1;
248*1fd5a2e1SPrashanth Swaminathan 	  if (gpr_count >= NUM_GPR_ARG_REGISTERS)
249*1fd5a2e1SPrashanth Swaminathan 	    {
250*1fd5a2e1SPrashanth Swaminathan 	      stack_count += stack_count & 1;
251*1fd5a2e1SPrashanth Swaminathan 	      stack_count += 2;
252*1fd5a2e1SPrashanth Swaminathan 	    }
253*1fd5a2e1SPrashanth Swaminathan 	  else
254*1fd5a2e1SPrashanth Swaminathan 	    gpr_count += 2;
255*1fd5a2e1SPrashanth Swaminathan 	  break;
256*1fd5a2e1SPrashanth Swaminathan 
257*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_STRUCT:
258*1fd5a2e1SPrashanth Swaminathan 	  /* We must allocate space for a copy of these to enforce
259*1fd5a2e1SPrashanth Swaminathan 	     pass-by-value.  Pad the space up to a multiple of 16
260*1fd5a2e1SPrashanth Swaminathan 	     bytes (the maximum alignment required for anything under
261*1fd5a2e1SPrashanth Swaminathan 	     the SYSV ABI).  */
262*1fd5a2e1SPrashanth Swaminathan 	  struct_copy_size += ((*ptr)->size + 15) & ~0xF;
263*1fd5a2e1SPrashanth Swaminathan 	  /* Fall through (allocate space for the pointer).  */
264*1fd5a2e1SPrashanth Swaminathan 
265*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_POINTER:
266*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_INT:
267*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT32:
268*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT32:
269*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT16:
270*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT16:
271*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT8:
272*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT8:
273*1fd5a2e1SPrashanth Swaminathan 	  /* Everything else is passed as a 4-byte word in a GPR, either
274*1fd5a2e1SPrashanth Swaminathan 	     the object itself or a pointer to it.  */
275*1fd5a2e1SPrashanth Swaminathan 	  if (gpr_count >= NUM_GPR_ARG_REGISTERS)
276*1fd5a2e1SPrashanth Swaminathan 	    stack_count += 1;
277*1fd5a2e1SPrashanth Swaminathan 	  else
278*1fd5a2e1SPrashanth Swaminathan 	    gpr_count += 1;
279*1fd5a2e1SPrashanth Swaminathan 	  break;
280*1fd5a2e1SPrashanth Swaminathan 
281*1fd5a2e1SPrashanth Swaminathan 	default:
282*1fd5a2e1SPrashanth Swaminathan 	  FFI_ASSERT (0);
283*1fd5a2e1SPrashanth Swaminathan 	}
284*1fd5a2e1SPrashanth Swaminathan     }
285*1fd5a2e1SPrashanth Swaminathan 
286*1fd5a2e1SPrashanth Swaminathan   if (fpr_count != 0)
287*1fd5a2e1SPrashanth Swaminathan     flags |= FLAG_FP_ARGUMENTS;
288*1fd5a2e1SPrashanth Swaminathan   if (gpr_count > 4)
289*1fd5a2e1SPrashanth Swaminathan     flags |= FLAG_4_GPR_ARGUMENTS;
290*1fd5a2e1SPrashanth Swaminathan   if (struct_copy_size != 0)
291*1fd5a2e1SPrashanth Swaminathan     flags |= FLAG_ARG_NEEDS_COPY;
292*1fd5a2e1SPrashanth Swaminathan 
293*1fd5a2e1SPrashanth Swaminathan   /* Space for the FPR registers, if needed.  */
294*1fd5a2e1SPrashanth Swaminathan   if (fpr_count != 0)
295*1fd5a2e1SPrashanth Swaminathan     bytes += NUM_FPR_ARG_REGISTERS * sizeof (double);
296*1fd5a2e1SPrashanth Swaminathan 
297*1fd5a2e1SPrashanth Swaminathan   /* Stack space.  */
298*1fd5a2e1SPrashanth Swaminathan   bytes += stack_count * sizeof (int);
299*1fd5a2e1SPrashanth Swaminathan 
300*1fd5a2e1SPrashanth Swaminathan   /* The stack space allocated needs to be a multiple of 16 bytes.  */
301*1fd5a2e1SPrashanth Swaminathan   bytes = (bytes + 15) & ~0xF;
302*1fd5a2e1SPrashanth Swaminathan 
303*1fd5a2e1SPrashanth Swaminathan   /* Add in the space for the copied structures.  */
304*1fd5a2e1SPrashanth Swaminathan   bytes += struct_copy_size;
305*1fd5a2e1SPrashanth Swaminathan 
306*1fd5a2e1SPrashanth Swaminathan   cif->flags = flags;
307*1fd5a2e1SPrashanth Swaminathan   cif->bytes = bytes;
308*1fd5a2e1SPrashanth Swaminathan 
309*1fd5a2e1SPrashanth Swaminathan   return FFI_OK;
310*1fd5a2e1SPrashanth Swaminathan }
311*1fd5a2e1SPrashanth Swaminathan 
312*1fd5a2e1SPrashanth Swaminathan ffi_status FFI_HIDDEN
ffi_prep_cif_sysv(ffi_cif * cif)313*1fd5a2e1SPrashanth Swaminathan ffi_prep_cif_sysv (ffi_cif *cif)
314*1fd5a2e1SPrashanth Swaminathan {
315*1fd5a2e1SPrashanth Swaminathan   if ((cif->abi & FFI_SYSV) == 0)
316*1fd5a2e1SPrashanth Swaminathan     {
317*1fd5a2e1SPrashanth Swaminathan       /* This call is from old code.  Translate to new ABI values.  */
318*1fd5a2e1SPrashanth Swaminathan       cif->flags |= FLAG_COMPAT;
319*1fd5a2e1SPrashanth Swaminathan       switch (cif->abi)
320*1fd5a2e1SPrashanth Swaminathan 	{
321*1fd5a2e1SPrashanth Swaminathan 	default:
322*1fd5a2e1SPrashanth Swaminathan 	  return FFI_BAD_ABI;
323*1fd5a2e1SPrashanth Swaminathan 
324*1fd5a2e1SPrashanth Swaminathan 	case FFI_COMPAT_SYSV:
325*1fd5a2e1SPrashanth Swaminathan 	  cif->abi = FFI_SYSV | FFI_SYSV_STRUCT_RET | FFI_SYSV_LONG_DOUBLE_128;
326*1fd5a2e1SPrashanth Swaminathan 	  break;
327*1fd5a2e1SPrashanth Swaminathan 
328*1fd5a2e1SPrashanth Swaminathan 	case FFI_COMPAT_GCC_SYSV:
329*1fd5a2e1SPrashanth Swaminathan 	  cif->abi = FFI_SYSV | FFI_SYSV_LONG_DOUBLE_128;
330*1fd5a2e1SPrashanth Swaminathan 	  break;
331*1fd5a2e1SPrashanth Swaminathan 
332*1fd5a2e1SPrashanth Swaminathan 	case FFI_COMPAT_LINUX:
333*1fd5a2e1SPrashanth Swaminathan 	  cif->abi = (FFI_SYSV | FFI_SYSV_IBM_LONG_DOUBLE
334*1fd5a2e1SPrashanth Swaminathan 		      | FFI_SYSV_LONG_DOUBLE_128);
335*1fd5a2e1SPrashanth Swaminathan 	  break;
336*1fd5a2e1SPrashanth Swaminathan 
337*1fd5a2e1SPrashanth Swaminathan 	case FFI_COMPAT_LINUX_SOFT_FLOAT:
338*1fd5a2e1SPrashanth Swaminathan 	  cif->abi = (FFI_SYSV | FFI_SYSV_SOFT_FLOAT | FFI_SYSV_IBM_LONG_DOUBLE
339*1fd5a2e1SPrashanth Swaminathan 		      | FFI_SYSV_LONG_DOUBLE_128);
340*1fd5a2e1SPrashanth Swaminathan 	  break;
341*1fd5a2e1SPrashanth Swaminathan 	}
342*1fd5a2e1SPrashanth Swaminathan     }
343*1fd5a2e1SPrashanth Swaminathan   return ffi_prep_cif_sysv_core (cif);
344*1fd5a2e1SPrashanth Swaminathan }
345*1fd5a2e1SPrashanth Swaminathan 
346*1fd5a2e1SPrashanth Swaminathan /* ffi_prep_args_SYSV is called by the assembly routine once stack space
347*1fd5a2e1SPrashanth Swaminathan    has been allocated for the function's arguments.
348*1fd5a2e1SPrashanth Swaminathan 
349*1fd5a2e1SPrashanth Swaminathan    The stack layout we want looks like this:
350*1fd5a2e1SPrashanth Swaminathan 
351*1fd5a2e1SPrashanth Swaminathan    |   Return address from ffi_call_SYSV 4bytes	|	higher addresses
352*1fd5a2e1SPrashanth Swaminathan    |--------------------------------------------|
353*1fd5a2e1SPrashanth Swaminathan    |   Previous backchain pointer	4	|       stack pointer here
354*1fd5a2e1SPrashanth Swaminathan    |--------------------------------------------|<+ <<<	on entry to
355*1fd5a2e1SPrashanth Swaminathan    |   Saved r28-r31			4*4	| |	ffi_call_SYSV
356*1fd5a2e1SPrashanth Swaminathan    |--------------------------------------------| |
357*1fd5a2e1SPrashanth Swaminathan    |   GPR registers r3-r10		8*4	| |	ffi_call_SYSV
358*1fd5a2e1SPrashanth Swaminathan    |--------------------------------------------| |
359*1fd5a2e1SPrashanth Swaminathan    |   FPR registers f1-f8 (optional)	8*8	| |
360*1fd5a2e1SPrashanth Swaminathan    |--------------------------------------------| |	stack	|
361*1fd5a2e1SPrashanth Swaminathan    |   Space for copied structures		| |	grows	|
362*1fd5a2e1SPrashanth Swaminathan    |--------------------------------------------| |	down    V
363*1fd5a2e1SPrashanth Swaminathan    |   Parameters that didn't fit in registers  | |
364*1fd5a2e1SPrashanth Swaminathan    |--------------------------------------------| |	lower addresses
365*1fd5a2e1SPrashanth Swaminathan    |   Space for callee's LR		4	| |
366*1fd5a2e1SPrashanth Swaminathan    |--------------------------------------------| |	stack pointer here
367*1fd5a2e1SPrashanth Swaminathan    |   Current backchain pointer	4	|-/	during
368*1fd5a2e1SPrashanth Swaminathan    |--------------------------------------------|   <<<	ffi_call_SYSV
369*1fd5a2e1SPrashanth Swaminathan 
370*1fd5a2e1SPrashanth Swaminathan */
371*1fd5a2e1SPrashanth Swaminathan 
372*1fd5a2e1SPrashanth Swaminathan void FFI_HIDDEN
ffi_prep_args_SYSV(extended_cif * ecif,unsigned * const stack)373*1fd5a2e1SPrashanth Swaminathan ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
374*1fd5a2e1SPrashanth Swaminathan {
375*1fd5a2e1SPrashanth Swaminathan   const unsigned bytes = ecif->cif->bytes;
376*1fd5a2e1SPrashanth Swaminathan   const unsigned flags = ecif->cif->flags;
377*1fd5a2e1SPrashanth Swaminathan 
378*1fd5a2e1SPrashanth Swaminathan   typedef union
379*1fd5a2e1SPrashanth Swaminathan   {
380*1fd5a2e1SPrashanth Swaminathan     char *c;
381*1fd5a2e1SPrashanth Swaminathan     unsigned *u;
382*1fd5a2e1SPrashanth Swaminathan     long long *ll;
383*1fd5a2e1SPrashanth Swaminathan     float *f;
384*1fd5a2e1SPrashanth Swaminathan     double *d;
385*1fd5a2e1SPrashanth Swaminathan   } valp;
386*1fd5a2e1SPrashanth Swaminathan 
387*1fd5a2e1SPrashanth Swaminathan   /* 'stacktop' points at the previous backchain pointer.  */
388*1fd5a2e1SPrashanth Swaminathan   valp stacktop;
389*1fd5a2e1SPrashanth Swaminathan 
390*1fd5a2e1SPrashanth Swaminathan   /* 'gpr_base' points at the space for gpr3, and grows upwards as
391*1fd5a2e1SPrashanth Swaminathan      we use GPR registers.  */
392*1fd5a2e1SPrashanth Swaminathan   valp gpr_base;
393*1fd5a2e1SPrashanth Swaminathan   valp gpr_end;
394*1fd5a2e1SPrashanth Swaminathan 
395*1fd5a2e1SPrashanth Swaminathan #ifndef __NO_FPRS__
396*1fd5a2e1SPrashanth Swaminathan   /* 'fpr_base' points at the space for fpr1, and grows upwards as
397*1fd5a2e1SPrashanth Swaminathan      we use FPR registers.  */
398*1fd5a2e1SPrashanth Swaminathan   valp fpr_base;
399*1fd5a2e1SPrashanth Swaminathan   valp fpr_end;
400*1fd5a2e1SPrashanth Swaminathan #endif
401*1fd5a2e1SPrashanth Swaminathan 
402*1fd5a2e1SPrashanth Swaminathan   /* 'copy_space' grows down as we put structures in it.  It should
403*1fd5a2e1SPrashanth Swaminathan      stay 16-byte aligned.  */
404*1fd5a2e1SPrashanth Swaminathan   valp copy_space;
405*1fd5a2e1SPrashanth Swaminathan 
406*1fd5a2e1SPrashanth Swaminathan   /* 'next_arg' grows up as we put parameters in it.  */
407*1fd5a2e1SPrashanth Swaminathan   valp next_arg;
408*1fd5a2e1SPrashanth Swaminathan 
409*1fd5a2e1SPrashanth Swaminathan   int i;
410*1fd5a2e1SPrashanth Swaminathan   ffi_type **ptr;
411*1fd5a2e1SPrashanth Swaminathan #ifndef __NO_FPRS__
412*1fd5a2e1SPrashanth Swaminathan   double double_tmp;
413*1fd5a2e1SPrashanth Swaminathan #endif
414*1fd5a2e1SPrashanth Swaminathan   union
415*1fd5a2e1SPrashanth Swaminathan   {
416*1fd5a2e1SPrashanth Swaminathan     void **v;
417*1fd5a2e1SPrashanth Swaminathan     char **c;
418*1fd5a2e1SPrashanth Swaminathan     signed char **sc;
419*1fd5a2e1SPrashanth Swaminathan     unsigned char **uc;
420*1fd5a2e1SPrashanth Swaminathan     signed short **ss;
421*1fd5a2e1SPrashanth Swaminathan     unsigned short **us;
422*1fd5a2e1SPrashanth Swaminathan     unsigned int **ui;
423*1fd5a2e1SPrashanth Swaminathan     long long **ll;
424*1fd5a2e1SPrashanth Swaminathan     float **f;
425*1fd5a2e1SPrashanth Swaminathan     double **d;
426*1fd5a2e1SPrashanth Swaminathan   } p_argv;
427*1fd5a2e1SPrashanth Swaminathan   size_t struct_copy_size;
428*1fd5a2e1SPrashanth Swaminathan   unsigned gprvalue;
429*1fd5a2e1SPrashanth Swaminathan 
430*1fd5a2e1SPrashanth Swaminathan   stacktop.c = (char *) stack + bytes;
431*1fd5a2e1SPrashanth Swaminathan   gpr_end.u = stacktop.u - ASM_NEEDS_REGISTERS;
432*1fd5a2e1SPrashanth Swaminathan   gpr_base.u = gpr_end.u - NUM_GPR_ARG_REGISTERS;
433*1fd5a2e1SPrashanth Swaminathan #ifndef __NO_FPRS__
434*1fd5a2e1SPrashanth Swaminathan   fpr_end.d = gpr_base.d;
435*1fd5a2e1SPrashanth Swaminathan   fpr_base.d = fpr_end.d - NUM_FPR_ARG_REGISTERS;
436*1fd5a2e1SPrashanth Swaminathan   copy_space.c = ((flags & FLAG_FP_ARGUMENTS) ? fpr_base.c : gpr_base.c);
437*1fd5a2e1SPrashanth Swaminathan #else
438*1fd5a2e1SPrashanth Swaminathan   copy_space.c = gpr_base.c;
439*1fd5a2e1SPrashanth Swaminathan #endif
440*1fd5a2e1SPrashanth Swaminathan   next_arg.u = stack + 2;
441*1fd5a2e1SPrashanth Swaminathan 
442*1fd5a2e1SPrashanth Swaminathan   /* Check that everything starts aligned properly.  */
443*1fd5a2e1SPrashanth Swaminathan   FFI_ASSERT (((unsigned long) (char *) stack & 0xF) == 0);
444*1fd5a2e1SPrashanth Swaminathan   FFI_ASSERT (((unsigned long) copy_space.c & 0xF) == 0);
445*1fd5a2e1SPrashanth Swaminathan   FFI_ASSERT (((unsigned long) stacktop.c & 0xF) == 0);
446*1fd5a2e1SPrashanth Swaminathan   FFI_ASSERT ((bytes & 0xF) == 0);
447*1fd5a2e1SPrashanth Swaminathan   FFI_ASSERT (copy_space.c >= next_arg.c);
448*1fd5a2e1SPrashanth Swaminathan 
449*1fd5a2e1SPrashanth Swaminathan   /* Deal with return values that are actually pass-by-reference.  */
450*1fd5a2e1SPrashanth Swaminathan   if (flags & FLAG_RETVAL_REFERENCE)
451*1fd5a2e1SPrashanth Swaminathan     *gpr_base.u++ = (unsigned) (char *) ecif->rvalue;
452*1fd5a2e1SPrashanth Swaminathan 
453*1fd5a2e1SPrashanth Swaminathan   /* Now for the arguments.  */
454*1fd5a2e1SPrashanth Swaminathan   p_argv.v = ecif->avalue;
455*1fd5a2e1SPrashanth Swaminathan   for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
456*1fd5a2e1SPrashanth Swaminathan        i > 0;
457*1fd5a2e1SPrashanth Swaminathan        i--, ptr++, p_argv.v++)
458*1fd5a2e1SPrashanth Swaminathan     {
459*1fd5a2e1SPrashanth Swaminathan       unsigned int typenum = (*ptr)->type;
460*1fd5a2e1SPrashanth Swaminathan 
461*1fd5a2e1SPrashanth Swaminathan       typenum = translate_float (ecif->cif->abi, typenum);
462*1fd5a2e1SPrashanth Swaminathan 
463*1fd5a2e1SPrashanth Swaminathan       /* Now test the translated value */
464*1fd5a2e1SPrashanth Swaminathan       switch (typenum)
465*1fd5a2e1SPrashanth Swaminathan 	{
466*1fd5a2e1SPrashanth Swaminathan #ifndef __NO_FPRS__
467*1fd5a2e1SPrashanth Swaminathan # if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
468*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_LONGDOUBLE:
469*1fd5a2e1SPrashanth Swaminathan 	  double_tmp = (*p_argv.d)[0];
470*1fd5a2e1SPrashanth Swaminathan 
471*1fd5a2e1SPrashanth Swaminathan 	  if (fpr_base.d >= fpr_end.d - 1)
472*1fd5a2e1SPrashanth Swaminathan 	    {
473*1fd5a2e1SPrashanth Swaminathan 	      fpr_base.d = fpr_end.d;
474*1fd5a2e1SPrashanth Swaminathan 	      if (((next_arg.u - stack) & 1) != 0)
475*1fd5a2e1SPrashanth Swaminathan 		next_arg.u += 1;
476*1fd5a2e1SPrashanth Swaminathan 	      *next_arg.d = double_tmp;
477*1fd5a2e1SPrashanth Swaminathan 	      next_arg.u += 2;
478*1fd5a2e1SPrashanth Swaminathan 	      double_tmp = (*p_argv.d)[1];
479*1fd5a2e1SPrashanth Swaminathan 	      *next_arg.d = double_tmp;
480*1fd5a2e1SPrashanth Swaminathan 	      next_arg.u += 2;
481*1fd5a2e1SPrashanth Swaminathan 	    }
482*1fd5a2e1SPrashanth Swaminathan 	  else
483*1fd5a2e1SPrashanth Swaminathan 	    {
484*1fd5a2e1SPrashanth Swaminathan 	      *fpr_base.d++ = double_tmp;
485*1fd5a2e1SPrashanth Swaminathan 	      double_tmp = (*p_argv.d)[1];
486*1fd5a2e1SPrashanth Swaminathan 	      *fpr_base.d++ = double_tmp;
487*1fd5a2e1SPrashanth Swaminathan 	    }
488*1fd5a2e1SPrashanth Swaminathan 	  FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
489*1fd5a2e1SPrashanth Swaminathan 	  break;
490*1fd5a2e1SPrashanth Swaminathan # endif
491*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_DOUBLE:
492*1fd5a2e1SPrashanth Swaminathan 	  double_tmp = **p_argv.d;
493*1fd5a2e1SPrashanth Swaminathan 
494*1fd5a2e1SPrashanth Swaminathan 	  if (fpr_base.d >= fpr_end.d)
495*1fd5a2e1SPrashanth Swaminathan 	    {
496*1fd5a2e1SPrashanth Swaminathan 	      if (((next_arg.u - stack) & 1) != 0)
497*1fd5a2e1SPrashanth Swaminathan 		next_arg.u += 1;
498*1fd5a2e1SPrashanth Swaminathan 	      *next_arg.d = double_tmp;
499*1fd5a2e1SPrashanth Swaminathan 	      next_arg.u += 2;
500*1fd5a2e1SPrashanth Swaminathan 	    }
501*1fd5a2e1SPrashanth Swaminathan 	  else
502*1fd5a2e1SPrashanth Swaminathan 	    *fpr_base.d++ = double_tmp;
503*1fd5a2e1SPrashanth Swaminathan 	  FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
504*1fd5a2e1SPrashanth Swaminathan 	  break;
505*1fd5a2e1SPrashanth Swaminathan 
506*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_FLOAT:
507*1fd5a2e1SPrashanth Swaminathan 	  double_tmp = **p_argv.f;
508*1fd5a2e1SPrashanth Swaminathan 	  if (fpr_base.d >= fpr_end.d)
509*1fd5a2e1SPrashanth Swaminathan 	    {
510*1fd5a2e1SPrashanth Swaminathan 	      *next_arg.f = (float) double_tmp;
511*1fd5a2e1SPrashanth Swaminathan 	      next_arg.u += 1;
512*1fd5a2e1SPrashanth Swaminathan 	    }
513*1fd5a2e1SPrashanth Swaminathan 	  else
514*1fd5a2e1SPrashanth Swaminathan 	    *fpr_base.d++ = double_tmp;
515*1fd5a2e1SPrashanth Swaminathan 	  FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
516*1fd5a2e1SPrashanth Swaminathan 	  break;
517*1fd5a2e1SPrashanth Swaminathan #endif /* have FPRs */
518*1fd5a2e1SPrashanth Swaminathan 
519*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT128:
520*1fd5a2e1SPrashanth Swaminathan 	  /* The soft float ABI for long doubles works like this, a long double
521*1fd5a2e1SPrashanth Swaminathan 	     is passed in four consecutive GPRs if available.  A maximum of 2
522*1fd5a2e1SPrashanth Swaminathan 	     long doubles can be passed in gprs.  If we do not have 4 GPRs
523*1fd5a2e1SPrashanth Swaminathan 	     left, the long double is passed on the stack, 4-byte aligned.  */
524*1fd5a2e1SPrashanth Swaminathan 	  if (gpr_base.u >= gpr_end.u - 3)
525*1fd5a2e1SPrashanth Swaminathan 	    {
526*1fd5a2e1SPrashanth Swaminathan 	      unsigned int ii;
527*1fd5a2e1SPrashanth Swaminathan 	      gpr_base.u = gpr_end.u;
528*1fd5a2e1SPrashanth Swaminathan 	      for (ii = 0; ii < 4; ii++)
529*1fd5a2e1SPrashanth Swaminathan 		{
530*1fd5a2e1SPrashanth Swaminathan 		  unsigned int int_tmp = (*p_argv.ui)[ii];
531*1fd5a2e1SPrashanth Swaminathan 		  *next_arg.u++ = int_tmp;
532*1fd5a2e1SPrashanth Swaminathan 		}
533*1fd5a2e1SPrashanth Swaminathan 	    }
534*1fd5a2e1SPrashanth Swaminathan 	  else
535*1fd5a2e1SPrashanth Swaminathan 	    {
536*1fd5a2e1SPrashanth Swaminathan 	      unsigned int ii;
537*1fd5a2e1SPrashanth Swaminathan 	      for (ii = 0; ii < 4; ii++)
538*1fd5a2e1SPrashanth Swaminathan 		{
539*1fd5a2e1SPrashanth Swaminathan 		  unsigned int int_tmp = (*p_argv.ui)[ii];
540*1fd5a2e1SPrashanth Swaminathan 		  *gpr_base.u++ = int_tmp;
541*1fd5a2e1SPrashanth Swaminathan 		}
542*1fd5a2e1SPrashanth Swaminathan 	    }
543*1fd5a2e1SPrashanth Swaminathan 	  break;
544*1fd5a2e1SPrashanth Swaminathan 
545*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT64:
546*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT64:
547*1fd5a2e1SPrashanth Swaminathan 	  if (gpr_base.u >= gpr_end.u - 1)
548*1fd5a2e1SPrashanth Swaminathan 	    {
549*1fd5a2e1SPrashanth Swaminathan 	      gpr_base.u = gpr_end.u;
550*1fd5a2e1SPrashanth Swaminathan 	      if (((next_arg.u - stack) & 1) != 0)
551*1fd5a2e1SPrashanth Swaminathan 		next_arg.u++;
552*1fd5a2e1SPrashanth Swaminathan 	      *next_arg.ll = **p_argv.ll;
553*1fd5a2e1SPrashanth Swaminathan 	      next_arg.u += 2;
554*1fd5a2e1SPrashanth Swaminathan 	    }
555*1fd5a2e1SPrashanth Swaminathan 	  else
556*1fd5a2e1SPrashanth Swaminathan 	    {
557*1fd5a2e1SPrashanth Swaminathan 	      /* The abi states only certain register pairs can be
558*1fd5a2e1SPrashanth Swaminathan 		 used for passing long long int specifically (r3,r4),
559*1fd5a2e1SPrashanth Swaminathan 		 (r5,r6), (r7,r8), (r9,r10).  If next arg is long long
560*1fd5a2e1SPrashanth Swaminathan 		 but not correct starting register of pair then skip
561*1fd5a2e1SPrashanth Swaminathan 		 until the proper starting register.  */
562*1fd5a2e1SPrashanth Swaminathan 	      if (((gpr_end.u - gpr_base.u) & 1) != 0)
563*1fd5a2e1SPrashanth Swaminathan 		gpr_base.u++;
564*1fd5a2e1SPrashanth Swaminathan 	      *gpr_base.ll++ = **p_argv.ll;
565*1fd5a2e1SPrashanth Swaminathan 	    }
566*1fd5a2e1SPrashanth Swaminathan 	  break;
567*1fd5a2e1SPrashanth Swaminathan 
568*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_STRUCT:
569*1fd5a2e1SPrashanth Swaminathan 	  struct_copy_size = ((*ptr)->size + 15) & ~0xF;
570*1fd5a2e1SPrashanth Swaminathan 	  copy_space.c -= struct_copy_size;
571*1fd5a2e1SPrashanth Swaminathan 	  memcpy (copy_space.c, *p_argv.c, (*ptr)->size);
572*1fd5a2e1SPrashanth Swaminathan 
573*1fd5a2e1SPrashanth Swaminathan 	  gprvalue = (unsigned long) copy_space.c;
574*1fd5a2e1SPrashanth Swaminathan 
575*1fd5a2e1SPrashanth Swaminathan 	  FFI_ASSERT (copy_space.c > next_arg.c);
576*1fd5a2e1SPrashanth Swaminathan 	  FFI_ASSERT (flags & FLAG_ARG_NEEDS_COPY);
577*1fd5a2e1SPrashanth Swaminathan 	  goto putgpr;
578*1fd5a2e1SPrashanth Swaminathan 
579*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT8:
580*1fd5a2e1SPrashanth Swaminathan 	  gprvalue = **p_argv.uc;
581*1fd5a2e1SPrashanth Swaminathan 	  goto putgpr;
582*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT8:
583*1fd5a2e1SPrashanth Swaminathan 	  gprvalue = **p_argv.sc;
584*1fd5a2e1SPrashanth Swaminathan 	  goto putgpr;
585*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT16:
586*1fd5a2e1SPrashanth Swaminathan 	  gprvalue = **p_argv.us;
587*1fd5a2e1SPrashanth Swaminathan 	  goto putgpr;
588*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT16:
589*1fd5a2e1SPrashanth Swaminathan 	  gprvalue = **p_argv.ss;
590*1fd5a2e1SPrashanth Swaminathan 	  goto putgpr;
591*1fd5a2e1SPrashanth Swaminathan 
592*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_INT:
593*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT32:
594*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT32:
595*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_POINTER:
596*1fd5a2e1SPrashanth Swaminathan 
597*1fd5a2e1SPrashanth Swaminathan 	  gprvalue = **p_argv.ui;
598*1fd5a2e1SPrashanth Swaminathan 
599*1fd5a2e1SPrashanth Swaminathan 	putgpr:
600*1fd5a2e1SPrashanth Swaminathan 	  if (gpr_base.u >= gpr_end.u)
601*1fd5a2e1SPrashanth Swaminathan 	    *next_arg.u++ = gprvalue;
602*1fd5a2e1SPrashanth Swaminathan 	  else
603*1fd5a2e1SPrashanth Swaminathan 	    *gpr_base.u++ = gprvalue;
604*1fd5a2e1SPrashanth Swaminathan 	  break;
605*1fd5a2e1SPrashanth Swaminathan 	}
606*1fd5a2e1SPrashanth Swaminathan     }
607*1fd5a2e1SPrashanth Swaminathan 
608*1fd5a2e1SPrashanth Swaminathan   /* Check that we didn't overrun the stack...  */
609*1fd5a2e1SPrashanth Swaminathan   FFI_ASSERT (copy_space.c >= next_arg.c);
610*1fd5a2e1SPrashanth Swaminathan   FFI_ASSERT (gpr_base.u <= gpr_end.u);
611*1fd5a2e1SPrashanth Swaminathan #ifndef __NO_FPRS__
612*1fd5a2e1SPrashanth Swaminathan   FFI_ASSERT (fpr_base.u <= fpr_end.u);
613*1fd5a2e1SPrashanth Swaminathan #endif
614*1fd5a2e1SPrashanth Swaminathan   FFI_ASSERT (((flags & FLAG_4_GPR_ARGUMENTS) != 0)
615*1fd5a2e1SPrashanth Swaminathan 	      == (gpr_end.u - gpr_base.u < 4));
616*1fd5a2e1SPrashanth Swaminathan }
617*1fd5a2e1SPrashanth Swaminathan 
618*1fd5a2e1SPrashanth Swaminathan #define MIN_CACHE_LINE_SIZE 8
619*1fd5a2e1SPrashanth Swaminathan 
620*1fd5a2e1SPrashanth Swaminathan static void
flush_icache(char * wraddr,char * xaddr,int size)621*1fd5a2e1SPrashanth Swaminathan flush_icache (char *wraddr, char *xaddr, int size)
622*1fd5a2e1SPrashanth Swaminathan {
623*1fd5a2e1SPrashanth Swaminathan   int i;
624*1fd5a2e1SPrashanth Swaminathan   for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE)
625*1fd5a2e1SPrashanth Swaminathan     __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;"
626*1fd5a2e1SPrashanth Swaminathan 		      : : "r" (xaddr + i), "r" (wraddr + i) : "memory");
627*1fd5a2e1SPrashanth Swaminathan   __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;" "sync;" "isync;"
628*1fd5a2e1SPrashanth Swaminathan 		    : : "r"(xaddr + size - 1), "r"(wraddr + size - 1)
629*1fd5a2e1SPrashanth Swaminathan 		    : "memory");
630*1fd5a2e1SPrashanth Swaminathan }
631*1fd5a2e1SPrashanth Swaminathan 
632*1fd5a2e1SPrashanth Swaminathan ffi_status FFI_HIDDEN
ffi_prep_closure_loc_sysv(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)633*1fd5a2e1SPrashanth Swaminathan ffi_prep_closure_loc_sysv (ffi_closure *closure,
634*1fd5a2e1SPrashanth Swaminathan 			   ffi_cif *cif,
635*1fd5a2e1SPrashanth Swaminathan 			   void (*fun) (ffi_cif *, void *, void **, void *),
636*1fd5a2e1SPrashanth Swaminathan 			   void *user_data,
637*1fd5a2e1SPrashanth Swaminathan 			   void *codeloc)
638*1fd5a2e1SPrashanth Swaminathan {
639*1fd5a2e1SPrashanth Swaminathan   unsigned int *tramp;
640*1fd5a2e1SPrashanth Swaminathan 
641*1fd5a2e1SPrashanth Swaminathan   if (cif->abi < FFI_SYSV || cif->abi >= FFI_LAST_ABI)
642*1fd5a2e1SPrashanth Swaminathan     return FFI_BAD_ABI;
643*1fd5a2e1SPrashanth Swaminathan 
644*1fd5a2e1SPrashanth Swaminathan   tramp = (unsigned int *) &closure->tramp[0];
645*1fd5a2e1SPrashanth Swaminathan   tramp[0] = 0x7c0802a6;  /*   mflr    r0 */
646*1fd5a2e1SPrashanth Swaminathan   tramp[1] = 0x429f0005;  /*   bcl     20,31,.+4 */
647*1fd5a2e1SPrashanth Swaminathan   tramp[2] = 0x7d6802a6;  /*   mflr    r11 */
648*1fd5a2e1SPrashanth Swaminathan   tramp[3] = 0x7c0803a6;  /*   mtlr    r0 */
649*1fd5a2e1SPrashanth Swaminathan   tramp[4] = 0x800b0018;  /*   lwz     r0,24(r11) */
650*1fd5a2e1SPrashanth Swaminathan   tramp[5] = 0x816b001c;  /*   lwz     r11,28(r11) */
651*1fd5a2e1SPrashanth Swaminathan   tramp[6] = 0x7c0903a6;  /*   mtctr   r0 */
652*1fd5a2e1SPrashanth Swaminathan   tramp[7] = 0x4e800420;  /*   bctr */
653*1fd5a2e1SPrashanth Swaminathan   *(void **) &tramp[8] = (void *) ffi_closure_SYSV; /* function */
654*1fd5a2e1SPrashanth Swaminathan   *(void **) &tramp[9] = codeloc;                   /* context */
655*1fd5a2e1SPrashanth Swaminathan 
656*1fd5a2e1SPrashanth Swaminathan   /* Flush the icache.  */
657*1fd5a2e1SPrashanth Swaminathan   flush_icache ((char *)tramp, (char *)codeloc, 8 * 4);
658*1fd5a2e1SPrashanth Swaminathan 
659*1fd5a2e1SPrashanth Swaminathan   closure->cif = cif;
660*1fd5a2e1SPrashanth Swaminathan   closure->fun = fun;
661*1fd5a2e1SPrashanth Swaminathan   closure->user_data = user_data;
662*1fd5a2e1SPrashanth Swaminathan 
663*1fd5a2e1SPrashanth Swaminathan   return FFI_OK;
664*1fd5a2e1SPrashanth Swaminathan }
665*1fd5a2e1SPrashanth Swaminathan 
666*1fd5a2e1SPrashanth Swaminathan /* Basically the trampoline invokes ffi_closure_SYSV, and on
667*1fd5a2e1SPrashanth Swaminathan    entry, r11 holds the address of the closure.
668*1fd5a2e1SPrashanth Swaminathan    After storing the registers that could possibly contain
669*1fd5a2e1SPrashanth Swaminathan    parameters to be passed into the stack frame and setting
670*1fd5a2e1SPrashanth Swaminathan    up space for a return value, ffi_closure_SYSV invokes the
671*1fd5a2e1SPrashanth Swaminathan    following helper function to do most of the work.  */
672*1fd5a2e1SPrashanth Swaminathan 
673*1fd5a2e1SPrashanth Swaminathan int
ffi_closure_helper_SYSV(ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * rvalue,unsigned long * pgr,ffi_dblfl * pfr,unsigned long * pst)674*1fd5a2e1SPrashanth Swaminathan ffi_closure_helper_SYSV (ffi_cif *cif,
675*1fd5a2e1SPrashanth Swaminathan 			 void (*fun) (ffi_cif *, void *, void **, void *),
676*1fd5a2e1SPrashanth Swaminathan 			 void *user_data,
677*1fd5a2e1SPrashanth Swaminathan 			 void *rvalue,
678*1fd5a2e1SPrashanth Swaminathan 			 unsigned long *pgr,
679*1fd5a2e1SPrashanth Swaminathan 			 ffi_dblfl *pfr,
680*1fd5a2e1SPrashanth Swaminathan 			 unsigned long *pst)
681*1fd5a2e1SPrashanth Swaminathan {
682*1fd5a2e1SPrashanth Swaminathan   /* rvalue is the pointer to space for return value in closure assembly */
683*1fd5a2e1SPrashanth Swaminathan   /* pgr is the pointer to where r3-r10 are stored in ffi_closure_SYSV */
684*1fd5a2e1SPrashanth Swaminathan   /* pfr is the pointer to where f1-f8 are stored in ffi_closure_SYSV  */
685*1fd5a2e1SPrashanth Swaminathan   /* pst is the pointer to outgoing parameter stack in original caller */
686*1fd5a2e1SPrashanth Swaminathan 
687*1fd5a2e1SPrashanth Swaminathan   void **          avalue;
688*1fd5a2e1SPrashanth Swaminathan   ffi_type **      arg_types;
689*1fd5a2e1SPrashanth Swaminathan   long             i, avn;
690*1fd5a2e1SPrashanth Swaminathan #ifndef __NO_FPRS__
691*1fd5a2e1SPrashanth Swaminathan   long             nf = 0;   /* number of floating registers already used */
692*1fd5a2e1SPrashanth Swaminathan #endif
693*1fd5a2e1SPrashanth Swaminathan   long             ng = 0;   /* number of general registers already used */
694*1fd5a2e1SPrashanth Swaminathan 
695*1fd5a2e1SPrashanth Swaminathan   unsigned       size     = cif->rtype->size;
696*1fd5a2e1SPrashanth Swaminathan   unsigned short rtypenum = cif->rtype->type;
697*1fd5a2e1SPrashanth Swaminathan 
698*1fd5a2e1SPrashanth Swaminathan   avalue = alloca (cif->nargs * sizeof (void *));
699*1fd5a2e1SPrashanth Swaminathan 
700*1fd5a2e1SPrashanth Swaminathan   /* First translate for softfloat/nonlinux */
701*1fd5a2e1SPrashanth Swaminathan   rtypenum = translate_float (cif->abi, rtypenum);
702*1fd5a2e1SPrashanth Swaminathan 
703*1fd5a2e1SPrashanth Swaminathan   /* Copy the caller's structure return value address so that the closure
704*1fd5a2e1SPrashanth Swaminathan      returns the data directly to the caller.
705*1fd5a2e1SPrashanth Swaminathan      For FFI_SYSV the result is passed in r3/r4 if the struct size is less
706*1fd5a2e1SPrashanth Swaminathan      or equal 8 bytes.  */
707*1fd5a2e1SPrashanth Swaminathan   if (rtypenum == FFI_TYPE_STRUCT
708*1fd5a2e1SPrashanth Swaminathan       && !((cif->abi & FFI_SYSV_STRUCT_RET) != 0 && size <= 8))
709*1fd5a2e1SPrashanth Swaminathan     {
710*1fd5a2e1SPrashanth Swaminathan       rvalue = (void *) *pgr;
711*1fd5a2e1SPrashanth Swaminathan       ng++;
712*1fd5a2e1SPrashanth Swaminathan       pgr++;
713*1fd5a2e1SPrashanth Swaminathan     }
714*1fd5a2e1SPrashanth Swaminathan 
715*1fd5a2e1SPrashanth Swaminathan   i = 0;
716*1fd5a2e1SPrashanth Swaminathan   avn = cif->nargs;
717*1fd5a2e1SPrashanth Swaminathan   arg_types = cif->arg_types;
718*1fd5a2e1SPrashanth Swaminathan 
719*1fd5a2e1SPrashanth Swaminathan   /* Grab the addresses of the arguments from the stack frame.  */
720*1fd5a2e1SPrashanth Swaminathan   while (i < avn) {
721*1fd5a2e1SPrashanth Swaminathan     unsigned short typenum = arg_types[i]->type;
722*1fd5a2e1SPrashanth Swaminathan 
723*1fd5a2e1SPrashanth Swaminathan     /* We may need to handle some values depending on ABI.  */
724*1fd5a2e1SPrashanth Swaminathan     typenum = translate_float (cif->abi, typenum);
725*1fd5a2e1SPrashanth Swaminathan 
726*1fd5a2e1SPrashanth Swaminathan     switch (typenum)
727*1fd5a2e1SPrashanth Swaminathan       {
728*1fd5a2e1SPrashanth Swaminathan #ifndef __NO_FPRS__
729*1fd5a2e1SPrashanth Swaminathan       case FFI_TYPE_FLOAT:
730*1fd5a2e1SPrashanth Swaminathan 	/* Unfortunately float values are stored as doubles
731*1fd5a2e1SPrashanth Swaminathan 	   in the ffi_closure_SYSV code (since we don't check
732*1fd5a2e1SPrashanth Swaminathan 	   the type in that routine).  */
733*1fd5a2e1SPrashanth Swaminathan 	if (nf < NUM_FPR_ARG_REGISTERS)
734*1fd5a2e1SPrashanth Swaminathan 	  {
735*1fd5a2e1SPrashanth Swaminathan 	    /* FIXME? here we are really changing the values
736*1fd5a2e1SPrashanth Swaminathan 	       stored in the original calling routines outgoing
737*1fd5a2e1SPrashanth Swaminathan 	       parameter stack.  This is probably a really
738*1fd5a2e1SPrashanth Swaminathan 	       naughty thing to do but...  */
739*1fd5a2e1SPrashanth Swaminathan 	    double temp = pfr->d;
740*1fd5a2e1SPrashanth Swaminathan 	    pfr->f = (float) temp;
741*1fd5a2e1SPrashanth Swaminathan 	    avalue[i] = pfr;
742*1fd5a2e1SPrashanth Swaminathan 	    nf++;
743*1fd5a2e1SPrashanth Swaminathan 	    pfr++;
744*1fd5a2e1SPrashanth Swaminathan 	  }
745*1fd5a2e1SPrashanth Swaminathan 	else
746*1fd5a2e1SPrashanth Swaminathan 	  {
747*1fd5a2e1SPrashanth Swaminathan 	    avalue[i] = pst;
748*1fd5a2e1SPrashanth Swaminathan 	    pst += 1;
749*1fd5a2e1SPrashanth Swaminathan 	  }
750*1fd5a2e1SPrashanth Swaminathan 	break;
751*1fd5a2e1SPrashanth Swaminathan 
752*1fd5a2e1SPrashanth Swaminathan       case FFI_TYPE_DOUBLE:
753*1fd5a2e1SPrashanth Swaminathan 	if (nf < NUM_FPR_ARG_REGISTERS)
754*1fd5a2e1SPrashanth Swaminathan 	  {
755*1fd5a2e1SPrashanth Swaminathan 	    avalue[i] = pfr;
756*1fd5a2e1SPrashanth Swaminathan 	    nf++;
757*1fd5a2e1SPrashanth Swaminathan 	    pfr++;
758*1fd5a2e1SPrashanth Swaminathan 	  }
759*1fd5a2e1SPrashanth Swaminathan 	else
760*1fd5a2e1SPrashanth Swaminathan 	  {
761*1fd5a2e1SPrashanth Swaminathan 	    if (((long) pst) & 4)
762*1fd5a2e1SPrashanth Swaminathan 	      pst++;
763*1fd5a2e1SPrashanth Swaminathan 	    avalue[i] = pst;
764*1fd5a2e1SPrashanth Swaminathan 	    pst += 2;
765*1fd5a2e1SPrashanth Swaminathan 	  }
766*1fd5a2e1SPrashanth Swaminathan 	break;
767*1fd5a2e1SPrashanth Swaminathan 
768*1fd5a2e1SPrashanth Swaminathan # if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
769*1fd5a2e1SPrashanth Swaminathan       case FFI_TYPE_LONGDOUBLE:
770*1fd5a2e1SPrashanth Swaminathan 	if (nf < NUM_FPR_ARG_REGISTERS - 1)
771*1fd5a2e1SPrashanth Swaminathan 	  {
772*1fd5a2e1SPrashanth Swaminathan 	    avalue[i] = pfr;
773*1fd5a2e1SPrashanth Swaminathan 	    pfr += 2;
774*1fd5a2e1SPrashanth Swaminathan 	    nf += 2;
775*1fd5a2e1SPrashanth Swaminathan 	  }
776*1fd5a2e1SPrashanth Swaminathan 	else
777*1fd5a2e1SPrashanth Swaminathan 	  {
778*1fd5a2e1SPrashanth Swaminathan 	    if (((long) pst) & 4)
779*1fd5a2e1SPrashanth Swaminathan 	      pst++;
780*1fd5a2e1SPrashanth Swaminathan 	    avalue[i] = pst;
781*1fd5a2e1SPrashanth Swaminathan 	    pst += 4;
782*1fd5a2e1SPrashanth Swaminathan 	    nf = 8;
783*1fd5a2e1SPrashanth Swaminathan 	  }
784*1fd5a2e1SPrashanth Swaminathan 	break;
785*1fd5a2e1SPrashanth Swaminathan # endif
786*1fd5a2e1SPrashanth Swaminathan #endif
787*1fd5a2e1SPrashanth Swaminathan 
788*1fd5a2e1SPrashanth Swaminathan       case FFI_TYPE_UINT128:
789*1fd5a2e1SPrashanth Swaminathan 	/* Test if for the whole long double, 4 gprs are available.
790*1fd5a2e1SPrashanth Swaminathan 	   otherwise the stuff ends up on the stack.  */
791*1fd5a2e1SPrashanth Swaminathan 	if (ng < NUM_GPR_ARG_REGISTERS - 3)
792*1fd5a2e1SPrashanth Swaminathan 	  {
793*1fd5a2e1SPrashanth Swaminathan 	    avalue[i] = pgr;
794*1fd5a2e1SPrashanth Swaminathan 	    pgr += 4;
795*1fd5a2e1SPrashanth Swaminathan 	    ng += 4;
796*1fd5a2e1SPrashanth Swaminathan 	  }
797*1fd5a2e1SPrashanth Swaminathan 	else
798*1fd5a2e1SPrashanth Swaminathan 	  {
799*1fd5a2e1SPrashanth Swaminathan 	    avalue[i] = pst;
800*1fd5a2e1SPrashanth Swaminathan 	    pst += 4;
801*1fd5a2e1SPrashanth Swaminathan 	    ng = 8+4;
802*1fd5a2e1SPrashanth Swaminathan 	  }
803*1fd5a2e1SPrashanth Swaminathan 	break;
804*1fd5a2e1SPrashanth Swaminathan 
805*1fd5a2e1SPrashanth Swaminathan       case FFI_TYPE_SINT8:
806*1fd5a2e1SPrashanth Swaminathan       case FFI_TYPE_UINT8:
807*1fd5a2e1SPrashanth Swaminathan #ifndef __LITTLE_ENDIAN__
808*1fd5a2e1SPrashanth Swaminathan 	if (ng < NUM_GPR_ARG_REGISTERS)
809*1fd5a2e1SPrashanth Swaminathan 	  {
810*1fd5a2e1SPrashanth Swaminathan 	    avalue[i] = (char *) pgr + 3;
811*1fd5a2e1SPrashanth Swaminathan 	    ng++;
812*1fd5a2e1SPrashanth Swaminathan 	    pgr++;
813*1fd5a2e1SPrashanth Swaminathan 	  }
814*1fd5a2e1SPrashanth Swaminathan 	else
815*1fd5a2e1SPrashanth Swaminathan 	  {
816*1fd5a2e1SPrashanth Swaminathan 	    avalue[i] = (char *) pst + 3;
817*1fd5a2e1SPrashanth Swaminathan 	    pst++;
818*1fd5a2e1SPrashanth Swaminathan 	  }
819*1fd5a2e1SPrashanth Swaminathan 	break;
820*1fd5a2e1SPrashanth Swaminathan #endif
821*1fd5a2e1SPrashanth Swaminathan 
822*1fd5a2e1SPrashanth Swaminathan       case FFI_TYPE_SINT16:
823*1fd5a2e1SPrashanth Swaminathan       case FFI_TYPE_UINT16:
824*1fd5a2e1SPrashanth Swaminathan #ifndef __LITTLE_ENDIAN__
825*1fd5a2e1SPrashanth Swaminathan 	if (ng < NUM_GPR_ARG_REGISTERS)
826*1fd5a2e1SPrashanth Swaminathan 	  {
827*1fd5a2e1SPrashanth Swaminathan 	    avalue[i] = (char *) pgr + 2;
828*1fd5a2e1SPrashanth Swaminathan 	    ng++;
829*1fd5a2e1SPrashanth Swaminathan 	    pgr++;
830*1fd5a2e1SPrashanth Swaminathan 	  }
831*1fd5a2e1SPrashanth Swaminathan 	else
832*1fd5a2e1SPrashanth Swaminathan 	  {
833*1fd5a2e1SPrashanth Swaminathan 	    avalue[i] = (char *) pst + 2;
834*1fd5a2e1SPrashanth Swaminathan 	    pst++;
835*1fd5a2e1SPrashanth Swaminathan 	  }
836*1fd5a2e1SPrashanth Swaminathan 	break;
837*1fd5a2e1SPrashanth Swaminathan #endif
838*1fd5a2e1SPrashanth Swaminathan 
839*1fd5a2e1SPrashanth Swaminathan       case FFI_TYPE_SINT32:
840*1fd5a2e1SPrashanth Swaminathan       case FFI_TYPE_UINT32:
841*1fd5a2e1SPrashanth Swaminathan       case FFI_TYPE_POINTER:
842*1fd5a2e1SPrashanth Swaminathan 	if (ng < NUM_GPR_ARG_REGISTERS)
843*1fd5a2e1SPrashanth Swaminathan 	  {
844*1fd5a2e1SPrashanth Swaminathan 	    avalue[i] = pgr;
845*1fd5a2e1SPrashanth Swaminathan 	    ng++;
846*1fd5a2e1SPrashanth Swaminathan 	    pgr++;
847*1fd5a2e1SPrashanth Swaminathan 	  }
848*1fd5a2e1SPrashanth Swaminathan 	else
849*1fd5a2e1SPrashanth Swaminathan 	  {
850*1fd5a2e1SPrashanth Swaminathan 	    avalue[i] = pst;
851*1fd5a2e1SPrashanth Swaminathan 	    pst++;
852*1fd5a2e1SPrashanth Swaminathan 	  }
853*1fd5a2e1SPrashanth Swaminathan 	break;
854*1fd5a2e1SPrashanth Swaminathan 
855*1fd5a2e1SPrashanth Swaminathan       case FFI_TYPE_STRUCT:
856*1fd5a2e1SPrashanth Swaminathan 	/* Structs are passed by reference. The address will appear in a
857*1fd5a2e1SPrashanth Swaminathan 	   gpr if it is one of the first 8 arguments.  */
858*1fd5a2e1SPrashanth Swaminathan 	if (ng < NUM_GPR_ARG_REGISTERS)
859*1fd5a2e1SPrashanth Swaminathan 	  {
860*1fd5a2e1SPrashanth Swaminathan 	    avalue[i] = (void *) *pgr;
861*1fd5a2e1SPrashanth Swaminathan 	    ng++;
862*1fd5a2e1SPrashanth Swaminathan 	    pgr++;
863*1fd5a2e1SPrashanth Swaminathan 	  }
864*1fd5a2e1SPrashanth Swaminathan 	else
865*1fd5a2e1SPrashanth Swaminathan 	  {
866*1fd5a2e1SPrashanth Swaminathan 	    avalue[i] = (void *) *pst;
867*1fd5a2e1SPrashanth Swaminathan 	    pst++;
868*1fd5a2e1SPrashanth Swaminathan 	  }
869*1fd5a2e1SPrashanth Swaminathan 	break;
870*1fd5a2e1SPrashanth Swaminathan 
871*1fd5a2e1SPrashanth Swaminathan       case FFI_TYPE_SINT64:
872*1fd5a2e1SPrashanth Swaminathan       case FFI_TYPE_UINT64:
873*1fd5a2e1SPrashanth Swaminathan 	/* Passing long long ints are complex, they must
874*1fd5a2e1SPrashanth Swaminathan 	   be passed in suitable register pairs such as
875*1fd5a2e1SPrashanth Swaminathan 	   (r3,r4) or (r5,r6) or (r6,r7), or (r7,r8) or (r9,r10)
876*1fd5a2e1SPrashanth Swaminathan 	   and if the entire pair aren't available then the outgoing
877*1fd5a2e1SPrashanth Swaminathan 	   parameter stack is used for both but an alignment of 8
878*1fd5a2e1SPrashanth Swaminathan 	   must will be kept.  So we must either look in pgr
879*1fd5a2e1SPrashanth Swaminathan 	   or pst to find the correct address for this type
880*1fd5a2e1SPrashanth Swaminathan 	   of parameter.  */
881*1fd5a2e1SPrashanth Swaminathan 	if (ng < NUM_GPR_ARG_REGISTERS - 1)
882*1fd5a2e1SPrashanth Swaminathan 	  {
883*1fd5a2e1SPrashanth Swaminathan 	    if (ng & 1)
884*1fd5a2e1SPrashanth Swaminathan 	      {
885*1fd5a2e1SPrashanth Swaminathan 		/* skip r4, r6, r8 as starting points */
886*1fd5a2e1SPrashanth Swaminathan 		ng++;
887*1fd5a2e1SPrashanth Swaminathan 		pgr++;
888*1fd5a2e1SPrashanth Swaminathan 	      }
889*1fd5a2e1SPrashanth Swaminathan 	    avalue[i] = pgr;
890*1fd5a2e1SPrashanth Swaminathan 	    ng += 2;
891*1fd5a2e1SPrashanth Swaminathan 	    pgr += 2;
892*1fd5a2e1SPrashanth Swaminathan 	  }
893*1fd5a2e1SPrashanth Swaminathan 	else
894*1fd5a2e1SPrashanth Swaminathan 	  {
895*1fd5a2e1SPrashanth Swaminathan 	    if (((long) pst) & 4)
896*1fd5a2e1SPrashanth Swaminathan 	      pst++;
897*1fd5a2e1SPrashanth Swaminathan 	    avalue[i] = pst;
898*1fd5a2e1SPrashanth Swaminathan 	    pst += 2;
899*1fd5a2e1SPrashanth Swaminathan 	    ng = NUM_GPR_ARG_REGISTERS;
900*1fd5a2e1SPrashanth Swaminathan 	  }
901*1fd5a2e1SPrashanth Swaminathan 	break;
902*1fd5a2e1SPrashanth Swaminathan 
903*1fd5a2e1SPrashanth Swaminathan       default:
904*1fd5a2e1SPrashanth Swaminathan 	FFI_ASSERT (0);
905*1fd5a2e1SPrashanth Swaminathan       }
906*1fd5a2e1SPrashanth Swaminathan 
907*1fd5a2e1SPrashanth Swaminathan     i++;
908*1fd5a2e1SPrashanth Swaminathan   }
909*1fd5a2e1SPrashanth Swaminathan 
910*1fd5a2e1SPrashanth Swaminathan   (*fun) (cif, rvalue, avalue, user_data);
911*1fd5a2e1SPrashanth Swaminathan 
912*1fd5a2e1SPrashanth Swaminathan   /* Tell ffi_closure_SYSV how to perform return type promotions.
913*1fd5a2e1SPrashanth Swaminathan      Because the FFI_SYSV ABI returns the structures <= 8 bytes in
914*1fd5a2e1SPrashanth Swaminathan      r3/r4 we have to tell ffi_closure_SYSV how to treat them.  We
915*1fd5a2e1SPrashanth Swaminathan      combine the base type FFI_SYSV_TYPE_SMALL_STRUCT with the size of
916*1fd5a2e1SPrashanth Swaminathan      the struct less one.  We never have a struct with size zero.
917*1fd5a2e1SPrashanth Swaminathan      See the comment in ffitarget.h about ordering.  */
918*1fd5a2e1SPrashanth Swaminathan   if (rtypenum == FFI_TYPE_STRUCT
919*1fd5a2e1SPrashanth Swaminathan       && (cif->abi & FFI_SYSV_STRUCT_RET) != 0 && size <= 8)
920*1fd5a2e1SPrashanth Swaminathan     return FFI_SYSV_TYPE_SMALL_STRUCT - 1 + size;
921*1fd5a2e1SPrashanth Swaminathan   return rtypenum;
922*1fd5a2e1SPrashanth Swaminathan }
923*1fd5a2e1SPrashanth Swaminathan #endif
924