~ubuntu-branches/ubuntu/oneiric/libffi/oneiric

« back to all changes in this revision

Viewing changes to src/arm/ffi.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2011-04-18 20:53:34 UTC
  • mfrom: (1.1.5 upstream) (15.2.1 experimental)
  • Revision ID: james.westby@ubuntu.com-20110418205334-odjww9ndylq3cchl
Tags: 3.0.10~rc8-1
* New upstream version (release candidate 8).
  - Adds VFP hard-float calling convention support. Closes: #597920.
* Install to the multiarch triplet directories, not the gnu triplet
  directories (Steve Langasek). Closes: #622976.
* Bump soversion, update symbols files.
* Update debian/copyright file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* -----------------------------------------------------------------------
2
 
   ffi.c - Copyright (c) 1998, 2008  Red Hat, Inc.
3
 
   
 
2
   ffi.c - Copyright (c) 2011 Plausible Labs Cooperative, Inc.
 
3
           Copyright (c) 2011 Anthony Green
 
4
           Copyright (c) 2011 Free Software Foundation
 
5
           Copyright (c) 1998, 2008, 2011  Red Hat, Inc.
 
6
           
4
7
   ARM Foreign Function Interface 
5
8
 
6
9
   Permission is hereby granted, free of charge, to any person obtaining
29
32
 
30
33
#include <stdlib.h>
31
34
 
 
35
/* Forward declares. */
 
36
static int vfp_type_p (ffi_type *);
 
37
static void layout_vfp_args (ffi_cif *);
 
38
 
32
39
/* ffi_prep_args is called by the assembly routine once stack space
33
 
   has been allocated for the function's arguments */
34
 
 
35
 
void ffi_prep_args(char *stack, extended_cif *ecif)
 
40
   has been allocated for the function's arguments
 
41
   
 
42
   The vfp_space parameter is the load area for VFP regs, the return
 
43
   value is cif->vfp_used (word bitset of VFP regs used for passing
 
44
   arguments). These are only used for the VFP hard-float ABI.
 
45
*/
 
46
int ffi_prep_args(char *stack, extended_cif *ecif, float *vfp_space)
36
47
{
37
 
  register unsigned int i;
 
48
  register unsigned int i, vi = 0;
38
49
  register void **p_argv;
39
50
  register char *argp;
40
51
  register ffi_type **p_arg;
54
65
    {
55
66
      size_t z;
56
67
 
 
68
      /* Allocated in VFP registers. */
 
69
      if (ecif->cif->abi == FFI_VFP
 
70
          && vi < ecif->cif->vfp_nargs && vfp_type_p (*p_arg))
 
71
        {
 
72
          float* vfp_slot = vfp_space + ecif->cif->vfp_args[vi++];
 
73
          if ((*p_arg)->type == FFI_TYPE_FLOAT)
 
74
            *((float*)vfp_slot) = *((float*)*p_argv);
 
75
          else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
 
76
            *((double*)vfp_slot) = *((double*)*p_argv);
 
77
          else
 
78
            memcpy(vfp_slot, *p_argv, (*p_arg)->size);
 
79
          p_argv++;
 
80
          continue;
 
81
        }
 
82
 
57
83
      /* Align if necessary */
58
84
      if (((*p_arg)->alignment - 1) & (unsigned) argp) {
59
85
        argp = (char *) ALIGN(argp, (*p_arg)->alignment);
103
129
          p_argv++;
104
130
          argp += z;
105
131
    }
106
 
  
107
 
  return;
 
132
 
 
133
  /* Indicate the VFP registers used. */
 
134
  return ecif->cif->vfp_used;
108
135
}
109
136
 
110
137
/* Perform machine dependent cif processing */
111
138
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
112
139
{
 
140
  int type_code;
113
141
  /* Round the stack up to a multiple of 8 bytes.  This isn't needed 
114
142
     everywhere, but it is on some platforms, and it doesn't harm anything
115
143
     when it isn't needed.  */
130
158
      break;
131
159
 
132
160
    case FFI_TYPE_STRUCT:
133
 
      if (cif->rtype->size <= 4)
 
161
      if (cif->abi == FFI_VFP
 
162
          && (type_code = vfp_type_p (cif->rtype)) != 0)
 
163
        {
 
164
          /* A Composite Type passed in VFP registers, either
 
165
             FFI_TYPE_STRUCT_VFP_FLOAT or FFI_TYPE_STRUCT_VFP_DOUBLE. */
 
166
          cif->flags = (unsigned) type_code;
 
167
        }
 
168
      else if (cif->rtype->size <= 4)
134
169
        /* A Composite Type not larger than 4 bytes is returned in r0.  */
135
170
        cif->flags = (unsigned)FFI_TYPE_INT;
136
171
      else
145
180
      break;
146
181
    }
147
182
 
 
183
  /* Map out the register placements of VFP register args.
 
184
     The VFP hard-float calling conventions are slightly more sophisticated than
 
185
     the base calling conventions, so we do it here instead of in ffi_prep_args(). */
 
186
  if (cif->abi == FFI_VFP)
 
187
    layout_vfp_args (cif);
 
188
 
148
189
  return FFI_OK;
149
190
}
150
191
 
