OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libffi/] [src/] [powerpc/] [ffi_darwin.c] - Blame information for rev 14

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
/* -----------------------------------------------------------------------
2
   ffi.c - Copyright (c) 1998 Geoffrey Keating
3
 
4
   PowerPC Foreign Function Interface
5
 
6
   Darwin ABI support (c) 2001 John Hornkvist
7
   AIX ABI support (c) 2002 Free Software Foundation, Inc.
8
 
9
   Permission is hereby granted, free of charge, to any person obtaining
10
   a copy of this software and associated documentation files (the
11
   ``Software''), to deal in the Software without restriction, including
12
   without limitation the rights to use, copy, modify, merge, publish,
13
   distribute, sublicense, and/or sell copies of the Software, and to
14
   permit persons to whom the Software is furnished to do so, subject to
15
   the following conditions:
16
 
17
   The above copyright notice and this permission notice shall be included
18
   in all copies or substantial portions of the Software.
19
 
20
   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
21
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23
   IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
24
   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25
   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26
   OTHER DEALINGS IN THE SOFTWARE.
27
   ----------------------------------------------------------------------- */
28
 
29
#include <ffi.h>
30
#include <ffi_common.h>
31
 
32
#include <stdlib.h>
33
 
34
extern void ffi_closure_ASM(void);
35
 
36
enum {
37
  /* The assembly depends on these exact flags.  */
38
  FLAG_RETURNS_NOTHING  = 1 << (31-30), /* These go in cr7  */
39
  FLAG_RETURNS_FP       = 1 << (31-29),
40
  FLAG_RETURNS_64BITS   = 1 << (31-28),
41
  FLAG_RETURNS_128BITS  = 1 << (31-31),
42
 
43
  FLAG_ARG_NEEDS_COPY   = 1 << (31- 7),
44
  FLAG_FP_ARGUMENTS     = 1 << (31- 6), /* cr1.eq; specified by ABI  */
45
  FLAG_4_GPR_ARGUMENTS  = 1 << (31- 5),
46
  FLAG_RETVAL_REFERENCE = 1 << (31- 4)
47
};
48
 
49
/* About the DARWIN ABI.  */
50
enum {
51
  NUM_GPR_ARG_REGISTERS = 8,
52
  NUM_FPR_ARG_REGISTERS = 13
53
};
54
enum { ASM_NEEDS_REGISTERS = 4 };
55
 
56
/* ffi_prep_args is called by the assembly routine once stack space
57
   has been allocated for the function's arguments.
58
 
59
   The stack layout we want looks like this:
60
 
61
   |   Return address from ffi_call_DARWIN      |       higher addresses
62
   |--------------------------------------------|
63
   |   Previous backchain pointer       4       |       stack pointer here
64
   |--------------------------------------------|<+ <<< on entry to
65
   |   Saved r28-r31                    4*4     | |     ffi_call_DARWIN
66
   |--------------------------------------------| |
67
   |   Parameters             (at least 8*4=32) | |
68
   |--------------------------------------------| |
69
   |   Space for GPR2                   4       | |
70
   |--------------------------------------------| |     stack   |
71
   |   Reserved                       2*4       | |     grows   |
72
   |--------------------------------------------| |     down    V
73
   |   Space for callee's LR            4       | |
74
   |--------------------------------------------| |     lower addresses
75
   |   Saved CR                         4       | |
76
   |--------------------------------------------| |     stack pointer here
77
   |   Current backchain pointer        4       |-/     during
78
   |--------------------------------------------|   <<< ffi_call_DARWIN
79
 
80
   */
81
 
