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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libffi/] [src/] [arm/] [ffi.c] - Blame information for rev 757

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 732 jeremybenn
/* -----------------------------------------------------------------------
2
   ffi.c - Copyright (c) 1998, 2008  Red Hat, Inc.
3
 
4
   ARM Foreign Function Interface
5
 
6
   Permission is hereby granted, free of charge, to any person obtaining
7
   a copy of this software and associated documentation files (the
8
   ``Software''), to deal in the Software without restriction, including
9
   without limitation the rights to use, copy, modify, merge, publish,
10
   distribute, sublicense, and/or sell copies of the Software, and to
11
   permit persons to whom the Software is furnished to do so, subject to
12
   the following conditions:
13
 
14
   The above copyright notice and this permission notice shall be included
15
   in all copies or substantial portions of the Software.
16
 
17
   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
18
   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21
   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22
   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24
   DEALINGS IN THE SOFTWARE.
25
   ----------------------------------------------------------------------- */
26
 
27
#include <ffi.h>
28
#include <ffi_common.h>
29
 
30
#include <stdlib.h>
31
 
32
/* Forward declares. */
33
static int vfp_type_p (ffi_type *);
34
static void layout_vfp_args (ffi_cif *);
35
 
36
/* ffi_prep_args is called by the assembly routine once stack space
37
   has been allocated for the function's arguments
38
 
39
   The vfp_space parameter is the load area for VFP regs, the return
40
   value is cif->vfp_used (word bitset of VFP regs used for passing
41
   arguments). These are only used for the VFP hard-float ABI.
42
*/
43
int ffi_prep_args(char *stack, extended_cif *ecif, float *vfp_space)
44
{
45
  register unsigned int i, vi = 0;
46
  register void **p_argv;
47
  register char *argp;
48
  register ffi_type **p_arg;
49
 
50
  argp = stack;
51
 
52
  if ( ecif->cif->flags == FFI_TYPE_STRUCT ) {
53
    *(void **) argp = ecif->rvalue;
54
    argp += 4;
55
  }
56
 
57
  p_argv = ecif->avalue;
58
 
59
  for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
60
       (i != 0);
61
       i--, p_arg++)
62
    {
63
      size_t z;
64
 
65
      /* Allocated in VFP registers. */
66
      if (ecif->cif->abi == FFI_VFP
67
          && vi < ecif->cif->vfp_nargs && vfp_type_p (*p_arg))
68
        {
69
          float* vfp_slot = vfp_space + ecif->cif->vfp_args[vi++];
70
          if ((*p_arg)->type == FFI_TYPE_FLOAT)
71
            *((float*)vfp_slot) = *((float*)*p_argv);
72
          else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
73
            *((double*)vfp_slot) = *((double*)*p_argv);
74
          else
75
            memcpy(vfp_slot, *p_argv, (*p_arg)->size);
76
          p_argv++;
77
          continue;
78
        }
79
 
80
      /* Align if necessary */
81
      if (((*p_arg)->alignment - 1) & (unsigned) argp) {
82
        argp = (char *) ALIGN(argp, (*p_arg)->alignment);
83
      }
84
 
85
      if ((*p_arg)->type == FFI_TYPE_STRUCT)
86
        argp = (char *) ALIGN(argp, 4);
87
 
88
          z = (*p_arg)->size;
89
          if (z < sizeof(int))
90
            {
91
              z = sizeof(int);
92
              switch ((*p_arg)->type)
93
                {
94
                case FFI_TYPE_SINT8:
95
                  *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
96
                  break;
97
 
98
                case FFI_TYPE_UINT8:
99
                  *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
100
                  break;
101
 
102
                case FFI_TYPE_SINT16:
103
                  *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
104
                  break;
105
 
106
                case FFI_TYPE_UINT16:
107
                  *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
108
                  break;
109
 
110
                case FFI_TYPE_STRUCT:
111
                  memcpy(argp, *p_argv, (*p_arg)->size);
112
                  break;
113
 
114
                default:
115
                  FFI_ASSERT(0);
116
                }
117
            }
118
          else if (z == sizeof(int))
119
            {
120
              *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
121
            }
122
          else
123
            {
124
              memcpy(argp, *p_argv, z);
125
            }
126
          p_argv++;
127
          argp += z;
128
    }
129
 
130
  /* Indicate the VFP registers used. */
