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

Subversion Repositories scarts

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

powered by: WebSVN 2.1.0

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