82
/*@-exportheader@*/
83
void ffi_prep_args(extended_cif *ecif, unsigned *const stack)
84
/*@=exportheader@*/
85
{
86
  const unsigned bytes = ecif->cif->bytes;
87
  const unsigned flags = ecif->cif->flags;
88
 
89
  /* 'stacktop' points at the previous backchain pointer.  */
90
  unsigned *const stacktop = stack + (bytes / sizeof(unsigned));
91
 
92
  /* 'fpr_base' points at the space for fpr1, and grows upwards as
93
     we use FPR registers.  */
94
  double *fpr_base = (double*) (stacktop - ASM_NEEDS_REGISTERS) - NUM_FPR_ARG_REGISTERS;
95
  int fparg_count = 0;
96
 
97
 
98
  /* 'next_arg' grows up as we put parameters in it.  */
99
  unsigned *next_arg = stack + 6; /* 6 reserved positions.  */
100
 
101
  int i = ecif->cif->nargs;
102
  double double_tmp;
103
  void **p_argv = ecif->avalue;
104
  unsigned gprvalue;
105
  ffi_type** ptr = ecif->cif->arg_types;
106
  char *dest_cpy;
107
  unsigned size_al = 0;
108
 
109
  /* Check that everything starts aligned properly.  */
110
  FFI_ASSERT(((unsigned)(char *)stack & 0xF) == 0);
111
  FFI_ASSERT(((unsigned)(char *)stacktop & 0xF) == 0);
112
  FFI_ASSERT((bytes & 0xF) == 0);
113
 
114
  /* Deal with return values that are actually pass-by-reference.
115
     Rule:
116
     Return values are referenced by r3, so r4 is the first parameter.  */
117
 
118
  if (flags & FLAG_RETVAL_REFERENCE)
119
    *next_arg++ = (unsigned)(char *)ecif->rvalue;
120
 
121
  /* Now for the arguments.  */
122
  for (;
123
       i > 0;
124
       i--, ptr++, p_argv++)
125
    {
126
      switch ((*ptr)->type)
127
        {
128
        /* If a floating-point parameter appears before all of the general-
129
           purpose registers are filled, the corresponding GPRs that match
130
           the size of the floating-point parameter are skipped.  */
131
        case FFI_TYPE_FLOAT:
132
          double_tmp = *(float *)*p_argv;
133
          if (fparg_count >= NUM_FPR_ARG_REGISTERS)
134
            *(double *)next_arg = double_tmp;
135
          else
136
            *fpr_base++ = double_tmp;
137
          next_arg++;
138
          fparg_count++;
139
          FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
140
          break;
141
 
142
        case FFI_TYPE_DOUBLE:
143
          double_tmp = *(double *)*p_argv;
144
          if (fparg_count >= NUM_FPR_ARG_REGISTERS)
145
            *(double *)next_arg = double_tmp;
146
          else
147
            *fpr_base++ = double_tmp;
148
          next_arg += 2;
149
          fparg_count++;
150
          FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
151
          break;
152
 
153
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
154
 
155
        case FFI_TYPE_LONGDOUBLE:
156
          double_tmp = ((double *)*p_argv)[0];
157
          if (fparg_count >= NUM_FPR_ARG_REGISTERS)
158
            *(double *)next_arg = double_tmp;
159
          else
160
            *fpr_base++ = double_tmp;
161
          next_arg += 2;
162
          fparg_count++;
163
          double_tmp = ((double *)*p_argv)[1];
164
          if (fparg_count >= NUM_FPR_ARG_REGISTERS)
165
            *(double *)next_arg = double_tmp;
166
          else
167
            *fpr_base++ = double_tmp;
168
          next_arg += 2;
169
          fparg_count++;
170
          FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
171
          break;
172
#endif
173
        case FFI_TYPE_UINT64:
174
        case FFI_TYPE_SINT64:
175
          *(long long *)next_arg = *(long long *)*p_argv;
176
          next_arg+=2;
177
          break;
178
        case FFI_TYPE_UINT8:
179
          gprvalue = *(unsigned char *)*p_argv;
180
          goto putgpr;
181
        case FFI_TYPE_SINT8:
182
          gprvalue = *(signed char *)*p_argv;
183
          goto putgpr;
184
        case FFI_TYPE_UINT16:
185
          gprvalue = *(unsigned short *)*p_argv;
186
          goto putgpr;
187
        case FFI_TYPE_SINT16:
188
          gprvalue = *(signed short *)*p_argv;
189
          goto putgpr;
190
 
191
        case FFI_TYPE_STRUCT:
192
          dest_cpy = (char *) next_arg;
193
 
194
          /* Structures that match the basic modes (QI 1 byte, HI 2 bytes,
195
             SI 4 bytes) are aligned as if they were those modes.
196
             Structures with 3 byte in size are padded upwards.  */
197
          size_al = (*ptr)->size;
198
          /* If the first member of the struct is a double, then align
199
             the struct to double-word.
200
             Type 3 is defined in include/ffi.h. #define FFI_TYPE_DOUBLE 3.  */
201
          if ((*ptr)->elements[0]->type == 3)
202
            size_al = ALIGN((*ptr)->size, 8);
203
          if (size_al < 3 && ecif->cif->abi == FFI_DARWIN)
204
            dest_cpy += 4 - size_al;
205
 
206
          memcpy((char *)dest_cpy, (char *)*p_argv, size_al);
207
          next_arg += (size_al + 3) / 4;
208
          break;
209
 
210
        case FFI_TYPE_INT:
211
        case FFI_TYPE_UINT32:
212
        case FFI_TYPE_SINT32:
213
        case FFI_TYPE_POINTER:
214
          gprvalue = *(unsigned *)*p_argv;
215
        putgpr:
216
          *next_arg++ = gprvalue;
217
          break;
218
        default:
219
          break;
220
        }
221
    }
222
 
223
  /* Check that we didn't overrun the stack...  */
224
  //FFI_ASSERT(gpr_base <= stacktop - ASM_NEEDS_REGISTERS);
225
  //FFI_ASSERT((unsigned *)fpr_base
226
  //         <= stacktop - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS);
227
  //FFI_ASSERT(flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4);
228
}
229
 
