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

Subversion Repositories openrisc

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 732 jeremybenn
/* -----------------------------------------------------------------------
2
   ffi.c - Copyright (c) 1996, 2003, 2004, 2007, 2008 Red Hat, Inc.
3
 
4
   SPARC 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
 
33
/* ffi_prep_args is called by the assembly routine once stack space
34
   has been allocated for the function's arguments */
35
 
36
void ffi_prep_args_v8(char *stack, extended_cif *ecif)
37
{
38
  int i;
39
  void **p_argv;
40
  char *argp;
41
  ffi_type **p_arg;
42
 
43
  /* Skip 16 words for the window save area */
44
  argp = stack + 16*sizeof(int);
45
 
46
  /* This should only really be done when we are returning a structure,
47
     however, it's faster just to do it all the time...
48
 
49
  if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) */
50
  *(int *) argp = (long)ecif->rvalue;
51
 
52
  /* And 1 word for the  structure return value. */
53
  argp += sizeof(int);
54
 
55
#ifdef USING_PURIFY
56
  /* Purify will probably complain in our assembly routine, unless we
57
     zero out this memory. */
58
 
59
  ((int*)argp)[0] = 0;
60
  ((int*)argp)[1] = 0;
61
  ((int*)argp)[2] = 0;
62
  ((int*)argp)[3] = 0;
63
  ((int*)argp)[4] = 0;
64
  ((int*)argp)[5] = 0;
65
#endif
66
 
67
  p_argv = ecif->avalue;
68
 
69
  for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++)
70
    {
71
      size_t z;
72
 
73
          if ((*p_arg)->type == FFI_TYPE_STRUCT
74
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
75
              || (*p_arg)->type == FFI_TYPE_LONGDOUBLE
76
#endif
77
              )
78
            {
79
              *(unsigned int *) argp = (unsigned long)(* p_argv);
80
              z = sizeof(int);
81
            }
82
          else
83
            {
84
              z = (*p_arg)->size;
85
              if (z < sizeof(int))
86
                {
87
                  z = sizeof(int);
88
                  switch ((*p_arg)->type)
89
                    {
90
                    case FFI_TYPE_SINT8:
91
                      *(signed int *) argp = *(SINT8 *)(* p_argv);
92
                      break;
93
 
94
                    case FFI_TYPE_UINT8:
95
                      *(unsigned int *) argp = *(UINT8 *)(* p_argv);
96
                      break;
97
 
98
                    case FFI_TYPE_SINT16:
99
                      *(signed int *) argp = *(SINT16 *)(* p_argv);
100
                      break;
101
 
102
                    case FFI_TYPE_UINT16:
103
                      *(unsigned int *) argp = *(UINT16 *)(* p_argv);
104
                      break;
105
 
106
                    default:
107
                      FFI_ASSERT(0);
108
                    }
109
                }
110
              else
111
                {
112
                  memcpy(argp, *p_argv, z);
113
                }
114
            }
115
          p_argv++;
116
          argp += z;
117
    }
118
 
119
  return;
120
}
121
 
122
int ffi_prep_args_v9(char *stack, extended_cif *ecif)
123
{
124
  int i, ret = 0;
125
  int tmp;
126
  void **p_argv;
127
  char *argp;
128
  ffi_type **p_arg;
129
 
130
  tmp = 0;
131
 
132
  /* Skip 16 words for the window save area */
133
  argp = stack + 16*sizeof(long long);
134
 
135
#ifdef USING_PURIFY
136
  /* Purify will probably complain in our assembly routine, unless we
137
     zero out this memory. */
138
 
139
  ((long long*)argp)[0] = 0;
140
  ((long long*)argp)[1] = 0;
141
  ((long long*)argp)[2] = 0;
142
  ((long long*)argp)[3] = 0;
143
  ((long long*)argp)[4] = 0;
144
  ((long long*)argp)[5] = 0;
145
#endif
146
 
147
  p_argv = ecif->avalue;
148
 
149
  if (ecif->cif->rtype->type == FFI_TYPE_STRUCT &&
150
      ecif->cif->rtype->size > 32)
151
    {
152
      *(unsigned long long *) argp = (unsigned long)ecif->rvalue;
153
      argp += sizeof(long long);
154
      tmp = 1;
155
    }
156
 
157
  for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs;
158
       i++, p_arg++)