151
 
extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
152
 
                          unsigned, unsigned, unsigned *, void (*fn)(void));
 
192
/* Prototypes for assembly functions, in sysv.S */
 
193
extern void ffi_call_SYSV (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
 
194
extern void ffi_call_VFP (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
153
195
 
154
196
void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
155
197
{
157
199
 
158
200
  int small_struct = (cif->flags == FFI_TYPE_INT 
159
201
                      && cif->rtype->type == FFI_TYPE_STRUCT);
 
202
  int vfp_struct = (cif->flags == FFI_TYPE_STRUCT_VFP_FLOAT
 
203
                    || cif->flags == FFI_TYPE_STRUCT_VFP_DOUBLE);
160
204
 
161
205
  ecif.cif = cif;
162
206
  ecif.avalue = avalue;
173
217
    }
174
218
  else if (small_struct)
175
219
    ecif.rvalue = &temp;
 
220
  else if (vfp_struct)
 
221
    {
 
222
      /* Largest case is double x 4. */
 
223
      ecif.rvalue = alloca(32);
 
224
    }
176
225
  else
177
226
    ecif.rvalue = rvalue;
178
227
 
179
228
  switch (cif->abi) 
180
229
    {
181
230
    case FFI_SYSV:
182
 
      ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
183
 
                    fn);
184
 
 
185
 
      break;
 
231
      ffi_call_SYSV (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
 
232
      break;
 
233
 
 
234
    case FFI_VFP:
 
235
      ffi_call_VFP (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
 
236
      break;
 
237
 
186
238
    default:
187
239
      FFI_ASSERT(0);
188
240
      break;
189
241
    }
190
242
  if (small_struct)
191
243
    memcpy (rvalue, &temp, cif->rtype->size);
 
244
  else if (vfp_struct)
 
245
    memcpy (rvalue, ecif.rvalue, cif->rtype->size);
192
246
}
193
247
 
194
248
/** private members **/
195
249
 
196
250
static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
197
 
                                         void** args, ffi_cif* cif);
 
251
                                         void** args, ffi_cif* cif, float *vfp_stack);
198
252
 
199
253
void ffi_closure_SYSV (ffi_closure *);
200
254
 
 
255
void ffi_closure_VFP (ffi_closure *);
 
256
 
201
257
/* This function is jumped to by the trampoline */
202
258
 
203
259
unsigned int
204
 
ffi_closure_SYSV_inner (closure, respp, args)
 
260
ffi_closure_SYSV_inner (closure, respp, args, vfp_args)
205
261
     ffi_closure *closure;
206
262
     void **respp;
207
263
     void *args;
 
264
     void *vfp_args;
208
265
{
209
266
  // our various things...
210
267
  ffi_cif       *cif;
219
276
   * a structure, it will re-set RESP to point to the
220
277
   * structure return address.  */
221
278
 
222
 
  ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
 
279
  ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif, vfp_args);
223
280
 
224
281
  (closure->fun) (cif, *respp, arg_area, closure->user_data);
225
282
 
229
286
/*@-exportheader@*/
230
287
static void 
231
288
ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
232
 
                            void **avalue, ffi_cif *cif)
 
289
                            void **avalue, ffi_cif *cif,
 
290
                            /* Used only under VFP hard-float ABI. */
 
291
                            float *vfp_stack)