230
/* Perform machine dependent cif processing.  */
231
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
232
{
233
  /* All this is for the DARWIN ABI.  */
234
  int i;
235
  ffi_type **ptr;
236
  unsigned bytes;
237
  int fparg_count = 0, intarg_count = 0;
238
  unsigned flags = 0;
239
  unsigned size_al = 0;
240
 
241
  /* All the machine-independent calculation of cif->bytes will be wrong.
242
     Redo the calculation for DARWIN.  */
243
 
244
  /* Space for the frame pointer, callee's LR, CR, etc, and for
245
     the asm's temp regs.  */
246
 
247
  bytes = (6 + ASM_NEEDS_REGISTERS) * sizeof(long);
248
 
249
  /* Return value handling.  The rules are as follows:
250
     - 32-bit (or less) integer values are returned in gpr3;
251
     - Structures of size <= 4 bytes also returned in gpr3;
252
     - 64-bit integer values and structures between 5 and 8 bytes are returned
253
       in gpr3 and gpr4;
254
     - Single/double FP values are returned in fpr1;
255
     - Long double FP (if not equivalent to double) values are returned in
256
       fpr1 and fpr2;
257
     - Larger structures values are allocated space and a pointer is passed
258
       as the first argument.  */
259
  switch (cif->rtype->type)
260
    {
261
 
262
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
263
    case FFI_TYPE_LONGDOUBLE:
264
      flags |= FLAG_RETURNS_128BITS;
265
      flags |= FLAG_RETURNS_FP;
266
      break;
267
#endif
268
 
269
    case FFI_TYPE_DOUBLE:
270
      flags |= FLAG_RETURNS_64BITS;
271
      /* Fall through.  */
272
    case FFI_TYPE_FLOAT:
273
      flags |= FLAG_RETURNS_FP;
274
      break;
275
 
276
    case FFI_TYPE_UINT64:
277
    case FFI_TYPE_SINT64:
278
      flags |= FLAG_RETURNS_64BITS;
279
      break;
280
 
281
    case FFI_TYPE_STRUCT:
282
      flags |= FLAG_RETVAL_REFERENCE;
283
      flags |= FLAG_RETURNS_NOTHING;
284
      intarg_count++;
285
      break;
286
    case FFI_TYPE_VOID:
287
      flags |= FLAG_RETURNS_NOTHING;
288
      break;
289
 
290
    default:
291
      /* Returns 32-bit integer, or similar.  Nothing to do here.  */
292
      break;
293
    }
294
 
295
  /* The first NUM_GPR_ARG_REGISTERS words of integer arguments, and the
296
     first NUM_FPR_ARG_REGISTERS fp arguments, go in registers; the rest
297
     goes on the stack.  Structures are passed as a pointer to a copy of
298
     the structure. Stuff on the stack needs to keep proper alignment.  */
299
  for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
300
    {
301
      switch ((*ptr)->type)
302
        {
303
        case FFI_TYPE_FLOAT:
304
        case FFI_TYPE_DOUBLE:
305
          fparg_count++;
306
          /* If this FP arg is going on the stack, it must be
307
             8-byte-aligned.  */
308
          if (fparg_count > NUM_FPR_ARG_REGISTERS
309
              && intarg_count%2 != 0)
310
            intarg_count++;
311
          break;
312
 
313
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
314
 
315
        case FFI_TYPE_LONGDOUBLE:
316
          fparg_count += 2;
317
          /* If this FP arg is going on the stack, it must be
318
             8-byte-aligned.  */
319
          if (fparg_count > NUM_FPR_ARG_REGISTERS
320
              && intarg_count%2 != 0)
321
            intarg_count++;
322
          intarg_count +=2;
323
          break;
324
#endif
325
 
326
        case FFI_TYPE_UINT64:
327
        case FFI_TYPE_SINT64:
328
          /* 'long long' arguments are passed as two words, but
329
             either both words must fit in registers or both go
330
             on the stack.  If they go on the stack, they must
331
             be 8-byte-aligned.  */
332
          if (intarg_count == NUM_GPR_ARG_REGISTERS-1
333
              || (intarg_count >= NUM_GPR_ARG_REGISTERS && intarg_count%2 != 0))
334
            intarg_count++;
335
          intarg_count += 2;
336
          break;
337
 
338
        case FFI_TYPE_STRUCT:
339
          size_al = (*ptr)->size;
340
          /* If the first member of the struct is a double, then align
341
             the struct to double-word.
342
             Type 3 is defined in include/ffi.h. #define FFI_TYPE_DOUBLE 3.  */
343
          if ((*ptr)->elements[0]->type == 3)
344
            size_al = ALIGN((*ptr)->size, 8);
345
          intarg_count += (size_al + 3) / 4;
346
          break;
347
 
348
        default:
349
          /* Everything else is passed as a 4-byte word in a GPR, either
350
             the object itself or a pointer to it.  */
351
          intarg_count++;
352
          break;
353
        }
354
    }
355
 
356
  if (fparg_count != 0)
357
    flags |= FLAG_FP_ARGUMENTS;
358
 
359
  /* Space for the FPR registers, if needed.  */
360
  if (fparg_count != 0)
361
    bytes += NUM_FPR_ARG_REGISTERS * sizeof(double);
362
 
363
  /* Stack space.  */
364
  if ((intarg_count + 2 * fparg_count) > NUM_GPR_ARG_REGISTERS)
365
    bytes += (intarg_count + 2 * fparg_count) * sizeof(long);
366
  else
367
    bytes += NUM_GPR_ARG_REGISTERS * sizeof(long);
368
 
369
  /* The stack space allocated needs to be a multiple of 16 bytes.  */
370
  bytes = (bytes + 15) & ~0xF;
371
 
372
  cif->flags = flags;
373
  cif->bytes = bytes;
374
 
375
  return FFI_OK;
376
}
377
 