131
  return ecif->cif->vfp_used;
132
}
133
 
134
/* Perform machine dependent cif processing */
135
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
136
{
137
  int type_code;
138
  /* Round the stack up to a multiple of 8 bytes.  This isn't needed
139
     everywhere, but it is on some platforms, and it doesn't harm anything
140
     when it isn't needed.  */
141
  cif->bytes = (cif->bytes + 7) & ~7;
142
 
143
  /* Set the return type flag */
144
  switch (cif->rtype->type)
145
    {
146
    case FFI_TYPE_VOID:
147
    case FFI_TYPE_FLOAT:
148
    case FFI_TYPE_DOUBLE:
149
      cif->flags = (unsigned) cif->rtype->type;
150
      break;
151
 
152
    case FFI_TYPE_SINT64:
153
    case FFI_TYPE_UINT64:
154
      cif->flags = (unsigned) FFI_TYPE_SINT64;
155
      break;
156
 
157
    case FFI_TYPE_STRUCT:
158
      if (cif->abi == FFI_VFP
159
          && (type_code = vfp_type_p (cif->rtype)) != 0)
160
        {
161
          /* A Composite Type passed in VFP registers, either
162
             FFI_TYPE_STRUCT_VFP_FLOAT or FFI_TYPE_STRUCT_VFP_DOUBLE. */
163
          cif->flags = (unsigned) type_code;
164
        }
165
      else if (cif->rtype->size <= 4)
166
        /* A Composite Type not larger than 4 bytes is returned in r0.  */
167
        cif->flags = (unsigned)FFI_TYPE_INT;
168
      else
169
        /* A Composite Type larger than 4 bytes, or whose size cannot
170
           be determined statically ... is stored in memory at an
171
           address passed [in r0].  */
172
        cif->flags = (unsigned)FFI_TYPE_STRUCT;
173
      break;
174
 
175
    default:
176
      cif->flags = FFI_TYPE_INT;
177
      break;
178
    }
179
 
180
  /* Map out the register placements of VFP register args.
181
     The VFP hard-float calling conventions are slightly more sophisticated than
182
     the base calling conventions, so we do it here instead of in ffi_prep_args(). */
183
  if (cif->abi == FFI_VFP)
184
    layout_vfp_args (cif);
185
 
186
  return FFI_OK;
187
}
188
 
