OSDN Git Service

Initial revision
[pf3gnuchains/gcc-fork.git] / libffi / src / powerpc / ffi.c
1 /* -----------------------------------------------------------------------
2    ffi.c - Copyright (c) 1998 Geoffrey Keating
3    
4    PowerPC Foreign Function Interface 
5
6    $Id: ffi.c,v 1.1.1.1 1998/11/29 16:48:16 green Exp $
7
8    Permission is hereby granted, free of charge, to any person obtaining
9    a copy of this software and associated documentation files (the
10    ``Software''), to deal in the Software without restriction, including
11    without limitation the rights to use, copy, modify, merge, publish,
12    distribute, sublicense, and/or sell copies of the Software, and to
13    permit persons to whom the Software is furnished to do so, subject to
14    the following conditions:
15
16    The above copyright notice and this permission notice shall be included
17    in all copies or substantial portions of the Software.
18
19    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
20    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
23    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25    OTHER DEALINGS IN THE SOFTWARE.
26    ----------------------------------------------------------------------- */
27
28 #include <ffi.h>
29 #include <ffi_common.h>
30
31 #include <stdlib.h>
32
33 enum {
34   /* The assembly depends on these exact flags.  */
35   FLAG_RETURNS_NOTHING  = 1 << (31-30), /* These go in cr7 */
36   FLAG_RETURNS_FP       = 1 << (31-29),
37   FLAG_RETURNS_64BITS   = 1 << (31-28),
38
39   FLAG_ARG_NEEDS_COPY   = 1 << (31- 7),
40   FLAG_FP_ARGUMENTS     = 1 << (31- 6), /* cr1.eq; specified by ABI */
41   FLAG_4_GPR_ARGUMENTS  = 1 << (31- 5),
42   FLAG_RETVAL_REFERENCE = 1 << (31- 4)
43 };
44
45 /* About the SYSV ABI.  */
46 enum {
47   NUM_GPR_ARG_REGISTERS = 8,
48   NUM_FPR_ARG_REGISTERS = 8
49 };
50 enum { ASM_NEEDS_REGISTERS = 4 };
51
52 /* ffi_prep_args is called by the assembly routine once stack space
53    has been allocated for the function's arguments.
54
55    The stack layout we want looks like this:
56
57    |   Return address from ffi_call_SYSV 4bytes |       higher addresses
58    |--------------------------------------------|
59    |   Previous backchain pointer       4       |       stack pointer here
60    |--------------------------------------------|<+ <<< on entry to
61    |   Saved r28-r31                    4*4     | |     ffi_call_SYSV
62    |--------------------------------------------| |
63    |   GPR registers r3-r10             8*4     | |     ffi_call_SYSV
64    |--------------------------------------------| |
65    |   FPR registers f1-f8 (optional)   8*8     | |
66    |--------------------------------------------| |     stack   |
67    |   Space for copied structures              | |     grows   |
68    |--------------------------------------------| |     down    V
69    |   Parameters that didn't fit in registers  | |
70    |--------------------------------------------| |     lower addresses
71    |   Space for callee's LR            4       | |
72    |--------------------------------------------| |     stack pointer here
73    |   Current backchain pointer        4       |-/     during
74    |--------------------------------------------|   <<< ffi_call_SYSV
75
76    */
77
78 /*@-exportheader@*/
79 void ffi_prep_args(extended_cif *ecif, unsigned *const stack)
80 /*@=exportheader@*/
81 {
82   const unsigned bytes = ecif->cif->bytes;
83   const unsigned flags = ecif->cif->flags;
84   
85   /* 'stacktop' points at the previous backchain pointer.  */
86   unsigned *const stacktop = stack + (ecif->cif->bytes / sizeof(unsigned));
87
88   /* 'gpr_base' points at the space for gpr3, and grows upwards as
89      we use GPR registers.  */
90   unsigned *gpr_base = stacktop - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS;
91   int intarg_count = 0;
92
93   /* 'fpr_base' points at the space for fpr1, and grows upwards as
94      we use FPR registers.  */
95   double *fpr_base = (double *)gpr_base - NUM_FPR_ARG_REGISTERS;
96   int fparg_count = 0;
97
98   /* 'copy_space' grows down as we put structures in it.  It should
99      stay 16-byte aligned.  */
100   char *copy_space = ((flags & FLAG_FP_ARGUMENTS)
101                       ? (char *)fpr_base
102                       : (char *)gpr_base);
103
104   /* 'next_arg' grows up as we put parameters in it.  */
105   unsigned *next_arg = stack + 2;
106
107   int i;
108   ffi_type **ptr;
109   double double_tmp;
110   void **p_argv;
111   size_t struct_copy_size;
112   unsigned gprvalue;
113
114   /* Check that everything starts aligned properly.  */
115   FFI_ASSERT(((unsigned)(char *)stack & 0xF) == 0);
116   FFI_ASSERT(((unsigned)(char *)copy_space & 0xF) == 0);
117   FFI_ASSERT(((unsigned)(char *)stacktop & 0xF) == 0);
118   FFI_ASSERT((bytes & 0xF) == 0);
119   FFI_ASSERT(copy_space >= (char *)next_arg);
120
121   /* Deal with return values that are actually pass-by-reference.  */
122   if (flags & FLAG_RETVAL_REFERENCE)
123   {
124     *gpr_base++ = (unsigned)(char *)ecif->rvalue;
125     intarg_count++;
126   }
127
128   /* Now for the arguments.  */
129   p_argv = ecif->avalue;
130   for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
131        i > 0;
132        i--, ptr++, p_argv++)
133     {
134       switch ((*ptr)->type)
135         {
136         case FFI_TYPE_FLOAT:
137         case FFI_TYPE_DOUBLE:
138           if ((*ptr)->type == FFI_TYPE_FLOAT)
139             double_tmp = *(float *)*p_argv;
140           else
141             double_tmp = *(double *)*p_argv;
142
143           if (fparg_count >= NUM_FPR_ARG_REGISTERS)
144             {
145               if (intarg_count%2 != 0)
146                 {
147                   intarg_count++;
148                   next_arg++;
149                 }
150               *(double *)next_arg = double_tmp;
151               next_arg += 2;
152             }
153           else
154             *fpr_base++ = double_tmp;
155           fparg_count++;
156           FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
157           break;
158
159         case FFI_TYPE_UINT64:
160         case FFI_TYPE_SINT64:
161           if (intarg_count == NUM_GPR_ARG_REGISTERS-1)
162             intarg_count++;
163           if (intarg_count >= NUM_GPR_ARG_REGISTERS)
164             {
165               if (intarg_count%2 != 0)
166                 {
167                   intarg_count++;
168                   next_arg++;
169                 }
170               *(long long *)next_arg = *(long long *)*p_argv;
171               next_arg += 2;
172             }
173           else
174             {
175               *(long long *)gpr_base = *(long long *)*p_argv;
176               gpr_base += 2;
177             }
178           intarg_count += 2;
179           break;
180
181         case FFI_TYPE_STRUCT:
182 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
183         case FFI_TYPE_LONGDOUBLE:
184 #endif
185           struct_copy_size = ((*ptr)->size + 15) & ~0xF;
186           copy_space -= struct_copy_size;
187           memcpy(copy_space, (char *)*p_argv, (*ptr)->size);
188           
189           gprvalue = (unsigned)copy_space;
190
191           FFI_ASSERT(copy_space > (char *)next_arg);
192           FFI_ASSERT(flags & FLAG_ARG_NEEDS_COPY);
193           goto putgpr;
194
195         case FFI_TYPE_UINT8:
196           gprvalue = *(unsigned char *)*p_argv;
197           goto putgpr;
198         case FFI_TYPE_SINT8:
199           gprvalue = *(signed char *)*p_argv;
200           goto putgpr;
201         case FFI_TYPE_UINT16:
202           gprvalue = *(unsigned short *)*p_argv;
203           goto putgpr;
204         case FFI_TYPE_SINT16:
205           gprvalue = *(signed short *)*p_argv;
206           goto putgpr;
207
208         case FFI_TYPE_INT:
209         case FFI_TYPE_UINT32:
210         case FFI_TYPE_SINT32:
211         case FFI_TYPE_POINTER:
212           gprvalue = *(unsigned *)*p_argv;
213         putgpr:
214           if (intarg_count >= NUM_GPR_ARG_REGISTERS)
215             *next_arg++ = gprvalue;
216           else
217             *gpr_base++ = gprvalue;
218           intarg_count++;
219           break;
220         }
221     }
222
223   /* Check that we didn't overrun the stack...  */
224   FFI_ASSERT(copy_space >= (char *)next_arg);
225   FFI_ASSERT(gpr_base <= stacktop - ASM_NEEDS_REGISTERS);
226   FFI_ASSERT((unsigned *)fpr_base
227              <= stacktop - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS);
228   FFI_ASSERT(flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4);
229 }
230
231 /* Perform machine dependent cif processing */
232 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
233 {
234   /* All this is for the SYSV ABI.  */
235   int i;
236   ffi_type **ptr;
237   unsigned bytes;
238   int fparg_count = 0, intarg_count = 0;
239   unsigned flags = 0;
240   unsigned struct_copy_size = 0;
241   
242   /* All the machine-independent calculation of cif->bytes will be wrong.
243      Redo the calculation for SYSV.  */
244
245   /* Space for the frame pointer, callee's LR, and the asm's temp regs.  */
246   bytes = (2 + ASM_NEEDS_REGISTERS) * sizeof(int);
247
248   /* Space for the GPR registers.  */
249   bytes += NUM_GPR_ARG_REGISTERS * sizeof(int);
250
251   /* Return value handling.  The rules are as follows:
252      - 32-bit (or less) integer values are returned in gpr3;
253      - Structures of size <= 4 bytes also returned in gpr3;
254      - 64-bit integer values and structures between 5 and 8 bytes are returned
255        in gpr3 and gpr4;
256      - Single/double FP values are returned in fpr1;
257      - Larger structures and long double (if not equivalent to double) values
258        are allocated space and a pointer is passed as the first argument.  */
259   switch (cif->rtype->type)
260     {
261     case FFI_TYPE_DOUBLE:
262       flags |= FLAG_RETURNS_64BITS;
263       /* Fall through.  */
264     case FFI_TYPE_FLOAT:
265       flags |= FLAG_RETURNS_FP;
266       break;
267
268     case FFI_TYPE_UINT64:
269     case FFI_TYPE_SINT64:
270       flags |= FLAG_RETURNS_64BITS;
271       break;
272
273     case FFI_TYPE_STRUCT:
274       if (cif->abi != FFI_GCC_SYSV)
275         if (cif->rtype->size <= 4)
276           break;
277         else if (cif->rtype->size <= 8)
278           {
279             flags |= FLAG_RETURNS_64BITS;
280             break;
281           }
282       /* else fall through.  */
283 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
284     case FFI_TYPE_LONGDOUBLE:
285 #endif
286       intarg_count++;
287       flags |= FLAG_RETVAL_REFERENCE;
288       /* Fall through.  */
289     case FFI_TYPE_VOID:
290       flags |= FLAG_RETURNS_NOTHING;
291       break;
292
293     default:
294       /* Returns 32-bit integer, or similar.  Nothing to do here.  */
295       break;
296     }
297
298   /* The first NUM_GPR_ARG_REGISTERS words of integer arguments, and the
299      first NUM_FPR_ARG_REGISTERS fp arguments, go in registers; the rest
300      goes on the stack.  Structures and long doubles (if not equivalent
301      to double) are passed as a pointer to a copy of the structure.
302      Stuff on the stack needs to keep proper alignment.  */
303   for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
304     {
305       switch ((*ptr)->type)
306         {
307         case FFI_TYPE_FLOAT:
308         case FFI_TYPE_DOUBLE:
309           fparg_count++;
310           /* If this FP arg is going on the stack, it must be
311              8-byte-aligned.  */
312           if (fparg_count > NUM_FPR_ARG_REGISTERS
313               && intarg_count%2 != 0)
314             intarg_count++;
315           break;
316
317         case FFI_TYPE_UINT64:
318         case FFI_TYPE_SINT64:
319           /* 'long long' arguments are passed as two words, but
320              either both words must fit in registers or both go
321              on the stack.  If they go on the stack, they must
322              be 8-byte-aligned.  */
323           if (intarg_count == NUM_GPR_ARG_REGISTERS-1
324               || intarg_count >= NUM_GPR_ARG_REGISTERS && intarg_count%2 != 0)
325             intarg_count++;
326           intarg_count += 2;
327           break;
328
329         case FFI_TYPE_STRUCT:
330 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
331         case FFI_TYPE_LONGDOUBLE:
332 #endif
333           /* We must allocate space for a copy of these to enforce
334              pass-by-value.  Pad the space up to a multiple of 16
335              bytes (the maximum alignment required for anything under
336              the SYSV ABI).  */
337           struct_copy_size += ((*ptr)->size + 15) & ~0xF;
338           /* Fall through (allocate space for the pointer).  */
339
340         default:
341           /* Everything else is passed as a 4-byte word in a GPR, either
342              the object itself or a pointer to it.  */
343           intarg_count++;
344           break;
345         }
346     }
347
348   if (fparg_count != 0)
349     flags |= FLAG_FP_ARGUMENTS;
350   if (intarg_count > 4)
351     flags |= FLAG_4_GPR_ARGUMENTS;
352   if (struct_copy_size != 0)
353     flags |= FLAG_ARG_NEEDS_COPY;
354   
355   /* Space for the FPR registers, if needed.  */
356   if (fparg_count != 0)
357     bytes += NUM_FPR_ARG_REGISTERS * sizeof(double);
358
359   /* Stack space.  */
360   if (intarg_count > NUM_GPR_ARG_REGISTERS)
361     bytes += (intarg_count - NUM_GPR_ARG_REGISTERS) * sizeof(int);
362   if (fparg_count > NUM_FPR_ARG_REGISTERS)
363     bytes += (fparg_count - NUM_FPR_ARG_REGISTERS) * sizeof(double);
364
365   /* The stack space allocated needs to be a multiple of 16 bytes.  */
366   bytes = (bytes + 15) & ~0xF;
367
368   /* Add in the space for the copied structures.  */
369   bytes += struct_copy_size;
370
371   cif->flags = flags;
372   cif->bytes = bytes;
373
374   return FFI_OK;
375 }
376
377 /*@-declundef@*/
378 /*@-exportheader@*/
379 extern void ffi_call_SYSV(/*@out@*/ extended_cif *, 
380                           unsigned, unsigned, 
381                           /*@out@*/ unsigned *, 
382                           void (*fn)());
383 /*@=declundef@*/
384 /*@=exportheader@*/
385
386 void ffi_call(/*@dependent@*/ ffi_cif *cif, 
387               void (*fn)(), 
388               /*@out@*/ void *rvalue, 
389               /*@dependent@*/ void **avalue)
390 {
391   extended_cif ecif;
392
393   ecif.cif = cif;
394   ecif.avalue = avalue;
395   
396   /* If the return value is a struct and we don't have a return */
397   /* value address then we need to make one                     */
398
399   if ((rvalue == NULL) && 
400       (cif->rtype->type == FFI_TYPE_STRUCT))
401     {
402       /*@-sysunrecog@*/
403       ecif.rvalue = alloca(cif->rtype->size);
404       /*@=sysunrecog@*/
405     }
406   else
407     ecif.rvalue = rvalue;
408     
409   
410   switch (cif->abi) 
411     {
412     case FFI_SYSV:
413     case FFI_GCC_SYSV:
414       /*@-usedef@*/
415       ffi_call_SYSV(&ecif, -cif->bytes, 
416                     cif->flags, ecif.rvalue, fn);
417       /*@=usedef@*/
418       break;
419     default:
420       FFI_ASSERT(0);
421       break;
422     }
423 }