378
/*@-declundef@*/
379
/*@-exportheader@*/
380
extern void ffi_call_AIX(/*@out@*/ extended_cif *,
381
                         unsigned, unsigned,
382
                         /*@out@*/ unsigned *,
383
                         void (*fn)(),
384
                         void (*fn2)());
385
extern void ffi_call_DARWIN(/*@out@*/ extended_cif *,
386
                            unsigned, unsigned,
387
                            /*@out@*/ unsigned *,
388
                            void (*fn)(),
389
                            void (*fn2)());
390
/*@=declundef@*/
391
/*@=exportheader@*/
392
 
393
void ffi_call(/*@dependent@*/ ffi_cif *cif,
394
              void (*fn)(),
395
              /*@out@*/ void *rvalue,
396
              /*@dependent@*/ void **avalue)
397
{
398
  extended_cif ecif;
399
 
400
  ecif.cif = cif;
401
  ecif.avalue = avalue;
402
 
403
  /* If the return value is a struct and we don't have a return
404
     value address then we need to make one.  */
405
 
406
  if ((rvalue == NULL) &&
407
      (cif->rtype->type == FFI_TYPE_STRUCT))
408
    {
409
      /*@-sysunrecog@*/
410
      ecif.rvalue = alloca(cif->rtype->size);
411
      /*@=sysunrecog@*/
412
    }
413
  else
414
    ecif.rvalue = rvalue;
415
 
416
  switch (cif->abi)
417
    {
418
    case FFI_AIX:
419
      /*@-usedef@*/
420
      ffi_call_AIX(&ecif, -cif->bytes,
421
                   cif->flags, ecif.rvalue, fn, ffi_prep_args);
422
      /*@=usedef@*/
423
      break;
424
    case FFI_DARWIN:
425
      /*@-usedef@*/
426
      ffi_call_DARWIN(&ecif, -cif->bytes,
427
                      cif->flags, ecif.rvalue, fn, ffi_prep_args);
428
      /*@=usedef@*/
429
      break;
430
    default:
431
      FFI_ASSERT(0);
432
      break;
433
    }
434
}
435
 