159
    {
160
      size_t z;
161
 
162
      z = (*p_arg)->size;
163
      switch ((*p_arg)->type)
164
        {
165
        case FFI_TYPE_STRUCT:
166
          if (z > 16)
167
            {
168
              /* For structures larger than 16 bytes we pass reference.  */
169
              *(unsigned long long *) argp = (unsigned long)* p_argv;
170
              argp += sizeof(long long);
171
              tmp++;
172
              p_argv++;
173
              continue;
174
            }
175
          /* FALLTHROUGH */
176
        case FFI_TYPE_FLOAT:
177
        case FFI_TYPE_DOUBLE:
178
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
179
        case FFI_TYPE_LONGDOUBLE:
180
#endif
181
          ret = 1; /* We should promote into FP regs as well as integer.  */
182
          break;
183
        }
184
      if (z < sizeof(long long))
185
        {
186
          switch ((*p_arg)->type)
187
            {
188
            case FFI_TYPE_SINT8:
189
              *(signed long long *) argp = *(SINT8 *)(* p_argv);
190
              break;
191
 
192
            case FFI_TYPE_UINT8:
193
              *(unsigned long long *) argp = *(UINT8 *)(* p_argv);
194
              break;
195
 
196
            case FFI_TYPE_SINT16:
197
              *(signed long long *) argp = *(SINT16 *)(* p_argv);
198
              break;
199
 
200
            case FFI_TYPE_UINT16:
201
              *(unsigned long long *) argp = *(UINT16 *)(* p_argv);
202
              break;
203
 
204
            case FFI_TYPE_SINT32:
205
              *(signed long long *) argp = *(SINT32 *)(* p_argv);
206
              break;
207
 
208
            case FFI_TYPE_UINT32:
209
              *(unsigned long long *) argp = *(UINT32 *)(* p_argv);
210
              break;
211
 
212
            case FFI_TYPE_FLOAT:
213
              *(float *) (argp + 4) = *(FLOAT32 *)(* p_argv); /* Right justify */
214
              break;
215
 
216
            case FFI_TYPE_STRUCT:
217
              memcpy(argp, *p_argv, z);
218
              break;
219
 
220
            default:
221
              FFI_ASSERT(0);
222
            }
223
          z = sizeof(long long);
224
          tmp++;
225
        }
226
      else if (z == sizeof(long long))
227
        {
228
          memcpy(argp, *p_argv, z);
229
          z = sizeof(long long);
230
          tmp++;
231
        }
232
      else
233
        {
234
          if ((tmp & 1) && (*p_arg)->alignment > 8)
235
            {
236
              tmp++;
237
              argp += sizeof(long long);
238
            }
239
          memcpy(argp, *p_argv, z);
240
          z = 2 * sizeof(long long);
241
          tmp += 2;
242
        }
243
      p_argv++;
244
      argp += z;
245
    }
246
 
247
  return ret;
248
}
249
 