233
292
/*@=exportheader@*/
234
293
{
235
 
  register unsigned int i;
 
294
  register unsigned int i, vi = 0;
236
295
  register void **p_argv;
237
296
  register char *argp;
238
297
  register ffi_type **p_arg;
249
308
  for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
250
309
    {
251
310
      size_t z;
 
311
      size_t alignment;
 
312
  
 
313
      if (cif->abi == FFI_VFP
 
314
          && vi < cif->vfp_nargs && vfp_type_p (*p_arg))
 
315
        {
 
316
          *p_argv++ = (void*)(vfp_stack + cif->vfp_args[vi++]);
 
317
          continue;
 
318
        }
252
319
 
253
 
      size_t alignment = (*p_arg)->alignment;
 
320
      alignment = (*p_arg)->alignment;
254
321
      if (alignment < 4)
255
322
        alignment = 4;
256
323
      /* Align if necessary */
273
340
 
274
341
/* How to make a trampoline.  */
275
342
 
 
343
#if FFI_EXEC_TRAMPOLINE_TABLE
 
344
 
 
345
#include <mach/mach.h>
 
346
#include <pthread.h>
 
347
#include <stdio.h>
 
348
#include <stdlib.h>
 
349
 
 
350
extern void *ffi_closure_trampoline_table_page;
 
351
 
 
352
typedef struct ffi_trampoline_table ffi_trampoline_table;
 
353
typedef struct ffi_trampoline_table_entry ffi_trampoline_table_entry;
 
354
 
 
355
struct ffi_trampoline_table {
 
356
  /* contigious writable and executable pages */
 
357
  vm_address_t config_page;
 
358
  vm_address_t trampoline_page;
 
359
 
 
360
  /* free list tracking */
 
361
  uint16_t free_count;
 
362
  ffi_trampoline_table_entry *free_list;
 
363
  ffi_trampoline_table_entry *free_list_pool;
 
364
 
 
365
  ffi_trampoline_table *prev;
 
366
  ffi_trampoline_table *next;
 
367
};
 
368
 
 
369
struct ffi_trampoline_table_entry {
 
370
  void *(*trampoline)();
 
371
  ffi_trampoline_table_entry *next;
 
372
};
 
373
 
 
374
/* Override the standard architecture trampoline size */
 
375
// XXX TODO - Fix
 
376
#undef FFI_TRAMPOLINE_SIZE
 
377
#define FFI_TRAMPOLINE_SIZE 12
 
378
 
 
379
/* The trampoline configuration is placed at 4080 bytes prior to the trampoline's entry point */
 
380
#define FFI_TRAMPOLINE_CODELOC_CONFIG(codeloc) ((void **) (((uint8_t *) codeloc) - 4080));
 
381
 
 
382
/* The first 16 bytes of the config page are unused, as they are unaddressable from the trampoline page. */
 
383
#define FFI_TRAMPOLINE_CONFIG_PAGE_OFFSET 16
 
384
 
 
385
/* Total number of trampolines that fit in one trampoline table */
 
386
#define FFI_TRAMPOLINE_COUNT ((PAGE_SIZE - FFI_TRAMPOLINE_CONFIG_PAGE_OFFSET) / FFI_TRAMPOLINE_SIZE)
 
387
 
 
388
static pthread_mutex_t ffi_trampoline_lock = PTHREAD_MUTEX_INITIALIZER;
 
389
static ffi_trampoline_table *ffi_trampoline_tables = NULL;
 
390
 
 
391
static ffi_trampoline_table *
 
392
ffi_trampoline_table_alloc ()
 
393
{
 
394
  ffi_trampoline_table *table = NULL;
 
395
 
 
396
  /* Loop until we can allocate two contigious pages */
 
397
  while (table == NULL) {
 
398
    vm_address_t config_page = 0x0;
 
399
    kern_return_t kt;
 
400
 
 
401
    /* Try to allocate two pages */
 
402
    kt = vm_allocate (mach_task_self (), &config_page, PAGE_SIZE*2, VM_FLAGS_ANYWHERE);
 
403
    if (kt != KERN_SUCCESS) {
 
404
      fprintf(stderr, "vm_allocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
 
405
      break;
 
406
    }
 
407
 
 
408
    /* Now drop the second half of the allocation to make room for the trampoline table */
 
409
    vm_address_t trampoline_page = config_page+PAGE_SIZE;
 
410
    kt = vm_deallocate (mach_task_self (), trampoline_page, PAGE_SIZE);
 
411
    if (kt != KERN_SUCCESS) {
 
412
      fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
 
413
      break;
 
414
    }
 
415
 
 
416
    /* Remap the trampoline table to directly follow the config page */
 
417
    vm_prot_t cur_prot;
 
418
    vm_prot_t max_prot;
 
419
 
 
420
    kt = vm_remap (mach_task_self (), &trampoline_page, PAGE_SIZE, 0x0, FALSE, mach_task_self (), (vm_address_t) &ffi_closure_trampoline_table_page, FALSE, &cur_prot, &max_prot, VM_INHERIT_SHARE);
 
421
 
 
422
    /* If we lost access to the destination trampoline page, drop our config allocation mapping and retry */
 
423
    if (kt != KERN_SUCCESS) {
 
424
      /* Log unexpected failures */
 
425
      if (kt != KERN_NO_SPACE) {
 
426
        fprintf(stderr, "vm_remap() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
 
427
      }
 
428
 
 
429
      vm_deallocate (mach_task_self (), config_page, PAGE_SIZE);
 
430
      continue;
 
431
    }
 
432
 
 
433
    /* We have valid trampoline and config pages */
 
434
    table = calloc (1, sizeof(ffi_trampoline_table));
 
435
    table->free_count = FFI_TRAMPOLINE_COUNT;
 
436
    table->config_page = config_page;
 
437
    table->trampoline_page = trampoline_page;
 
438
 
 
439
    /* Create and initialize the free list */
 
440
    table->free_list_pool = calloc(FFI_TRAMPOLINE_COUNT, sizeof(ffi_trampoline_table_entry));
 
441
 
 
442
    uint16_t i;
 
443
    for (i = 0; i < table->free_count; i++) {
 
444
      ffi_trampoline_table_entry *entry = &table->free_list_pool[i];
 
445
      entry->trampoline = (void *) (table->trampoline_page + (i * FFI_TRAMPOLINE_SIZE));
 
446
 
 
447
      if (i < table->free_count - 1)
 
448
        entry->next = &table->free_list_pool[i+1];
 
449
    }
 
450
 
 
451
    table->free_list = table->free_list_pool;
 
452
  }
 
453
 
 
454
  return table;
 
455
}
 
456
 
 
457
void *
 
458
ffi_closure_alloc (size_t size, void **code)
 
459
{
 
460
  /* Create the closure */
 
461
  ffi_closure *closure = malloc(size);
 
462
  if (closure == NULL)
 
463
    return NULL;
 
464
 
 
465
  pthread_mutex_lock(&ffi_trampoline_lock);
 
466
 
 
467
  /* Check for an active trampoline table with available entries. */
 
468
  ffi_trampoline_table *table = ffi_trampoline_tables;
 
469
  if (table == NULL || table->free_list == NULL) {
 
470
    table = ffi_trampoline_table_alloc ();
 
471
    if (table == NULL) {
 
472
      free(closure);
 
473
      return NULL;
 
474
    }
 
475
 
 
476
    /* Insert the new table at the top of the list */
 
477
    table->next = ffi_trampoline_tables;
 
478
    if (table->next != NULL)
 
479
        table->next->prev = table;
 
480
 
 
481
    ffi_trampoline_tables = table;
 
482
  }
 
483
 
 
484
  /* Claim the free entry */
 
485
  ffi_trampoline_table_entry *entry = ffi_trampoline_tables->free_list;
 
486
  ffi_trampoline_tables->free_list = entry->next;
 
487
  ffi_trampoline_tables->free_count--;
 
488
  entry->next = NULL;
 
489
 
 
490
  pthread_mutex_unlock(&ffi_trampoline_lock);
 
491
 
 
492
  /* Initialize the return values */
 
493
  *code = entry->trampoline;
 
494
  closure->trampoline_table = table;
 
495
  closure->trampoline_table_entry = entry;
 
496
 
 
497
  return closure;
 
498
}
 
499
 
 
500
void
 
501
ffi_closure_free (void *ptr)
 
502
{
 
503
  ffi_closure *closure = ptr;
 
504
 
 
505
  pthread_mutex_lock(&ffi_trampoline_lock);
 
506
 
 
507
  /* Fetch the table and entry references */
 
508
  ffi_trampoline_table *table = closure->trampoline_table;
 
509
  ffi_trampoline_table_entry *entry = closure->trampoline_table_entry;
 
510
 
 
511
  /* Return the entry to the free list */
 
512
  entry->next = table->free_list;
 
513
  table->free_list = entry;
 
514
  table->free_count++;
 
515
 
 
516
  /* If all trampolines within this table are free, and at least one other table exists, deallocate
 
517
   * the table */
 
518
  if (table->free_count == FFI_TRAMPOLINE_COUNT && ffi_trampoline_tables != table) {
 
519
    /* Remove from the list */
 
520
    if (table->prev != NULL)
 
521
      table->prev->next = table->next;
 
522
 
 
523
    if (table->next != NULL)
 
524
      table->next->prev = table->prev;
 
525
 
 
526
    /* Deallocate pages */
 
527
    kern_return_t kt;
 
528
    kt = vm_deallocate (mach_task_self (), table->config_page, PAGE_SIZE);
 
529
    if (kt != KERN_SUCCESS)
 
530
      fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
 
531
 
 
532
    kt = vm_deallocate (mach_task_self (), table->trampoline_page, PAGE_SIZE);
 
533
    if (kt != KERN_SUCCESS)
 
534
      fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
 
535
 
 
536
    /* Deallocate free list */
 
537
    free (table->free_list_pool);
 
538
    free (table);
 
539
  } else if (ffi_trampoline_tables != table) {
 
540
    /* Otherwise, bump this table to the top of the list */
 
541
    table->prev = NULL;
 
542
    table->next = ffi_trampoline_tables;
 
543
    if (ffi_trampoline_tables != NULL)
 
544
      ffi_trampoline_tables->prev = table;
 
545
 
 
546
    ffi_trampoline_tables = table;
 
547
  }
 
548
 
 
549
  pthread_mutex_unlock (&ffi_trampoline_lock);
 
550
 
 
551
  /* Free the closure */
 
552
  free (closure);
 
553
}
 
554
 
 
555
#else
 
556
 
276
557
#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX)                              \
277
558
({ unsigned char *__tramp = (unsigned char*)(TRAMP);                    \
278
559
   unsigned int  __fun = (unsigned int)(FUN);                           \
285
566
   __clear_cache((&__tramp[0]), (&__tramp[19]));                        \
286
567
 })
287
568
 
 
569
#endif
288
570
 
289
571
/* the cif must already be prep'ed */
290
572
 
295
577
                      void *user_data,
296
578
                      void *codeloc)
297
579
{
298
 
  FFI_ASSERT (cif->abi == FFI_SYSV);
 
580
  void (*closure_func)(ffi_closure*) = NULL;
299
581
 
 
582
  if (cif->abi == FFI_SYSV)
 
583
    closure_func = &ffi_closure_SYSV;
 
584
  else if (cif->abi == FFI_VFP)
 
585
    closure_func = &ffi_closure_VFP;
 
586
  else
 
587
    return FFI_BAD_ABI;
 
588
    
 
589
#if FFI_EXEC_TRAMPOLINE_TABLE
 
590
  void **config = FFI_TRAMPOLINE_CODELOC_CONFIG(codeloc);
 
591
  config[0] = closure;
 
592
  config[1] = closure_func;
 
593
#else
300
594
  FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
301
 
                       &ffi_closure_SYSV,  \
 
595
                       closure_func,  \
302
596
                       codeloc);
303
 
    
 
597
#endif
 
598
 
304
599
  closure->cif  = cif;
305
600
  closure->user_data = user_data;
306
601
  closure->fun  = fun;
307
602
 
308
603
  return FFI_OK;
309
604
}
 
605
 
 
606
/* Below are routines for VFP hard-float support. */
 
607
 
 
608
static int rec_vfp_type_p (ffi_type *t, int *elt, int *elnum)
 
609
{
 
610
  switch (t->type)
 
611
    {
 
612
    case FFI_TYPE_FLOAT:
 
613
    case FFI_TYPE_DOUBLE:
 
614
      *elt = (int) t->type;
 
615
      *elnum = 1;
 
616
      return 1;
 
617
 
 
618
    case FFI_TYPE_STRUCT_VFP_FLOAT:
 
619
      *elt = FFI_TYPE_FLOAT;
 
620
      *elnum = t->size / sizeof (float);
 
621
      return 1;
 
622
 
 
623
    case FFI_TYPE_STRUCT_VFP_DOUBLE:
 
624
      *elt = FFI_TYPE_DOUBLE;
 
625
      *elnum = t->size / sizeof (double);
 
626
      return 1;
 
627
 
 
628
    case FFI_TYPE_STRUCT:;
 
629
      {
 
630
        int base_elt = 0, total_elnum = 0;
 
631
        ffi_type **el = t->elements;
 
632
        while (*el)
 
633
          {
 
634
            int el_elt = 0, el_elnum = 0;
 
635
            if (! rec_vfp_type_p (*el, &el_elt, &el_elnum)
 
636
                || (base_elt && base_elt != el_elt)
 
637
                || total_elnum + el_elnum > 4)
 
638
              return 0;
 
639
            base_elt = el_elt;
 
640
            total_elnum += el_elnum;
 
641
            el++;
 
642
          }
 
643
        *elnum = total_elnum;
 
644
        *elt = base_elt;
 
645
        return 1;
 
646
      }
 
647
    default: ;
 
648
    }
 
649
  return 0;
 
650
}
 
651
 
 
652
static int vfp_type_p (ffi_type *t)
 
653
{
 
654
  int elt, elnum;
 
655
  if (rec_vfp_type_p (t, &elt, &elnum))
 
656
    {
 
657
      if (t->type == FFI_TYPE_STRUCT)
 
658
        {
 
659
          if (elnum == 1)
 
660
            t->type = elt;
 
661
          else
 
662
            t->type = (elt == FFI_TYPE_FLOAT
 
663
                       ? FFI_TYPE_STRUCT_VFP_FLOAT
 
664
                       : FFI_TYPE_STRUCT_VFP_DOUBLE);
 
665
        }
 
666
      return (int) t->type;
 
667
    }
 
668
  return 0;
 
669
}
 
670
 
 
671
static void place_vfp_arg (ffi_cif *cif, ffi_type *t)
 
672
{
 
673
  int reg = cif->vfp_reg_free;
 
674
  int nregs = t->size / sizeof (float);
 
675
  int align = ((t->type == FFI_TYPE_STRUCT_VFP_FLOAT
 
676
                || t->type == FFI_TYPE_FLOAT) ? 1 : 2);
 
677
  /* Align register number. */
 
678
  if ((reg & 1) && align == 2)
 
679
    reg++;
 
680
  while (reg + nregs <= 16)
 
681
    {
 
682
      int s, new_used = 0;
 
683
      for (s = reg; s < reg + nregs; s++)
 
684
        {
 
685
          new_used |= (1 << s);
 
686
          if (cif->vfp_used & (1 << s))
 
687
            {
 
688
              reg += align;
 
689
              goto next_reg;
 
690
            }
 
691
        }
 
692
      /* Found regs to allocate. */
 
693
      cif->vfp_used |= new_used;
 
694
      cif->vfp_args[cif->vfp_nargs++] = reg;
 
695
 
 
696
      /* Update vfp_reg_free. */
 
697
      if (cif->vfp_used & (1 << cif->vfp_reg_free))
 
698
        {
 
699
          reg += nregs;
 
700
          while (cif->vfp_used & (1 << reg))
 
701
            reg += 1;
 
702
          cif->vfp_reg_free = reg;
 
703
        }
 
704
      return;
 
705
    next_reg: ;
 
706
    }
 
707
}
 
708
 
 
709
static void layout_vfp_args (ffi_cif *cif)
 
710
{
 
711
  int i;
 
712
  /* Init VFP fields */
 
713
  cif->vfp_used = 0;
 
714
  cif->vfp_nargs = 0;
 
715
  cif->vfp_reg_free = 0;
 
716
  memset (cif->vfp_args, -1, 16); /* Init to -1. */
 
717
 
 
718
  for (i = 0; i < cif->nargs; i++)
 
719
    {
 
720
      ffi_type *t = cif->arg_types[i];
 
721
      if (vfp_type_p (t))
 
722
        place_vfp_arg (cif, t);
 
723
    }
 
724
}