436
static void flush_icache(char *);
437
static void flush_range(char *, int);
438
 
439
/* The layout of a function descriptor.  A C function pointer really
440
   points to one of these.  */
441
 
442
typedef struct aix_fd_struct {
443
  void *code_pointer;
444
  void *toc;
445
} aix_fd;
446
 
447
/* here I'd like to add the stack frame layout we use in darwin_closure.S
448
   and aix_clsoure.S
449
 
450
   SP previous -> +---------------------------------------+ <--- child frame
451
                  | back chain to caller 4                |
452
                  +---------------------------------------+ 4
453
                  | saved CR 4                            |
454
                  +---------------------------------------+ 8
455
                  | saved LR 4                            |
456
                  +---------------------------------------+ 12
457
                  | reserved for compilers 4              |
458
                  +---------------------------------------+ 16
459
                  | reserved for binders 4                |
460
                  +---------------------------------------+ 20
461
                  | saved TOC pointer 4                   |
462
                  +---------------------------------------+ 24
463
                  | always reserved 8*4=32 (previous GPRs)|
464
                  | according to the linkage convention   |
465
                  | from AIX                              |
466
                  +---------------------------------------+ 56
467
                  | our FPR area 13*8=104                 |
468
                  | f1                                    |
469
                  | .                                     |
470
                  | f13                                   |
471
                  +---------------------------------------+ 160
472
                  | result area 8                         |
473
                  +---------------------------------------+ 168
474
                  | alignement to the next multiple of 16 |
475
SP current -->    +---------------------------------------+ 176 <- parent frame
476
                  | back chain to caller 4                |
477
                  +---------------------------------------+ 180
478
                  | saved CR 4                            |
479
                  +---------------------------------------+ 184
480
                  | saved LR 4                            |
481
                  +---------------------------------------+ 188
482
                  | reserved for compilers 4              |
483
                  +---------------------------------------+ 192
484
                  | reserved for binders 4                |
485
                  +---------------------------------------+ 196
486
                  | saved TOC pointer 4                   |
487
                  +---------------------------------------+ 200
488
                  | always reserved 8*4=32  we store our  |
489
                  | GPRs here                             |
490
                  | r3                                    |
491
                  | .                                     |
492
                  | r10                                   |
493
                  +---------------------------------------+ 232
494
                  | overflow part                         |
495
                  +---------------------------------------+ xxx
496
                  | ????                                  |
497
                  +---------------------------------------+ xxx
498
 
499
*/
500
ffi_status
501
ffi_prep_closure (ffi_closure* closure,
502
                  ffi_cif* cif,
503
                  void (*fun)(ffi_cif*, void*, void**, void*),
504
                  void *user_data)
