215a3121faafbbab13ffe11edea7f8d1688a6493
[libffi.git] / patches / powerpc-ffi-softfloat
1 Index: libffi/ChangeLog
2 ===================================================================
3 --- libffi.orig/ChangeLog
4 +++ libffi/ChangeLog
5 @@ -41,6 +41,12 @@
6  
7         * configure: Regenerate.
8  
9 +2011-11-12  Kyle Moffett <Kyle.D.Moffett@boeing.com>
10 +
11 +       * src/powerpc/ffi.c, src/powerpc/ffitarget.h,
12 +       src/powerpc/ppc_closure.S, src/powerpc/sysv.S: Many changes for
13 +       softfloat powerpc variants.
14 +
15  2011-11-12  Petr Salinger <Petr.Salinger@seznam.cz>
16  
17         * configure.ac (FFI_EXEC_TRAMPOLINE_TABLE): Fix kfreebsd support.
18 Index: libffi/src/powerpc/ffi.c
19 ===================================================================
20 --- libffi.orig/src/powerpc/ffi.c
21 +++ libffi/src/powerpc/ffi.c
22 @@ -41,27 +41,28 @@ enum {
23    /* The assembly depends on these exact flags.  */
24    FLAG_RETURNS_SMST    = 1 << (31-31), /* Used for FFI_SYSV small structs.  */
25    FLAG_RETURNS_NOTHING  = 1 << (31-30), /* These go in cr7 */
26 +#ifndef __NO_FPRS__
27    FLAG_RETURNS_FP       = 1 << (31-29),
28 +#endif
29    FLAG_RETURNS_64BITS   = 1 << (31-28),
30  
31    FLAG_RETURNS_128BITS  = 1 << (31-27), /* cr6  */
32  
33    FLAG_ARG_NEEDS_COPY   = 1 << (31- 7),
34 +#ifndef __NO_FPRS__
35    FLAG_FP_ARGUMENTS     = 1 << (31- 6), /* cr1.eq; specified by ABI */
36 +#endif
37    FLAG_4_GPR_ARGUMENTS  = 1 << (31- 5),
38    FLAG_RETVAL_REFERENCE = 1 << (31- 4)
39  };
40  
41  /* About the SYSV ABI.  */
42 -unsigned int NUM_GPR_ARG_REGISTERS = 8;
43 +#define ASM_NEEDS_REGISTERS 4
44 +#define NUM_GPR_ARG_REGISTERS 8
45  #ifndef __NO_FPRS__
46 -unsigned int NUM_FPR_ARG_REGISTERS = 8;
47 -#else
48 -unsigned int NUM_FPR_ARG_REGISTERS = 0;
49 +# define NUM_FPR_ARG_REGISTERS 8
50  #endif
51  
52 -enum { ASM_NEEDS_REGISTERS = 4 };
53 -
54  /* ffi_prep_args_SYSV is called by the assembly routine once stack space
55     has been allocated for the function's arguments.
56  
57 @@ -110,10 +111,12 @@ ffi_prep_args_SYSV (extended_cif *ecif,
58    valp gpr_base;
59    int intarg_count;
60  
61 +#ifndef __NO_FPRS__
62    /* 'fpr_base' points at the space for fpr1, and grows upwards as
63       we use FPR registers.  */
64    valp fpr_base;
65    int fparg_count;
66 +#endif
67  
68    /* 'copy_space' grows down as we put structures in it.  It should
69       stay 16-byte aligned.  */
70 @@ -122,9 +125,8 @@ ffi_prep_args_SYSV (extended_cif *ecif,
71    /* 'next_arg' grows up as we put parameters in it.  */
72    valp next_arg;
73  
74 -  int i, ii MAYBE_UNUSED;
75 +  int i;
76    ffi_type **ptr;
77 -  double double_tmp;
78    union {
79      void **v;
80      char **c;
81 @@ -140,15 +142,16 @@ ffi_prep_args_SYSV (extended_cif *ecif,
82    size_t struct_copy_size;
83    unsigned gprvalue;
84  
85 -  if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT)
86 -    NUM_FPR_ARG_REGISTERS = 0;
87 -
88    stacktop.c = (char *) stack + bytes;
89    gpr_base.u = stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS;
90    intarg_count = 0;
91 +#ifndef __NO_FPRS__
92    fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS;
93    fparg_count = 0;
94    copy_space.c = ((flags & FLAG_FP_ARGUMENTS) ? fpr_base.c : gpr_base.c);
95 +#else
96 +  copy_space.c = gpr_base.c;
97 +#endif
98    next_arg.u = stack + 2;
99  
100    /* Check that everything starts aligned properly.  */
101 @@ -171,12 +174,28 @@ ffi_prep_args_SYSV (extended_cif *ecif,
102         i > 0;
103         i--, ptr++, p_argv.v++)
104      {
105 -      switch ((*ptr)->type)
106 -       {
107 +      unsigned short typenum = (*ptr)->type;
108 +
109 +      /* We may need to handle some values depending on ABI */
110 +      if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT) {
111 +               if (typenum == FFI_TYPE_FLOAT)
112 +                       typenum = FFI_TYPE_UINT32;
113 +               if (typenum == FFI_TYPE_DOUBLE)
114 +                       typenum = FFI_TYPE_UINT64;
115 +               if (typenum == FFI_TYPE_LONGDOUBLE)
116 +                       typenum = FFI_TYPE_UINT128;
117 +      } else if (ecif->cif->abi != FFI_LINUX) {
118 +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
119 +               if (typenum == FFI_TYPE_LONGDOUBLE)
120 +                       typenum = FFI_TYPE_STRUCT;
121 +#endif
122 +      }
123 +
124 +      /* Now test the translated value */
125 +      switch (typenum) {
126 +#ifndef __NO_FPRS__
127         case FFI_TYPE_FLOAT:
128           /* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32.  */
129 -         if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT)
130 -           goto soft_float_prep;
131           double_tmp = **p_argv.f;
132           if (fparg_count >= NUM_FPR_ARG_REGISTERS)
133             {
134 @@ -215,43 +234,6 @@ ffi_prep_args_SYSV (extended_cif *ecif,
135  
136  #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
137         case FFI_TYPE_LONGDOUBLE:
138 -         if ((ecif->cif->abi != FFI_LINUX)
139 -               && (ecif->cif->abi != FFI_LINUX_SOFT_FLOAT))
140 -           goto do_struct;
141 -         /* The soft float ABI for long doubles works like this,
142 -            a long double is passed in four consecutive gprs if available.
143 -            A maximum of 2 long doubles can be passed in gprs.
144 -            If we do not have 4 gprs left, the long double is passed on the
145 -            stack, 4-byte aligned.  */
146 -         if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT)
147 -           {
148 -             unsigned int int_tmp = (*p_argv.ui)[0];
149 -             if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3)
150 -               {
151 -                 if (intarg_count < NUM_GPR_ARG_REGISTERS)
152 -                   intarg_count += NUM_GPR_ARG_REGISTERS - intarg_count;
153 -                 *next_arg.u = int_tmp;
154 -                 next_arg.u++;
155 -                 for (ii = 1; ii < 4; ii++)
156 -                   {
157 -                     int_tmp = (*p_argv.ui)[ii];
158 -                     *next_arg.u = int_tmp;
159 -                     next_arg.u++;
160 -                   }
161 -               }
162 -             else
163 -               {
164 -                 *gpr_base.u++ = int_tmp;
165 -                 for (ii = 1; ii < 4; ii++)
166 -                   {
167 -                     int_tmp = (*p_argv.ui)[ii];
168 -                     *gpr_base.u++ = int_tmp;
169 -                   }
170 -               }
171 -             intarg_count +=4;
172 -           }
173 -         else
174 -           {
175               double_tmp = (*p_argv.d)[0];
176  
177               if (fparg_count >= NUM_FPR_ARG_REGISTERS - 1)
178 @@ -277,13 +259,40 @@ ffi_prep_args_SYSV (extended_cif *ecif,
179  
180               fparg_count += 2;
181               FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
182 -           }
183           break;
184  #endif
185 +#endif /* have FPRs */
186 +
187 +       /*
188 +        * The soft float ABI for long doubles works like this, a long double
189 +        * is passed in four consecutive GPRs if available.  A maximum of 2
190 +        * long doubles can be passed in gprs.  If we do not have 4 GPRs
191 +        * left, the long double is passed on the stack, 4-byte aligned.
192 +        */
193 +       case FFI_TYPE_UINT128: {
194 +               unsigned int int_tmp = (*p_argv.ui)[0];
195 +               unsigned int ii;
196 +               if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3) {
197 +                       if (intarg_count < NUM_GPR_ARG_REGISTERS)
198 +                               intarg_count += NUM_GPR_ARG_REGISTERS - intarg_count;
199 +                       *(next_arg.u++) = int_tmp;
200 +                       for (ii = 1; ii < 4; ii++) {
201 +                               int_tmp = (*p_argv.ui)[ii];
202 +                               *(next_arg.u++) = int_tmp;
203 +                       }
204 +               } else {
205 +                       *(gpr_base.u++) = int_tmp;
206 +                       for (ii = 1; ii < 4; ii++) {
207 +                               int_tmp = (*p_argv.ui)[ii];
208 +                               *(gpr_base.u++) = int_tmp;
209 +                       }
210 +               }
211 +               intarg_count += 4;
212 +               break;
213 +       }
214  
215         case FFI_TYPE_UINT64:
216         case FFI_TYPE_SINT64:
217 -       soft_double_prep:
218           if (intarg_count == NUM_GPR_ARG_REGISTERS-1)
219             intarg_count++;
220           if (intarg_count >= NUM_GPR_ARG_REGISTERS)
221 @@ -316,9 +325,6 @@ ffi_prep_args_SYSV (extended_cif *ecif,
222           break;
223  
224         case FFI_TYPE_STRUCT:
225 -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
226 -       do_struct:
227 -#endif
228           struct_copy_size = ((*ptr)->size + 15) & ~0xF;
229           copy_space.c -= struct_copy_size;
230           memcpy (copy_space.c, *p_argv.c, (*ptr)->size);
231 @@ -346,7 +352,6 @@ ffi_prep_args_SYSV (extended_cif *ecif,
232         case FFI_TYPE_UINT32:
233         case FFI_TYPE_SINT32:
234         case FFI_TYPE_POINTER:
235 -       soft_float_prep:
236  
237           gprvalue = **p_argv.ui;
238  
239 @@ -363,8 +368,10 @@ ffi_prep_args_SYSV (extended_cif *ecif,
240    /* Check that we didn't overrun the stack...  */
241    FFI_ASSERT (copy_space.c >= next_arg.c);
242    FFI_ASSERT (gpr_base.u <= stacktop.u - ASM_NEEDS_REGISTERS);
243 +#ifndef __NO_FPRS__
244    FFI_ASSERT (fpr_base.u
245               <= stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS);
246 +#endif
247    FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4);
248  }
249  
250 @@ -601,9 +608,6 @@ ffi_prep_cif_machdep (ffi_cif *cif)
251    unsigned type = cif->rtype->type;
252    unsigned size = cif->rtype->size;
253  
254 -  if (cif->abi == FFI_LINUX_SOFT_FLOAT)
255 -    NUM_FPR_ARG_REGISTERS = 0;
256 -
257    if (cif->abi != FFI_LINUX64)
258      {
259        /* All the machine-independent calculation of cif->bytes will be wrong.
260 @@ -643,25 +647,38 @@ ffi_prep_cif_machdep (ffi_cif *cif)
261       - Single/double FP values in fpr1, long double in fpr1,fpr2.
262       - soft-float float/doubles are treated as UINT32/UINT64 respectivley.
263       - soft-float long doubles are returned in gpr3-gpr6.  */
264 +  /* First translate for softfloat/nonlinux */
265 +  if (cif->abi == FFI_LINUX_SOFT_FLOAT) {
266 +       if (type == FFI_TYPE_FLOAT)
267 +               type = FFI_TYPE_UINT32;
268 +       if (type == FFI_TYPE_DOUBLE)
269 +               type = FFI_TYPE_UINT64;
270 +       if (type == FFI_TYPE_LONGDOUBLE)
271 +               type = FFI_TYPE_UINT128;
272 +  } else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) {
273 +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
274 +       if (type == FFI_TYPE_LONGDOUBLE)
275 +               type = FFI_TYPE_STRUCT;
276 +#endif
277 +  }
278 +
279    switch (type)
280      {
281 -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
282 +#ifndef __NO_FPRS__
283      case FFI_TYPE_LONGDOUBLE:
284 -      if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64
285 -       && cif->abi != FFI_LINUX_SOFT_FLOAT)
286 -       goto byref;
287        flags |= FLAG_RETURNS_128BITS;
288        /* Fall through.  */
289 -#endif
290      case FFI_TYPE_DOUBLE:
291        flags |= FLAG_RETURNS_64BITS;
292        /* Fall through.  */
293      case FFI_TYPE_FLOAT:
294 -      /* With FFI_LINUX_SOFT_FLOAT no fp registers are used.  */
295 -      if (cif->abi != FFI_LINUX_SOFT_FLOAT)
296 -       flags |= FLAG_RETURNS_FP;
297 +      flags |= FLAG_RETURNS_FP;
298        break;
299 +#endif
300  
301 +    case FFI_TYPE_UINT128:
302 +      flags |= FLAG_RETURNS_128BITS;
303 +      /* Fall through.  */
304      case FFI_TYPE_UINT64:
305      case FFI_TYPE_SINT64:
306        flags |= FLAG_RETURNS_64BITS;
307 @@ -680,10 +697,6 @@ ffi_prep_cif_machdep (ffi_cif *cif)
308         */
309        if (cif->abi == FFI_SYSV && size <= 8)
310         flags |= FLAG_RETURNS_SMST;
311 -      
312 -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
313 -    byref:
314 -#endif
315        intarg_count++;
316        flags |= FLAG_RETVAL_REFERENCE;
317        /* Fall through.  */
318 @@ -704,39 +717,36 @@ ffi_prep_cif_machdep (ffi_cif *cif)
319         Stuff on the stack needs to keep proper alignment.  */
320      for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
321        {
322 -       switch ((*ptr)->type)
323 -         {
324 +       unsigned short typenum = (*ptr)->type;
325 +
326 +       /* We may need to handle some values depending on ABI */
327 +       if (cif->abi == FFI_LINUX_SOFT_FLOAT) {
328 +               if (typenum == FFI_TYPE_FLOAT)
329 +                       typenum = FFI_TYPE_UINT32;
330 +               if (typenum == FFI_TYPE_DOUBLE)
331 +                       typenum = FFI_TYPE_UINT64;
332 +               if (typenum == FFI_TYPE_LONGDOUBLE)
333 +                       typenum = FFI_TYPE_UINT128;
334 +       } else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) {
335 +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
336 +               if (typenum == FFI_TYPE_LONGDOUBLE)
337 +                       typenum = FFI_TYPE_STRUCT;
338 +#endif
339 +       }
340 +
341 +       switch (typenum) {
342 +#ifndef __NO_FPRS__
343           case FFI_TYPE_FLOAT:
344 -           /* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32.  */
345 -           if (cif->abi == FFI_LINUX_SOFT_FLOAT)
346 -             goto soft_float_cif;
347             fparg_count++;
348             /* floating singles are not 8-aligned on stack */
349             break;
350  
351  #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
352           case FFI_TYPE_LONGDOUBLE:
353 -           if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
354 -             goto do_struct;
355 -           if (cif->abi == FFI_LINUX_SOFT_FLOAT)
356 -             {
357 -               if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3
358 -                 || intarg_count < NUM_GPR_ARG_REGISTERS)
359 -                 /* A long double in FFI_LINUX_SOFT_FLOAT can use only
360 -                    a set of four consecutive gprs. If we have not enough,
361 -                    we have to adjust the intarg_count value.  */
362 -                 intarg_count += NUM_GPR_ARG_REGISTERS - intarg_count;
363 -               intarg_count += 4;
364 -               break;
365 -             }
366 -           else
367 -             fparg_count++;
368 +           fparg_count++;
369             /* Fall thru */
370  #endif
371           case FFI_TYPE_DOUBLE:
372 -           /* With FFI_LINUX_SOFT_FLOAT doubles are handled like UINT64.  */
373 -           if (cif->abi == FFI_LINUX_SOFT_FLOAT)
374 -             goto soft_double_cif;
375             fparg_count++;
376             /* If this FP arg is going on the stack, it must be
377                8-byte-aligned.  */
378 @@ -745,10 +755,21 @@ ffi_prep_cif_machdep (ffi_cif *cif)
379                 && intarg_count % 2 != 0)
380               intarg_count++;
381             break;
382 +#endif
383 +         case FFI_TYPE_UINT128:
384 +               /*
385 +                * A long double in FFI_LINUX_SOFT_FLOAT can use only a set
386 +                * of four consecutive gprs. If we do not have enough, we
387 +                * have to adjust the intarg_count value.
388 +                */
389 +               if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3
390 +                               && intarg_count < NUM_GPR_ARG_REGISTERS)
391 +                       intarg_count = NUM_GPR_ARG_REGISTERS;
392 +               intarg_count += 4;
393 +               break;
394  
395           case FFI_TYPE_UINT64:
396           case FFI_TYPE_SINT64:
397 -         soft_double_cif:
398             /* 'long long' arguments are passed as two words, but
399                either both words must fit in registers or both go
400                on the stack.  If they go on the stack, they must
401 @@ -765,9 +786,6 @@ ffi_prep_cif_machdep (ffi_cif *cif)
402             break;
403  
404           case FFI_TYPE_STRUCT:
405 -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
406 -         do_struct:
407 -#endif
408             /* We must allocate space for a copy of these to enforce
409                pass-by-value.  Pad the space up to a multiple of 16
410                bytes (the maximum alignment required for anything under
411 @@ -775,12 +793,20 @@ ffi_prep_cif_machdep (ffi_cif *cif)
412             struct_copy_size += ((*ptr)->size + 15) & ~0xF;
413             /* Fall through (allocate space for the pointer).  */
414  
415 -         default:
416 -         soft_float_cif:
417 +         case FFI_TYPE_POINTER:
418 +         case FFI_TYPE_INT:
419 +         case FFI_TYPE_UINT32:
420 +         case FFI_TYPE_SINT32:
421 +         case FFI_TYPE_UINT16:
422 +         case FFI_TYPE_SINT16:
423 +         case FFI_TYPE_UINT8:
424 +         case FFI_TYPE_SINT8:
425             /* Everything else is passed as a 4-byte word in a GPR, either
426                the object itself or a pointer to it.  */
427             intarg_count++;
428             break;
429 +         default:
430 +               FFI_ASSERT (0);
431           }
432        }
433    else
434 @@ -809,16 +835,29 @@ ffi_prep_cif_machdep (ffi_cif *cif)
435             intarg_count += ((*ptr)->size + 7) / 8;
436             break;
437  
438 -         default:
439 +         case FFI_TYPE_POINTER:
440 +         case FFI_TYPE_UINT64:
441 +         case FFI_TYPE_SINT64:
442 +         case FFI_TYPE_INT:
443 +         case FFI_TYPE_UINT32:
444 +         case FFI_TYPE_SINT32:
445 +         case FFI_TYPE_UINT16:
446 +         case FFI_TYPE_SINT16:
447 +         case FFI_TYPE_UINT8:
448 +         case FFI_TYPE_SINT8:
449             /* Everything else is passed as a 8-byte word in a GPR, either
450                the object itself or a pointer to it.  */
451             intarg_count++;
452             break;
453 +         default:
454 +               FFI_ASSERT (0);
455           }
456        }
457  
458 +#ifndef __NO_FPRS__
459    if (fparg_count != 0)
460      flags |= FLAG_FP_ARGUMENTS;
461 +#endif
462    if (intarg_count > 4)
463      flags |= FLAG_4_GPR_ARGUMENTS;
464    if (struct_copy_size != 0)
465 @@ -826,21 +865,27 @@ ffi_prep_cif_machdep (ffi_cif *cif)
466  
467    if (cif->abi != FFI_LINUX64)
468      {
469 +#ifndef __NO_FPRS__
470        /* Space for the FPR registers, if needed.  */
471        if (fparg_count != 0)
472         bytes += NUM_FPR_ARG_REGISTERS * sizeof (double);
473 +#endif
474  
475        /* Stack space.  */
476        if (intarg_count > NUM_GPR_ARG_REGISTERS)
477         bytes += (intarg_count - NUM_GPR_ARG_REGISTERS) * sizeof (int);
478 +#ifndef __NO_FPRS__
479        if (fparg_count > NUM_FPR_ARG_REGISTERS)
480         bytes += (fparg_count - NUM_FPR_ARG_REGISTERS) * sizeof (double);
481 +#endif
482      }
483    else
484      {
485 +#ifndef __NO_FPRS__
486        /* Space for the FPR registers, if needed.  */
487        if (fparg_count != 0)
488         bytes += NUM_FPR_ARG_REGISTERS64 * sizeof (double);
489 +#endif
490  
491        /* Stack space.  */
492        if (intarg_count > NUM_GPR_ARG_REGISTERS64)
493 @@ -898,9 +943,11 @@ ffi_call(ffi_cif *cif, void (*fn)(void),
494    switch (cif->abi)
495      {
496  #ifndef POWERPC64
497 +# ifndef __NO_FPRS__
498      case FFI_SYSV:
499      case FFI_GCC_SYSV:
500      case FFI_LINUX:
501 +# endif
502      case FFI_LINUX_SOFT_FLOAT:
503        ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn);
504        break;
505 @@ -1013,32 +1060,38 @@ ffi_closure_helper_SYSV (ffi_closure *cl
506    void **          avalue;
507    ffi_type **      arg_types;
508    long             i, avn;
509 -  long             nf;   /* number of floating registers already used */
510 -  long             ng;   /* number of general registers already used */
511 -  ffi_cif *        cif;
512 -  double           temp;
513 -  unsigned         size;
514 +#ifndef __NO_FPRS__
515 +  long             nf = 0;   /* number of floating registers already used */
516 +#endif
517 +  long             ng = 0;   /* number of general registers already used */
518 +
519 +  ffi_cif *cif = closure->cif;
520 +  unsigned       size     = cif->rtype->size;
521 +  unsigned short rtypenum = cif->rtype->type;
522  
523 -  cif = closure->cif;
524    avalue = alloca (cif->nargs * sizeof (void *));
525 -  size = cif->rtype->size;
526  
527 -  nf = 0;
528 -  ng = 0;
529 +  /* First translate for softfloat/nonlinux */
530 +  if (cif->abi == FFI_LINUX_SOFT_FLOAT) {
531 +       if (rtypenum == FFI_TYPE_FLOAT)
532 +               rtypenum = FFI_TYPE_UINT32;
533 +       if (rtypenum == FFI_TYPE_DOUBLE)
534 +               rtypenum = FFI_TYPE_UINT64;
535 +       if (rtypenum == FFI_TYPE_LONGDOUBLE)
536 +               rtypenum = FFI_TYPE_UINT128;
537 +  } else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) {
538 +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
539 +       if (rtypenum == FFI_TYPE_LONGDOUBLE)
540 +               rtypenum = FFI_TYPE_STRUCT;
541 +#endif
542 +  }
543 +
544  
545    /* Copy the caller's structure return value address so that the closure
546       returns the data directly to the caller.
547       For FFI_SYSV the result is passed in r3/r4 if the struct size is less
548       or equal 8 bytes.  */
549 -
550 -  if ((cif->rtype->type == FFI_TYPE_STRUCT
551 -       && !((cif->abi == FFI_SYSV) && (size <= 8)))
552 -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
553 -      || (cif->rtype->type == FFI_TYPE_LONGDOUBLE
554 -         && cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
555 -#endif
556 -      )
557 -    {
558 +  if (rtypenum == FFI_TYPE_STRUCT && ((cif->abi != FFI_SYSV) || (size > 8))) {
559        rvalue = (void *) *pgr;
560        ng++;
561        pgr++;
562 @@ -1049,10 +1102,109 @@ ffi_closure_helper_SYSV (ffi_closure *cl
563    arg_types = cif->arg_types;
564  
565    /* Grab the addresses of the arguments from the stack frame.  */
566 -  while (i < avn)
567 -    {
568 -      switch (arg_types[i]->type)
569 -       {
570 +  while (i < avn) {
571 +      unsigned short typenum = arg_types[i]->type;
572 +
573 +      /* We may need to handle some values depending on ABI */
574 +      if (cif->abi == FFI_LINUX_SOFT_FLOAT) {
575 +               if (typenum == FFI_TYPE_FLOAT)
576 +                       typenum = FFI_TYPE_UINT32;
577 +               if (typenum == FFI_TYPE_DOUBLE)
578 +                       typenum = FFI_TYPE_UINT64;
579 +               if (typenum == FFI_TYPE_LONGDOUBLE)
580 +                       typenum = FFI_TYPE_UINT128;
581 +      } else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) {
582 +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
583 +               if (typenum == FFI_TYPE_LONGDOUBLE)
584 +                       typenum = FFI_TYPE_STRUCT;
585 +#endif
586 +      }
587 +
588 +      switch (typenum) {
589 +#ifndef __NO_FPRS__
590 +       case FFI_TYPE_FLOAT:
591 +         /* unfortunately float values are stored as doubles
592 +          * in the ffi_closure_SYSV code (since we don't check
593 +          * the type in that routine).
594 +          */
595 +
596 +         /* there are 8 64bit floating point registers */
597 +
598 +         if (nf < 8)
599 +           {
600 +             temp = pfr->d;
601 +             pfr->f = (float) temp;
602 +             avalue[i] = pfr;
603 +             nf++;
604 +             pfr++;
605 +           }
606 +         else
607 +           {
608 +             /* FIXME? here we are really changing the values
609 +              * stored in the original calling routines outgoing
610 +              * parameter stack.  This is probably a really
611 +              * naughty thing to do but...
612 +              */
613 +             avalue[i] = pst;
614 +             pst += 1;
615 +           }
616 +         break;
617 +
618 +       case FFI_TYPE_DOUBLE:
619 +         /* On the outgoing stack all values are aligned to 8 */
620 +         /* there are 8 64bit floating point registers */
621 +
622 +         if (nf < 8)
623 +           {
624 +             avalue[i] = pfr;
625 +             nf++;
626 +             pfr++;
627 +           }
628 +         else
629 +           {
630 +             if (((long) pst) & 4)
631 +               pst++;
632 +             avalue[i] = pst;
633 +             pst += 2;
634 +           }
635 +         break;
636 +
637 +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
638 +       case FFI_TYPE_LONGDOUBLE:
639 +         if (nf < 7)
640 +           {
641 +             avalue[i] = pfr;
642 +             pfr += 2;
643 +             nf += 2;
644 +           }
645 +         else
646 +           {
647 +             if (((long) pst) & 4)
648 +               pst++;
649 +             avalue[i] = pst;
650 +             pst += 4;
651 +             nf = 8;
652 +           }
653 +         break;
654 +#endif
655 +#endif /* have FPRS */
656 +
657 +       case FFI_TYPE_UINT128:
658 +               /*
659 +                * Test if for the whole long double, 4 gprs are available.
660 +                * otherwise the stuff ends up on the stack.
661 +                */
662 +               if (ng < 5) {
663 +                       avalue[i] = pgr;
664 +                       pgr += 4;
665 +                       ng += 4;
666 +               } else {
667 +                       avalue[i] = pst;
668 +                       pst += 4;
669 +                       ng = 8+4;
670 +               }
671 +               break;
672 +
673         case FFI_TYPE_SINT8:
674         case FFI_TYPE_UINT8:
675           /* there are 8 gpr registers used to pass values */
676 @@ -1088,7 +1240,6 @@ ffi_closure_helper_SYSV (ffi_closure *cl
677         case FFI_TYPE_SINT32:
678         case FFI_TYPE_UINT32:
679         case FFI_TYPE_POINTER:
680 -       soft_float_closure:
681           /* there are 8 gpr registers used to pass values */
682           if (ng < 8)
683             {
684 @@ -1104,9 +1255,6 @@ ffi_closure_helper_SYSV (ffi_closure *cl
685           break;
686  
687         case FFI_TYPE_STRUCT:
688 -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
689 -       do_struct:
690 -#endif
691           /* Structs are passed by reference. The address will appear in a
692              gpr if it is one of the first 8 arguments.  */
693           if (ng < 8)
694 @@ -1124,7 +1272,6 @@ ffi_closure_helper_SYSV (ffi_closure *cl
695  
696         case FFI_TYPE_SINT64:
697         case FFI_TYPE_UINT64:
698 -       soft_double_closure:
699           /* passing long long ints are complex, they must
700            * be passed in suitable register pairs such as
701            * (r3,r4) or (r5,r6) or (r6,r7), or (r7,r8) or (r9,r10)
702 @@ -1156,99 +1303,8 @@ ffi_closure_helper_SYSV (ffi_closure *cl
703             }
704           break;
705  
706 -       case FFI_TYPE_FLOAT:
707 -         /* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32.  */
708 -         if (cif->abi == FFI_LINUX_SOFT_FLOAT)
709 -           goto soft_float_closure;
710 -         /* unfortunately float values are stored as doubles
711 -          * in the ffi_closure_SYSV code (since we don't check
712 -          * the type in that routine).
713 -          */
714 -
715 -         /* there are 8 64bit floating point registers */
716 -
717 -         if (nf < 8)
718 -           {
719 -             temp = pfr->d;
720 -             pfr->f = (float) temp;
721 -             avalue[i] = pfr;
722 -             nf++;
723 -             pfr++;
724 -           }
725 -         else
726 -           {
727 -             /* FIXME? here we are really changing the values
728 -              * stored in the original calling routines outgoing
729 -              * parameter stack.  This is probably a really
730 -              * naughty thing to do but...
731 -              */
732 -             avalue[i] = pst;
733 -             pst += 1;
734 -           }
735 -         break;
736 -
737 -       case FFI_TYPE_DOUBLE:
738 -         /* With FFI_LINUX_SOFT_FLOAT doubles are handled like UINT64.  */
739 -         if (cif->abi == FFI_LINUX_SOFT_FLOAT)
740 -           goto soft_double_closure;
741 -         /* On the outgoing stack all values are aligned to 8 */
742 -         /* there are 8 64bit floating point registers */
743 -
744 -         if (nf < 8)
745 -           {
746 -             avalue[i] = pfr;
747 -             nf++;
748 -             pfr++;
749 -           }
750 -         else
751 -           {
752 -             if (((long) pst) & 4)
753 -               pst++;
754 -             avalue[i] = pst;
755 -             pst += 2;
756 -           }
757 -         break;
758 -
759 -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
760 -       case FFI_TYPE_LONGDOUBLE:
761 -         if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
762 -           goto do_struct;
763 -         if (cif->abi == FFI_LINUX_SOFT_FLOAT)
764 -           { /* Test if for the whole long double, 4 gprs are available.
765 -                otherwise the stuff ends up on the stack.  */
766 -             if (ng < 5)
767 -               {
768 -                 avalue[i] = pgr;
769 -                 pgr += 4;
770 -                 ng += 4;
771 -               }
772 -             else
773 -               {
774 -                 avalue[i] = pst;
775 -                 pst += 4;
776 -                 ng = 8;
777 -               }
778 -             break;
779 -           }
780 -         if (nf < 7)
781 -           {
782 -             avalue[i] = pfr;
783 -             pfr += 2;
784 -             nf += 2;
785 -           }
786 -         else
787 -           {
788 -             if (((long) pst) & 4)
789 -               pst++;
790 -             avalue[i] = pst;
791 -             pst += 4;
792 -             nf = 8;
793 -           }
794 -         break;
795 -#endif
796 -
797         default:
798 -         FFI_ASSERT (0);
799 +               FFI_ASSERT (0);
800         }
801  
802        i++;
803 @@ -1265,39 +1321,9 @@ ffi_closure_helper_SYSV (ffi_closure *cl
804       already used and we never have a struct with size zero. That is the reason
805       for the subtraction of 1. See the comment in ffitarget.h about ordering.
806    */
807 -  if (cif->abi == FFI_SYSV && cif->rtype->type == FFI_TYPE_STRUCT
808 -      && size <= 8)
809 +  if (cif->abi == FFI_SYSV && rtypenum == FFI_TYPE_STRUCT && size <= 8)
810      return (FFI_SYSV_TYPE_SMALL_STRUCT - 1) + size;
811 -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
812 -  else if (cif->rtype->type == FFI_TYPE_LONGDOUBLE
813 -          && cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
814 -    return FFI_TYPE_STRUCT;
815 -#endif
816 -  /* With FFI_LINUX_SOFT_FLOAT floats and doubles are handled like UINT32
817 -     respectivley UINT64.  */
818 -  if (cif->abi == FFI_LINUX_SOFT_FLOAT)
819 -    {
820 -      switch (cif->rtype->type)
821 -       {
822 -       case FFI_TYPE_FLOAT:
823 -         return FFI_TYPE_UINT32;
824 -         break;
825 -       case FFI_TYPE_DOUBLE:
826 -         return FFI_TYPE_UINT64;
827 -         break;
828 -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
829 -       case FFI_TYPE_LONGDOUBLE:
830 -         return FFI_TYPE_UINT128;
831 -         break;
832 -#endif
833 -       default:
834 -         return cif->rtype->type;
835 -       }
836 -    }
837 -  else
838 -    {
839 -      return cif->rtype->type;
840 -    }
841 +  return rtypenum;
842  }
843  
844  int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_closure *, void *,
845 Index: libffi/src/powerpc/ffitarget.h
846 ===================================================================
847 --- libffi.orig/src/powerpc/ffitarget.h
848 +++ libffi/src/powerpc/ffitarget.h
849 @@ -60,18 +60,14 @@ typedef enum ffi_abi {
850    FFI_LINUX64,
851    FFI_LINUX,
852    FFI_LINUX_SOFT_FLOAT,
853 -# ifdef POWERPC64
854 +# if defined(POWERPC64)
855    FFI_DEFAULT_ABI = FFI_LINUX64,
856 -# else
857 -#  if (!defined(__NO_FPRS__) && (__LDBL_MANT_DIG__ == 106))
858 -  FFI_DEFAULT_ABI = FFI_LINUX,
859 -#  else
860 -#   ifdef __NO_FPRS__
861 +# elif defined(__NO_FPRS__)
862    FFI_DEFAULT_ABI = FFI_LINUX_SOFT_FLOAT,
863 -#   else
864 +# elif (__LDBL_MANT_DIG__ == 106)
865 +  FFI_DEFAULT_ABI = FFI_LINUX,
866 +# else
867    FFI_DEFAULT_ABI = FFI_GCC_SYSV,
868 -#   endif
869 -#  endif
870  # endif
871  #endif
872  
873 Index: libffi/src/powerpc/ppc_closure.S
874 ===================================================================
875 --- libffi.orig/src/powerpc/ppc_closure.S
876 +++ libffi/src/powerpc/ppc_closure.S
877 @@ -122,22 +122,41 @@ ENTRY(ffi_closure_SYSV)
878         blr
879  
880  # case FFI_TYPE_FLOAT
881 +#ifndef __NO_FPRS__
882         lfs %f1,112+0(%r1)
883         mtlr %r0
884         addi %r1,%r1,144
885 +#else
886 +       nop
887 +       nop
888 +       nop
889 +#endif
890         blr
891  
892  # case FFI_TYPE_DOUBLE
893 +#ifndef __NO_FPRS__
894         lfd %f1,112+0(%r1)
895         mtlr %r0
896         addi %r1,%r1,144
897 +#else
898 +       nop
899 +       nop
900 +       nop
901 +#endif
902         blr
903  
904  # case FFI_TYPE_LONGDOUBLE
905 +#ifndef __NO_FPRS__
906         lfd %f1,112+0(%r1)
907         lfd %f2,112+8(%r1)
908         mtlr %r0
909         b .Lfinish
910 +#else
911 +       nop
912 +       nop
913 +       nop
914 +       blr
915 +#endif
916  
917  # case FFI_TYPE_UINT8
918         lbz %r3,112+3(%r1)
919 Index: libffi/src/powerpc/sysv.S
920 ===================================================================
921 --- libffi.orig/src/powerpc/sysv.S
922 +++ libffi/src/powerpc/sysv.S
923 @@ -83,6 +83,7 @@ ENTRY(ffi_call_SYSV)
924         nop
925  1:
926  
927 +#ifndef __NO_FPRS__
928         /* Load all the FP registers.  */
929         bf-     6,2f
930         lfd     %f1,-16-(8*4)-(8*8)(%r28)
931 @@ -94,6 +95,7 @@ ENTRY(ffi_call_SYSV)
932         lfd     %f6,-16-(8*4)-(3*8)(%r28)
933         lfd     %f7,-16-(8*4)-(2*8)(%r28)
934         lfd     %f8,-16-(8*4)-(1*8)(%r28)
935 +#endif
936  2:
937  
938         /* Make the call.  */
939 @@ -103,7 +105,9 @@ ENTRY(ffi_call_SYSV)
940         mtcrf   0x01,%r31 /* cr7  */
941         bt-     31,L(small_struct_return_value)
942         bt-     30,L(done_return_value)
943 +#ifndef __NO_FPRS__
944         bt-     29,L(fp_return_value)
945 +#endif
946         stw     %r3,0(%r30)
947         bf+     28,L(done_return_value)
948         stw     %r4,4(%r30)
949 @@ -124,6 +128,7 @@ L(done_return_value):
950         lwz     %r1,0(%r1)
951         blr
952  
953 +#ifndef __NO_FPRS__
954  L(fp_return_value):
955         bf      28,L(float_return_value)
956         stfd    %f1,0(%r30)
957 @@ -134,6 +139,7 @@ L(fp_return_value):
958  L(float_return_value):
959         stfs    %f1,0(%r30)
960         b       L(done_return_value)
961 +#endif
962  
963  L(small_struct_return_value):
964         /*