189
/* Prototypes for assembly functions, in sysv.S */
190
extern void ffi_call_SYSV (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
191
extern void ffi_call_VFP (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
192
 
193
void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
194
{
195
  extended_cif ecif;
196
 
197
  int small_struct = (cif->flags == FFI_TYPE_INT
198
                      && cif->rtype->type == FFI_TYPE_STRUCT);
199
  int vfp_struct = (cif->flags == FFI_TYPE_STRUCT_VFP_FLOAT
200
                    || cif->flags == FFI_TYPE_STRUCT_VFP_DOUBLE);
201
 
202
  ecif.cif = cif;
203
  ecif.avalue = avalue;
204
 
205
  unsigned int temp;
206
 
207
  /* If the return value is a struct and we don't have a return */
208
  /* value address then we need to make one                     */
209
 
210
  if ((rvalue == NULL) &&
211
      (cif->flags == FFI_TYPE_STRUCT))
212
    {
213
      ecif.rvalue = alloca(cif->rtype->size);
214
    }
215
  else if (small_struct)
216
    ecif.rvalue = &temp;
217
  else if (vfp_struct)
218
    {
219
      /* Largest case is double x 4. */
220
      ecif.rvalue = alloca(32);
221
    }
222
  else
223
    ecif.rvalue = rvalue;
224
 
225
  switch (cif->abi)
226
    {
227
    case FFI_SYSV:
228
      ffi_call_SYSV (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
229
      break;
230
 
231
    case FFI_VFP:
232
      ffi_call_VFP (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
233
      break;
234
 
235
    default:
236
      FFI_ASSERT(0);
237
      break;
238
    }
239
  if (small_struct)
240
    memcpy (rvalue, &temp, cif->rtype->size);
241
  else if (vfp_struct)
242
    memcpy (rvalue, ecif.rvalue, cif->rtype->size);
243
}
244
 
245
/** private members **/
246
 
247
static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
248
                                         void** args, ffi_cif* cif, float *vfp_stack);
249
 
250
void ffi_closure_SYSV (ffi_closure *);
251
 
252
void ffi_closure_VFP (ffi_closure *);
253
 
254
/* This function is jumped to by the trampoline */
255
 
256
unsigned int
257
ffi_closure_SYSV_inner (closure, respp, args, vfp_args)
258
     ffi_closure *closure;
259
     void **respp;
260
     void *args;
261
     void *vfp_args;
262
{
263
  // our various things...
264
  ffi_cif       *cif;
265
  void         **arg_area;
266
 
267
  cif         = closure->cif;
268
  arg_area    = (void**) alloca (cif->nargs * sizeof (void*));
269
 
270
  /* this call will initialize ARG_AREA, such that each
271
   * element in that array points to the corresponding
272
   * value on the stack; and if the function returns
273
   * a structure, it will re-set RESP to point to the
274
   * structure return address.  */
275
 
276
  ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif, vfp_args);
277
 
278
  (closure->fun) (cif, *respp, arg_area, closure->user_data);
279
 
280
  return cif->flags;
281
}
282
 
283
/*@-exportheader@*/
284
static void
285
ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
286
                            void **avalue, ffi_cif *cif,
287
                            /* Used only under VFP hard-float ABI. */
288
                            float *vfp_stack)
289
/*@=exportheader@*/
290
{
291
  register unsigned int i, vi = 0;
292
  register void **p_argv;
293
  register char *argp;
294
  register ffi_type **p_arg;
295
 
296
  argp = stack;
297
 
298
  if ( cif->flags == FFI_TYPE_STRUCT ) {
299
    *rvalue = *(void **) argp;
300
    argp += 4;
301
  }
302
 
303
  p_argv = avalue;
304
 
305
  for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
306
    {
307
      size_t z;
308
      size_t alignment;
309
 
310
      if (cif->abi == FFI_VFP
311
          && vi < cif->vfp_nargs && vfp_type_p (*p_arg))
312
        {
313
          *p_argv++ = (void*)(vfp_stack + cif->vfp_args[vi++]);
314
          continue;
315
        }
316
 
317
      alignment = (*p_arg)->alignment;
318
      if (alignment < 4)
319
        alignment = 4;
320
      /* Align if necessary */
321
      if ((alignment - 1) & (unsigned) argp) {
322
        argp = (char *) ALIGN(argp, alignment);
323
      }
324
 
325
      z = (*p_arg)->size;
326
 
327
      /* because we're little endian, this is what it turns into.   */
328
 
329
      *p_argv = (void*) argp;
330
 
331
      p_argv++;
332
      argp += z;
333
    }
334
 
335
  return;
336
}
337
 
338
/* How to make a trampoline.  */
339
 
340
extern unsigned int ffi_arm_trampoline[3];
341
 
342
#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX)                              \
343
({ unsigned char *__tramp = (unsigned char*)(TRAMP);                    \
344
   unsigned int  __fun = (unsigned int)(FUN);                           \
345
   unsigned int  __ctx = (unsigned int)(CTX);                           \
346
   unsigned char *insns = (unsigned char *)(CTX);                       \
347
   memcpy (__tramp, ffi_arm_trampoline, sizeof ffi_arm_trampoline);     \
348
   *(unsigned int*) &__tramp[12] = __ctx;                               \
349
   *(unsigned int*) &__tramp[16] = __fun;                               \
350
   __clear_cache((&__tramp[0]), (&__tramp[19])); /* Clear data mapping.  */ \
351
   __clear_cache(insns, insns + 3 * sizeof (unsigned int));             \
352
                                                 /* Clear instruction   \
353
                                                    mapping.  */        \
354
 })
355
 
356
 
357
/* the cif must already be prep'ed */
358
 
359
ffi_status
360
ffi_prep_closure_loc (ffi_closure* closure,
361
                      ffi_cif* cif,
362
                      void (*fun)(ffi_cif*,void*,void**,void*),
363
                      void *user_data,
364
                      void *codeloc)
365
{
366
  void (*closure_func)(ffi_closure*) = NULL;
367
 
368
  if (cif->abi == FFI_SYSV)
369
    closure_func = &ffi_closure_SYSV;
370
  else if (cif->abi == FFI_VFP)
371
    closure_func = &ffi_closure_VFP;
372
  else
373
    FFI_ASSERT (0);
374
 
375
  FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
376
                       closure_func,  \
377
                       codeloc);
378
 
379
  closure->cif  = cif;
380
  closure->user_data = user_data;
381
  closure->fun  = fun;
382
 
383
  return FFI_OK;
384
}
385
 