505
{
506
  unsigned int *tramp;
507
  struct ffi_aix_trampoline_struct *tramp_aix;
508
  aix_fd *fd;
509
 
510
  switch (cif->abi)
511
    {
512
    case FFI_DARWIN:
513
 
514
      FFI_ASSERT (cif->abi == FFI_DARWIN);
515
 
516
      tramp = (unsigned int *) &closure->tramp[0];
517
      tramp[0] = 0x7c0802a6;  /*   mflr    r0  */
518
      tramp[1] = 0x429f000d;  /*   bcl-    20,4*cr7+so,0x10  */
519
      tramp[4] = 0x7d6802a6;  /*   mflr    r11  */
520
      tramp[5] = 0x818b0000;  /*   lwz     r12,0(r11) function address  */
521
      tramp[6] = 0x7c0803a6;  /*   mtlr    r0   */
522
      tramp[7] = 0x7d8903a6;  /*   mtctr   r12  */
523
      tramp[8] = 0x816b0004;  /*   lwz     r11,4(r11) static chain  */
524
      tramp[9] = 0x4e800420;  /*   bctr  */
525
      tramp[2] = (unsigned long) ffi_closure_ASM; /* function  */
526
      tramp[3] = (unsigned long) closure; /* context  */
527
 
528
      closure->cif = cif;
529
      closure->fun = fun;
530
      closure->user_data = user_data;
531
 
532
      /* Flush the icache. Only necessary on Darwin.  */
533
      flush_range(&closure->tramp[0],FFI_TRAMPOLINE_SIZE);
534
 
535
      break;
536
 
537
    case FFI_AIX:
538
 
539
      tramp_aix = (struct ffi_aix_trampoline_struct *) (closure->tramp);
540
      fd = (aix_fd *)(void *)ffi_closure_ASM;
541
 
542
      FFI_ASSERT (cif->abi == FFI_AIX);
543
 
544
      tramp_aix->code_pointer = fd->code_pointer;
545
      tramp_aix->toc = fd->toc;
546
      tramp_aix->static_chain = closure;
547
      closure->cif = cif;
548
      closure->fun = fun;
549
      closure->user_data = user_data;
550
 
551
    default:
552
 
553
      FFI_ASSERT(0);
554
      break;
555
    }
556
  return FFI_OK;
557
}
558
 
559
static void
560
flush_icache(char *addr)
561
{
562
#ifndef _AIX
563
  __asm__ volatile (
564
                "dcbf 0,%0\n"
565
                "\tsync\n"
566
                "\ticbi 0,%0\n"
567
                "\tsync\n"
568
                "\tisync"
569
                : : "r"(addr) : "memory");
570
#endif
571
}
572
 
573
static void
574
flush_range(char * addr1, int size)
575
{
576
#define MIN_LINE_SIZE 32
577
  int i;
578
  for (i = 0; i < size; i += MIN_LINE_SIZE)
579
    flush_icache(addr1+i);
580
  flush_icache(addr1+size-1);
581
}
582
 
583
typedef union
584
{
585
  float f;
586
  double d;
587
} ffi_dblfl;
588
 
589
int ffi_closure_helper_DARWIN (ffi_closure*, void*,
590
                               unsigned long*, ffi_dblfl*);
591
 
592
/* Basically the trampoline invokes ffi_closure_ASM, and on
593
   entry, r11 holds the address of the closure.
594
   After storing the registers that could possibly contain
595
   parameters to be passed into the stack frame and setting
596
   up space for a return value, ffi_closure_ASM invokes the
597
   following helper function to do most of the work.  */
598
 
599
int ffi_closure_helper_DARWIN (ffi_closure* closure, void * rvalue,
600
                               unsigned long * pgr, ffi_dblfl * pfr)