250
/* Perform machine dependent cif processing */
251
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
252
{
253
  int wordsize;
254
 
255
  if (cif->abi != FFI_V9)
256
    {
257
      wordsize = 4;
258
 
259
      /* If we are returning a struct, this will already have been added.
260
         Otherwise we need to add it because it's always got to be there! */
261
 
262
      if (cif->rtype->type != FFI_TYPE_STRUCT)
263
        cif->bytes += wordsize;
264
 
265
      /* sparc call frames require that space is allocated for 6 args,
266
         even if they aren't used. Make that space if necessary. */
267
 
268
      if (cif->bytes < 4*6+4)
269
        cif->bytes = 4*6+4;
270
    }
271
  else
272
    {
273
      wordsize = 8;
274
 
275
      /* sparc call frames require that space is allocated for 6 args,
276
         even if they aren't used. Make that space if necessary. */
277
 
278
      if (cif->bytes < 8*6)
279
        cif->bytes = 8*6;
280
    }
281
 
282
  /* Adjust cif->bytes. to include 16 words for the window save area,
283
     and maybe the struct/union return pointer area, */
284
 
285
  cif->bytes += 16 * wordsize;
286
 
287
  /* The stack must be 2 word aligned, so round bytes up
288
     appropriately. */
289
 
290
  cif->bytes = ALIGN(cif->bytes, 2 * wordsize);
291
 
292
  /* Set the return type flag */
293
  switch (cif->rtype->type)
294
    {
295
    case FFI_TYPE_VOID:
296
    case FFI_TYPE_FLOAT:
297
    case FFI_TYPE_DOUBLE:
298
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
299
    case FFI_TYPE_LONGDOUBLE:
300
#endif
301
      cif->flags = cif->rtype->type;
302
      break;
303
 
304
    case FFI_TYPE_STRUCT:
305
      if (cif->abi == FFI_V9 && cif->rtype->size > 32)
306
        cif->flags = FFI_TYPE_VOID;
307
      else
308
        cif->flags = FFI_TYPE_STRUCT;
309
      break;
310
 
311
    case FFI_TYPE_SINT8:
312
    case FFI_TYPE_UINT8:
313
    case FFI_TYPE_SINT16:
314
    case FFI_TYPE_UINT16:
315
      if (cif->abi == FFI_V9)
316
        cif->flags = FFI_TYPE_INT;
317
      else
318
        cif->flags = cif->rtype->type;
319
      break;
320
 
321
    case FFI_TYPE_SINT64:
322
    case FFI_TYPE_UINT64:
323
      if (cif->abi == FFI_V9)
324
        cif->flags = FFI_TYPE_INT;
325
      else
326
        cif->flags = FFI_TYPE_SINT64;
327
      break;
328
 
329
    default:
330
      cif->flags = FFI_TYPE_INT;
331
      break;
332
    }
333
  return FFI_OK;
334
}
335
 
336
int ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt)
337
{
338
  ffi_type **ptr = &arg->elements[0];
339
 
340
  while (*ptr != NULL)
341
    {
342
      if (off & ((*ptr)->alignment - 1))
343
        off = ALIGN(off, (*ptr)->alignment);
344
 
345
      switch ((*ptr)->type)
346
        {
347
        case FFI_TYPE_STRUCT:
348
          off = ffi_v9_layout_struct(*ptr, off, ret, intg, flt);
349
          off = ALIGN(off, FFI_SIZEOF_ARG);
350
          break;
351
        case FFI_TYPE_FLOAT:
352
        case FFI_TYPE_DOUBLE:
353
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
354
        case FFI_TYPE_LONGDOUBLE:
355
#endif
356
          memmove(ret + off, flt + off, (*ptr)->size);
357
          off += (*ptr)->size;
358
          break;
359
        default:
360
          memmove(ret + off, intg + off, (*ptr)->size);
361
          off += (*ptr)->size;
362
          break;
363
        }
364
      ptr++;
365
    }
366
  return off;
367
}
368
 
369
 
370
#ifdef SPARC64
371
extern int ffi_call_v9(void *, extended_cif *, unsigned,
372
                       unsigned, unsigned *, void (*fn)(void));
373
#else
374
extern int ffi_call_v8(void *, extended_cif *, unsigned,
375
                       unsigned, unsigned *, void (*fn)(void));
376
#endif
377
 
378
void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
379
{
380
  extended_cif ecif;
381
  void *rval = rvalue;
382
 
383
  ecif.cif = cif;
384
  ecif.avalue = avalue;
385
 
386
  /* If the return value is a struct and we don't have a return */
387
  /* value address then we need to make one                     */
388
 
389
  ecif.rvalue = rvalue;
390
  if (cif->rtype->type == FFI_TYPE_STRUCT)
391
    {
392
      if (cif->rtype->size <= 32)
393
        rval = alloca(64);
394
      else
395
        {
396
          rval = NULL;
397
          if (rvalue == NULL)
398
            ecif.rvalue = alloca(cif->rtype->size);
399
        }
400
    }
401
 
402
  switch (cif->abi)
403
    {
404
    case FFI_V8:
405
#ifdef SPARC64
406
      /* We don't yet support calling 32bit code from 64bit */
407
      FFI_ASSERT(0);
408
#else
409
      ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes,
410
                  cif->flags, rvalue, fn);
411
#endif
412
      break;
413
    case FFI_V9:
414
#ifdef SPARC64
415
      ffi_call_v9(ffi_prep_args_v9, &ecif, cif->bytes,
416
                  cif->flags, rval, fn);
417
      if (rvalue && rval && cif->rtype->type == FFI_TYPE_STRUCT)
418
        ffi_v9_layout_struct(cif->rtype, 0, (char *)rvalue, (char *)rval, ((char *)rval)+32);
419
#else
420
      /* And vice versa */
421
      FFI_ASSERT(0);
422
#endif
423
      break;
424
    default:
425
      FFI_ASSERT(0);
426
      break;
427
    }