386
/* Below are routines for VFP hard-float support. */
387
 
388
static int rec_vfp_type_p (ffi_type *t, int *elt, int *elnum)
389
{
390
  switch (t->type)
391
    {
392
    case FFI_TYPE_FLOAT:
393
    case FFI_TYPE_DOUBLE:
394
      *elt = (int) t->type;
395
      *elnum = 1;
396
      return 1;
397
 
398
    case FFI_TYPE_STRUCT_VFP_FLOAT:
399
      *elt = FFI_TYPE_FLOAT;
400
      *elnum = t->size / sizeof (float);
401
      return 1;
402
 
403
    case FFI_TYPE_STRUCT_VFP_DOUBLE:
404
      *elt = FFI_TYPE_DOUBLE;
405
      *elnum = t->size / sizeof (double);
406
      return 1;
407
 
408
    case FFI_TYPE_STRUCT:;
409
      {
410
        int base_elt = 0, total_elnum = 0;
411
        ffi_type **el = t->elements;
412
        while (*el)
413
          {
414
            int el_elt = 0, el_elnum = 0;
415
            if (! rec_vfp_type_p (*el, &el_elt, &el_elnum)
416
                || (base_elt && base_elt != el_elt)
417
                || total_elnum + el_elnum > 4)
418
              return 0;
419
            base_elt = el_elt;
420
            total_elnum += el_elnum;
421
            el++;
422
          }
423
        *elnum = total_elnum;
424
        *elt = base_elt;
425
        return 1;
426
      }
427
    default: ;
428
    }
429
  return 0;
430
}
431
 
432
static int vfp_type_p (ffi_type *t)
433
{
434
  int elt, elnum;
435
  if (rec_vfp_type_p (t, &elt, &elnum))
436
    {
437
      if (t->type == FFI_TYPE_STRUCT)
438
        {
439
          if (elnum == 1)
440
            t->type = elt;
441
          else
442
            t->type = (elt == FFI_TYPE_FLOAT
443
                       ? FFI_TYPE_STRUCT_VFP_FLOAT
444
                       : FFI_TYPE_STRUCT_VFP_DOUBLE);
445
        }
446
      return (int) t->type;
447
    }
448
  return 0;
449
}
450
 
451
static void place_vfp_arg (ffi_cif *cif, ffi_type *t)
452
{
453
  int reg = cif->vfp_reg_free;
454
  int nregs = t->size / sizeof (float);
455
  int align = ((t->type == FFI_TYPE_STRUCT_VFP_FLOAT
456
                || t->type == FFI_TYPE_FLOAT) ? 1 : 2);
457
  /* Align register number. */
458
  if ((reg & 1) && align == 2)
459
    reg++;
460
  while (reg + nregs <= 16)
461
    {
462
      int s, new_used = 0;
463
      for (s = reg; s < reg + nregs; s++)
464
        {
465
          new_used |= (1 << s);
466
          if (cif->vfp_used & (1 << s))
467
            {
468
              reg += align;
469
              goto next_reg;
470
            }
471
        }
472
      /* Found regs to allocate. */
473
      cif->vfp_used |= new_used;
474
      cif->vfp_args[cif->vfp_nargs++] = reg;
475
 
476
      /* Update vfp_reg_free. */
477
      if (cif->vfp_used & (1 << cif->vfp_reg_free))
478
        {
479
          reg += nregs;
480
          while (cif->vfp_used & (1 << reg))
481
            reg += 1;
482
          cif->vfp_reg_free = reg;
483
        }
484
      return;
485
    next_reg: ;
486
    }
487
}
488
 
489
static void layout_vfp_args (ffi_cif *cif)
490
{
491
  int i;
492
  /* Init VFP fields */
493
  cif->vfp_used = 0;
494
  cif->vfp_nargs = 0;
495
  cif->vfp_reg_free = 0;
496
  memset (cif->vfp_args, -1, 16); /* Init to -1. */
497
 
498
  for (i = 0; i < cif->nargs; i++)
499
    {
500
      ffi_type *t = cif->arg_types[i];
501
      if (vfp_type_p (t))
502
        place_vfp_arg (cif, t);
503
    }
504
}

powered by: WebSVN 2.1.0

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