601
{
602
  /* rvalue is the pointer to space for return value in closure assembly
603
     pgr is the pointer to where r3-r10 are stored in ffi_closure_ASM
604
     pfr is the pointer to where f1-f13 are stored in ffi_closure_ASM.  */
605
 
606
  typedef double ldbits[2];
607
 
608
  union ldu
609
  {
610
    ldbits lb;
611
    long double ld;
612
  };
613
 
614
  void **          avalue;
615
  ffi_type **      arg_types;
616
  long             i, avn;
617
  long             nf;   /* number of floating registers already used.  */
618
  long             ng;   /* number of general registers already used.  */
619
  ffi_cif *        cif;
620
  double           temp;
621
  unsigned         size_al;
622
  union ldu        temp_ld;
623
 
624
  cif = closure->cif;
625
  avalue = alloca(cif->nargs * sizeof(void *));
626
 
627
  nf = 0;
628
  ng = 0;
629
 
630
  /* Copy the caller's structure return value address so that the closure
631
     returns the data directly to the caller.  */
632
  if (cif->rtype->type == FFI_TYPE_STRUCT)
633
    {
634
      rvalue = (void *) *pgr;
635
      pgr++;
636
      ng++;
637
    }
638
 
639
  i = 0;
640
  avn = cif->nargs;
641
  arg_types = cif->arg_types;
642
 
643
  /* Grab the addresses of the arguments from the stack frame.  */
644
  while (i < avn)
645
    {
646
      switch (arg_types[i]->type)
647
        {
648
        case FFI_TYPE_SINT8:
649
        case FFI_TYPE_UINT8:
650
          avalue[i] = (char *) pgr + 3;
651
          ng++;
652
          pgr++;
653
          break;
654
 
655
        case FFI_TYPE_SINT16:
656
        case FFI_TYPE_UINT16:
657
          avalue[i] = (char *) pgr + 2;
658
          ng++;
659
          pgr++;
660
          break;
661
 
662
        case FFI_TYPE_SINT32:
663
        case FFI_TYPE_UINT32:
664
        case FFI_TYPE_POINTER:
665
          avalue[i] = pgr;
666
          ng++;
667
          pgr++;
668
          break;
669
 
670
        case FFI_TYPE_STRUCT:
671
          /* Structures that match the basic modes (QI 1 byte, HI 2 bytes,
672
             SI 4 bytes) are aligned as if they were those modes.  */
673
          size_al = arg_types[i]->size;
674
          /* If the first member of the struct is a double, then align
675
             the struct to double-word.
676
             Type 3 is defined in include/ffi.h. #define FFI_TYPE_DOUBLE 3.  */
677
          if (arg_types[i]->elements[0]->type == 3)
678
            size_al = ALIGN(arg_types[i]->size, 8);
679
          if (size_al < 3 && cif->abi == FFI_DARWIN)
680
            avalue[i] = (void*) pgr + 4 - size_al;
681
          else
682
            avalue[i] = (void*) pgr;
683
          ng += (size_al + 3) / 4;
684
          pgr += (size_al + 3) / 4;
685
          break;
686
 
687
        case FFI_TYPE_SINT64:
688
        case FFI_TYPE_UINT64:
689
          /* Long long ints are passed in two gpr's.  */
690
          avalue[i] = pgr;
691
          ng += 2;
692
          pgr += 2;
693
          break;
694
 
695
        case FFI_TYPE_FLOAT:
696
          /* A float value consumes a GPR.
697
             There are 13 64bit floating point registers.  */
698
          if (nf < NUM_FPR_ARG_REGISTERS)
699
            {
700
              temp = pfr->d;
701
              pfr->f = (float)temp;
702
              avalue[i] = pfr;
703
              pfr++;
704
            }
705
          else
706
            {
707
              avalue[i] = pgr;
708
            }
709
          nf++;
710
          ng++;
711
          pgr++;
712
          break;
713
 
714
        case FFI_TYPE_DOUBLE:
715
          /* A double value consumes two GPRs.
716
             There are 13 64bit floating point registers.  */
717
          if (nf < NUM_FPR_ARG_REGISTERS)
718
            {
719
              avalue[i] = pfr;
720
              pfr++;
721
            }
722
          else
723
            {
724
              avalue[i] = pgr;
725
            }
726
          nf++;
727
          ng += 2;
728
          pgr += 2;
729
          break;
730
 
731
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
732
 
733
        case FFI_TYPE_LONGDOUBLE:
734
          /* A long double value consumes four GPRs and two FPRs.
735
             There are 13 64bit floating point registers.  */
736
          if (nf < NUM_FPR_ARG_REGISTERS - 1)
737
            {
738
              avalue[i] = pfr;
739
              pfr += 2;
740
            }
741
          /* Here we have the situation where one part of the long double
742
             is stored in fpr13 and the other part is already on the stack.
743
             We use a union to pass the long double to avalue[i].  */
744
          else if (nf == NUM_FPR_ARG_REGISTERS - 1)
745
            {
746
              memcpy (&temp_ld.lb[0], pfr, sizeof(ldbits));
747
              memcpy (&temp_ld.lb[1], pgr + 2, sizeof(ldbits));
748
              avalue[i] = &temp_ld.ld;
749
            }
750
          else
751
            {
752
              avalue[i] = pgr;
753
            }
754
          nf += 2;
755
          ng += 4;
756
          pgr += 4;
757
          break;
758
#endif
759
        default:
760
          FFI_ASSERT(0);
761
        }
762
      i++;
763
    }
764
 
765
  (closure->fun) (cif, rvalue, avalue, closure->user_data);
766
 
767
  /* Tell ffi_closure_ASM to perform return type promotions.  */
768
  return cif->rtype->type;
769
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.