428
 
429
}
430
 
431
 
432
#ifdef SPARC64
433
extern void ffi_closure_v9(void);
434
#else
435
extern void ffi_closure_v8(void);
436
#endif
437
 
438
ffi_status
439
ffi_prep_closure_loc (ffi_closure* closure,
440
                      ffi_cif* cif,
441
                      void (*fun)(ffi_cif*, void*, void**, void*),
442
                      void *user_data,
443
                      void *codeloc)
444
{
445
  unsigned int *tramp = (unsigned int *) &closure->tramp[0];
446
  unsigned long fn;
447
#ifdef SPARC64
448
  /* Trampoline address is equal to the closure address.  We take advantage
449
     of that to reduce the trampoline size by 8 bytes. */
450
  FFI_ASSERT (cif->abi == FFI_V9);
451
  fn = (unsigned long) ffi_closure_v9;
452
  tramp[0] = 0x83414000; /* rd   %pc, %g1        */
453
  tramp[1] = 0xca586010;        /* ldx  [%g1+16], %g5   */
454
  tramp[2] = 0x81c14000;        /* jmp  %g5             */
455
  tramp[3] = 0x01000000;        /* nop                  */
456
  *((unsigned long *) &tramp[4]) = fn;
457
#else
458
  unsigned long ctx = (unsigned long) codeloc;
459
  FFI_ASSERT (cif->abi == FFI_V8);
460
  fn = (unsigned long) ffi_closure_v8;
461
  tramp[0] = 0x03000000 | fn >> 10;      /* sethi %hi(fn), %g1   */
462
  tramp[1] = 0x05000000 | ctx >> 10;    /* sethi %hi(ctx), %g2  */
463
  tramp[2] = 0x81c06000 | (fn & 0x3ff); /* jmp   %g1+%lo(fn)    */
464
  tramp[3] = 0x8410a000 | (ctx & 0x3ff);/* or    %g2, %lo(ctx)  */
465
#endif
466
 
467
  closure->cif = cif;
468
  closure->fun = fun;
469
  closure->user_data = user_data;
470
 
471
  /* Flush the Icache.  FIXME: alignment isn't certain, assume 8 bytes */
472
#ifdef SPARC64
473
  asm volatile ("flush  %0" : : "r" (closure) : "memory");
474
  asm volatile ("flush  %0" : : "r" (((char *) closure) + 8) : "memory");
475
#else
476
  asm volatile ("iflush %0" : : "r" (closure) : "memory");
477
  asm volatile ("iflush %0" : : "r" (((char *) closure) + 8) : "memory");
478
#endif
479
 
480
  return FFI_OK;
481
}
482
 
483
int
484
ffi_closure_sparc_inner_v8(ffi_closure *closure,
485
  void *rvalue, unsigned long *gpr, unsigned long *scratch)
486
{
487
  ffi_cif *cif;
488
  ffi_type **arg_types;
489
  void **avalue;
490
  int i, argn;
491
 
492
  cif = closure->cif;
493
  arg_types = cif->arg_types;
494
  avalue = alloca(cif->nargs * sizeof(void *));
495
 
496
  /* Copy the caller's structure return address so that the closure
497
     returns the data directly to the caller.  */
498
  if (cif->flags == FFI_TYPE_STRUCT
499
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE  
500
      || cif->flags == FFI_TYPE_LONGDOUBLE
501
#endif
502
     )
503
    rvalue = (void *) gpr[0];
504
 
505
  /* Always skip the structure return address.  */
506
  argn = 1;
507
 
508
  /* Grab the addresses of the arguments from the stack frame.  */
509
  for (i = 0; i < cif->nargs; i++)
510
    {
511
      if (arg_types[i]->type == FFI_TYPE_STRUCT
512
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
513
          || arg_types[i]->type == FFI_TYPE_LONGDOUBLE
514
#endif
515
         )
516
        {
517
          /* Straight copy of invisible reference.  */
518
          avalue[i] = (void *)gpr[argn++];
519
        }
520
      else if ((arg_types[i]->type == FFI_TYPE_DOUBLE
521
               || arg_types[i]->type == FFI_TYPE_SINT64
522
               || arg_types[i]->type == FFI_TYPE_UINT64)
523
               /* gpr is 8-byte aligned.  */
524
               && (argn % 2) != 0)
525
        {
526
          /* Align on a 8-byte boundary.  */
527
          scratch[0] = gpr[argn];
528
          scratch[1] = gpr[argn+1];
529
          avalue[i] = scratch;
530
          scratch -= 2;
531
          argn += 2;
532
        }
533
      else
534
        {
535
          /* Always right-justify.  */
536
          argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
537
          avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
538
        }
539
    }
540
 
541
  /* Invoke the closure.  */
542
  (closure->fun) (cif, rvalue, avalue, closure->user_data);
543
 
544
  /* Tell ffi_closure_sparc how to perform return type promotions.  */
545
  return cif->rtype->type;
546
}
547
 
548
int
549
ffi_closure_sparc_inner_v9(ffi_closure *closure,
550
  void *rvalue, unsigned long *gpr, double *fpr)
551
{
552
  ffi_cif *cif;
553
  ffi_type **arg_types;
554
  void **avalue;
555
  int i, argn, fp_slot_max;
556
 
557
  cif = closure->cif;
558
  arg_types = cif->arg_types;
559
  avalue = alloca(cif->nargs * sizeof(void *));
560
 
561
  /* Copy the caller's structure return address so that the closure
562
     returns the data directly to the caller.  */
563
  if (cif->flags == FFI_TYPE_VOID
564
      && cif->rtype->type == FFI_TYPE_STRUCT)
565
    {
566
      rvalue = (void *) gpr[0];
567
      /* Skip the structure return address.  */
568
      argn = 1;
569
    }
570
  else
571
    argn = 0;
572
 
573
  fp_slot_max = 16 - argn;
574
 
575
  /* Grab the addresses of the arguments from the stack frame.  */
576
  for (i = 0; i < cif->nargs; i++)
577
    {
578
      if (arg_types[i]->type == FFI_TYPE_STRUCT)
579
        {
580
          if (arg_types[i]->size > 16)
581
            {
582
              /* Straight copy of invisible reference.  */
583
              avalue[i] = (void *)gpr[argn++];
584
            }
585
          else
586
            {
587
              /* Left-justify.  */
588
              ffi_v9_layout_struct(arg_types[i],
589
                                   0,
590
                                   (char *) &gpr[argn],
591
                                   (char *) &gpr[argn],
592
                                   (char *) &fpr[argn]);
593
              avalue[i] = &gpr[argn];
594
              argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
595
            }
596
        }
597
      else
598
        {
599
          /* Right-justify.  */
600
          argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
601
 
602
          /* Align on a 16-byte boundary.  */
603
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
604
          if (arg_types[i]->type == FFI_TYPE_LONGDOUBLE && (argn % 2) != 0)
605
            argn++;
606
#endif
607
          if (i < fp_slot_max
608
              && (arg_types[i]->type == FFI_TYPE_FLOAT
609
                  || arg_types[i]->type == FFI_TYPE_DOUBLE
610
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
611
                  || arg_types[i]->type == FFI_TYPE_LONGDOUBLE
612
#endif
613
                  ))
614
            avalue[i] = ((char *) &fpr[argn]) - arg_types[i]->size;
615
          else
616
            avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
617
        }
618
    }
619
 
620
  /* Invoke the closure.  */
621
  (closure->fun) (cif, rvalue, avalue, closure->user_data);
622
 
623
  /* Tell ffi_closure_sparc how to perform return type promotions.  */
624
  return cif->rtype->type;
625
}

powered by: WebSVN 2.1.0

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