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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libffi/] [src/] [ia64/] [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) 1998 Red Hat, Inc.
3
           Copyright (c) 2000 Hewlett Packard Company
4
 
5
   IA64 Foreign Function Interface
6
 
7
   Permission is hereby granted, free of charge, to any person obtaining
8
   a copy of this software and associated documentation files (the
9
   ``Software''), to deal in the Software without restriction, including
10
   without limitation the rights to use, copy, modify, merge, publish,
11
   distribute, sublicense, and/or sell copies of the Software, and to
12
   permit persons to whom the Software is furnished to do so, subject to
13
   the following conditions:
14
 
15
   The above copyright notice and this permission notice shall be included
16
   in all copies or substantial portions of the Software.
17
 
18
   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
19
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21
   IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22
   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23
   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24
   OTHER DEALINGS IN THE SOFTWARE.
25
   ----------------------------------------------------------------------- */
26
 
27
#include <ffi.h>
28
#include <ffi_common.h>
29
 
30
#include <stdlib.h>
31
#include <stdbool.h>
32
#include <float.h>
33
 
34
#include "ia64_flags.h"
35
 
36
/* A 64-bit pointer value.  In LP64 mode, this is effectively a plain
37
   pointer.  In ILP32 mode, it's a pointer that's been extended to
38
   64 bits by "addp4".  */
39
typedef void *PTR64 __attribute__((mode(DI)));
40
 
41
/* Memory image of fp register contents.  This is the implementation
42
   specific format used by ldf.fill/stf.spill.  All we care about is
43
   that it wants a 16 byte aligned slot.  */
44
typedef struct
45
{
46
  UINT64 x[2] __attribute__((aligned(16)));
47
} fpreg;
48
 
49
 
50
/* The stack layout given to ffi_call_unix and ffi_closure_unix_inner.  */
51
 
52
struct ia64_args
53
{
54
  fpreg fp_regs[8];     /* Contents of 8 fp arg registers.  */
55
  UINT64 gp_regs[8];    /* Contents of 8 gp arg registers.  */
56
  UINT64 other_args[];  /* Arguments passed on stack, variable size.  */
57
};
58
 
59
 
60
/* Adjust ADDR, a pointer to an 8 byte slot, to point to the low LEN bytes.  */
61
 
62
static inline void *
63
endian_adjust (void *addr, size_t len)
64
{
65
#ifdef __BIG_ENDIAN__
66
  return addr + (8 - len);
67
#else
68
  return addr;
69
#endif
70
}
71
 
72
/* Store VALUE to ADDR in the current cpu implementation's fp spill format.  */
73
 
74
static inline void
75
stf_spill(fpreg *addr, __float80 value)
76
{
77
  asm ("stf.spill %0 = %1%P0" : "=m" (*addr) : "f"(value));
78
}
79
 
80
/* Load a value from ADDR, which is in the current cpu implementation's
81
   fp spill format.  */
82
 
83
static inline __float80
84
ldf_fill(fpreg *addr)
85
{
86
  __float80 ret;
87
  asm ("ldf.fill %0 = %1%P1" : "=f"(ret) : "m"(*addr));
88
  return ret;
89
}
90
 
91
/* Return the size of the C type associated with with TYPE.  Which will
92
   be one of the FFI_IA64_TYPE_HFA_* values.  */
93
 
94
static size_t
95
hfa_type_size (int type)
96
{
97
  switch (type)
98
    {
99
    case FFI_IA64_TYPE_HFA_FLOAT:
100
      return sizeof(float);
101
    case FFI_IA64_TYPE_HFA_DOUBLE:
102
      return sizeof(double);
103
    case FFI_IA64_TYPE_HFA_LDOUBLE:
104
      return sizeof(__float80);
105
    default:
106
      abort ();
107
    }
108
}
109
 
110
/* Load from ADDR a value indicated by TYPE.  Which will be one of
111
   the FFI_IA64_TYPE_HFA_* values.  */
112
 
113
static __float80
114
hfa_type_load (int type, void *addr)
115
{
116
  switch (type)
117
    {
118
    case FFI_IA64_TYPE_HFA_FLOAT:
119
      return *(float *) addr;
120
    case FFI_IA64_TYPE_HFA_DOUBLE:
121
      return *(double *) addr;
122
    case FFI_IA64_TYPE_HFA_LDOUBLE:
123
      return *(__float80 *) addr;
124
    default:
125
      abort ();
126
    }
127
}
128
 
129
/* Load VALUE into ADDR as indicated by TYPE.  Which will be one of
130
   the FFI_IA64_TYPE_HFA_* values.  */
131
 
132
static void
133
hfa_type_store (int type, void *addr, __float80 value)
134
{
135
  switch (type)
136
    {
137
    case FFI_IA64_TYPE_HFA_FLOAT:
138
      *(float *) addr = value;
139
      break;
140
    case FFI_IA64_TYPE_HFA_DOUBLE:
141
      *(double *) addr = value;
142
      break;
143
    case FFI_IA64_TYPE_HFA_LDOUBLE:
144
      *(__float80 *) addr = value;
145
      break;
146
    default:
147
      abort ();
148
    }
149
}
150
 
151
/* Is TYPE a struct containing floats, doubles, or extended doubles,
152
   all of the same fp type?  If so, return the element type.  Return
153
   FFI_TYPE_VOID if not.  */
154
 
155
static int
156
hfa_element_type (ffi_type *type, int nested)
157
{
158
  int element = FFI_TYPE_VOID;
159
 
160
  switch (type->type)
161
    {
162
    case FFI_TYPE_FLOAT:
163
      /* We want to return VOID for raw floating-point types, but the
164
         synthetic HFA type if we're nested within an aggregate.  */
165
      if (nested)
166
        element = FFI_IA64_TYPE_HFA_FLOAT;
167
      break;
168
 
169
    case FFI_TYPE_DOUBLE:
170
      /* Similarly.  */
171
      if (nested)
172
        element = FFI_IA64_TYPE_HFA_DOUBLE;
173
      break;
174
 
175
    case FFI_TYPE_LONGDOUBLE:
176
      /* Similarly, except that that HFA is true for double extended,
177
         but not quad precision.  Both have sizeof == 16, so tell the
178
         difference based on the precision.  */
179
      if (LDBL_MANT_DIG == 64 && nested)
180
        element = FFI_IA64_TYPE_HFA_LDOUBLE;
181
      break;
182
 
183
    case FFI_TYPE_STRUCT:
184
      {
185
        ffi_type **ptr = &type->elements[0];
186
 
187
        for (ptr = &type->elements[0]; *ptr ; ptr++)
188
          {
189
            int sub_element = hfa_element_type (*ptr, 1);
190
            if (sub_element == FFI_TYPE_VOID)
191
              return FFI_TYPE_VOID;
192
 
193
            if (element == FFI_TYPE_VOID)
194
              element = sub_element;
195
            else if (element != sub_element)
196
              return FFI_TYPE_VOID;
197
          }
198
      }
199
      break;
200
 
201
    default:
202
      return FFI_TYPE_VOID;
203
    }
204
 
205
  return element;
206
}
207
 
208
 
209
/* Perform machine dependent cif processing. */
210
 
211
ffi_status
212
ffi_prep_cif_machdep(ffi_cif *cif)
213
{
214
  int flags;
215
 
216
  /* Adjust cif->bytes to include space for the bits of the ia64_args frame
217
     that preceeds the integer register portion.  The estimate that the
218
     generic bits did for the argument space required is good enough for the
219
     integer component.  */
220
  cif->bytes += offsetof(struct ia64_args, gp_regs[0]);
221
  if (cif->bytes < sizeof(struct ia64_args))
222
    cif->bytes = sizeof(struct ia64_args);
223
 
224
  /* Set the return type flag. */
225
  flags = cif->rtype->type;
226
  switch (cif->rtype->type)
227
    {
228
    case FFI_TYPE_LONGDOUBLE:
229
      /* Leave FFI_TYPE_LONGDOUBLE as meaning double extended precision,
230
         and encode quad precision as a two-word integer structure.  */
231
      if (LDBL_MANT_DIG != 64)
232
        flags = FFI_IA64_TYPE_SMALL_STRUCT | (16 << 8);
233
      break;
234
 
235
    case FFI_TYPE_STRUCT:
236
      {
237
        size_t size = cif->rtype->size;
238
        int hfa_type = hfa_element_type (cif->rtype, 0);
239
 
240
        if (hfa_type != FFI_TYPE_VOID)
241
          {
242
            size_t nelts = size / hfa_type_size (hfa_type);
243
            if (nelts <= 8)
244
              flags = hfa_type | (size << 8);
245
          }
246
        else
247
          {
248
            if (size <= 32)
249
              flags = FFI_IA64_TYPE_SMALL_STRUCT | (size << 8);
250
          }
251
      }
252
      break;
253
 
254
    default:
255
      break;
256
    }
257
  cif->flags = flags;
258
 
259
  return FFI_OK;
260
}
261
 
262
extern int ffi_call_unix (struct ia64_args *, PTR64, void (*)(), UINT64);
263
 
264
void
265
ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
266
{
267
  struct ia64_args *stack;
268
  long i, avn, gpcount, fpcount;
269
  ffi_type **p_arg;
270
 
271
  FFI_ASSERT (cif->abi == FFI_UNIX);
272
 
273
  /* If we have no spot for a return value, make one.  */
274
  if (rvalue == NULL && cif->rtype->type != FFI_TYPE_VOID)
275
    rvalue = alloca (cif->rtype->size);
276
 
277
  /* Allocate the stack frame.  */
278
  stack = alloca (cif->bytes);
279
 
280
  gpcount = fpcount = 0;
281
  avn = cif->nargs;
282
  for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
283
    {
284
      switch ((*p_arg)->type)
285
        {
286
        case FFI_TYPE_SINT8:
287
          stack->gp_regs[gpcount++] = *(SINT8 *)avalue[i];
288
          break;
289
        case FFI_TYPE_UINT8:
290
          stack->gp_regs[gpcount++] = *(UINT8 *)avalue[i];
291
          break;
292
        case FFI_TYPE_SINT16:
293
          stack->gp_regs[gpcount++] = *(SINT16 *)avalue[i];
294
          break;
295
        case FFI_TYPE_UINT16:
296
          stack->gp_regs[gpcount++] = *(UINT16 *)avalue[i];
297
          break;
298
        case FFI_TYPE_SINT32:
299
          stack->gp_regs[gpcount++] = *(SINT32 *)avalue[i];
300
          break;
301
        case FFI_TYPE_UINT32:
302
          stack->gp_regs[gpcount++] = *(UINT32 *)avalue[i];
303
          break;
304
        case FFI_TYPE_SINT64:
305
        case FFI_TYPE_UINT64:
306
          stack->gp_regs[gpcount++] = *(UINT64 *)avalue[i];
307
          break;
308
 
309
        case FFI_TYPE_POINTER:
310
          stack->gp_regs[gpcount++] = (UINT64)(PTR64) *(void **)avalue[i];
311
          break;
312
 
313
        case FFI_TYPE_FLOAT:
314
          if (gpcount < 8 && fpcount < 8)
315
            stf_spill (&stack->fp_regs[fpcount++], *(float *)avalue[i]);
316
          stack->gp_regs[gpcount++] = *(UINT32 *)avalue[i];
317
          break;
318
 
319
        case FFI_TYPE_DOUBLE:
320
          if (gpcount < 8 && fpcount < 8)
321
            stf_spill (&stack->fp_regs[fpcount++], *(double *)avalue[i]);
322
          stack->gp_regs[gpcount++] = *(UINT64 *)avalue[i];
323
          break;
324
 
325
        case FFI_TYPE_LONGDOUBLE:
326
          if (gpcount & 1)
327
            gpcount++;
328
          if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
329
            stf_spill (&stack->fp_regs[fpcount++], *(__float80 *)avalue[i]);
330
          memcpy (&stack->gp_regs[gpcount], avalue[i], 16);
331
          gpcount += 2;
332
          break;
333
 
334
        case FFI_TYPE_STRUCT:
335
          {
336
            size_t size = (*p_arg)->size;
337
            size_t align = (*p_arg)->alignment;
338
            int hfa_type = hfa_element_type (*p_arg, 0);
339
 
340
            FFI_ASSERT (align <= 16);
341
            if (align == 16 && (gpcount & 1))
342
              gpcount++;
343
 
344
            if (hfa_type != FFI_TYPE_VOID)
345
              {
346
                size_t hfa_size = hfa_type_size (hfa_type);
347
                size_t offset = 0;
348
                size_t gp_offset = gpcount * 8;
349
 
350
                while (fpcount < 8
351
                       && offset < size
352
                       && gp_offset < 8 * 8)
353
                  {
354
                    stf_spill (&stack->fp_regs[fpcount],
355
                               hfa_type_load (hfa_type, avalue[i] + offset));
356
                    offset += hfa_size;
357
                    gp_offset += hfa_size;
358
                    fpcount += 1;
359
                  }
360
              }
361
 
362
            memcpy (&stack->gp_regs[gpcount], avalue[i], size);
363
            gpcount += (size + 7) / 8;
364
          }
365
          break;
366
 
367
        default:
368
          abort ();
369
        }
370
    }
371
 
372
  ffi_call_unix (stack, rvalue, fn, cif->flags);
373
}
374
 
375
/* Closures represent a pair consisting of a function pointer, and
376
   some user data.  A closure is invoked by reinterpreting the closure
377
   as a function pointer, and branching to it.  Thus we can make an
378
   interpreted function callable as a C function: We turn the
379
   interpreter itself, together with a pointer specifying the
380
   interpreted procedure, into a closure.
381
 
382
   For IA64, function pointer are already pairs consisting of a code
383
   pointer, and a gp pointer.  The latter is needed to access global
384
   variables.  Here we set up such a pair as the first two words of
385
   the closure (in the "trampoline" area), but we replace the gp
386
   pointer with a pointer to the closure itself.  We also add the real
387
   gp pointer to the closure.  This allows the function entry code to
388
   both retrieve the user data, and to restire the correct gp pointer.  */
389
 
390
extern void ffi_closure_unix ();
391
 
392
ffi_status
393
ffi_prep_closure (ffi_closure* closure,
394
                  ffi_cif* cif,
395
                  void (*fun)(ffi_cif*,void*,void**,void*),
396
                  void *user_data)
397
{
398
  /* The layout of a function descriptor.  A C function pointer really
399
     points to one of these.  */
400
  struct ia64_fd
401
  {
402
    UINT64 code_pointer;
403
    UINT64 gp;
404
  };
405
 
406
  struct ffi_ia64_trampoline_struct
407
  {
408
    UINT64 code_pointer;        /* Pointer to ffi_closure_unix.  */
409
    UINT64 fake_gp;             /* Pointer to closure, installed as gp.  */
410
    UINT64 real_gp;             /* Real gp value.  */
411
  };
412
 
413
  struct ffi_ia64_trampoline_struct *tramp;
414
  struct ia64_fd *fd;
415
 
416
  FFI_ASSERT (cif->abi == FFI_UNIX);
417
 
418
  tramp = (struct ffi_ia64_trampoline_struct *)closure->tramp;
419
  fd = (struct ia64_fd *)(void *)ffi_closure_unix;
420
 
421
  tramp->code_pointer = fd->code_pointer;
422
  tramp->real_gp = fd->gp;
423
  tramp->fake_gp = (UINT64)(PTR64)closure;
424
  closure->cif = cif;
425
  closure->user_data = user_data;
426
  closure->fun = fun;
427
 
428
  return FFI_OK;
429
}
430
 
431
 
432
UINT64
433
ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
434
                        void *rvalue, void *r8)
435
{
436
  ffi_cif *cif;
437
  void **avalue;
438
  ffi_type **p_arg;
439
  long i, avn, gpcount, fpcount;
440
 
441
  cif = closure->cif;
442
  avn = cif->nargs;
443
  avalue = alloca (avn * sizeof (void *));
444
 
445
  /* If the structure return value is passed in memory get that location
446
     from r8 so as to pass the value directly back to the caller.  */
447
  if (cif->flags == FFI_TYPE_STRUCT)
448
    rvalue = r8;
449
 
450
  gpcount = fpcount = 0;
451
  for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
452
    {
453
      switch ((*p_arg)->type)
454
        {
455
        case FFI_TYPE_SINT8:
456
        case FFI_TYPE_UINT8:
457
          avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 1);
458
          break;
459
        case FFI_TYPE_SINT16:
460
        case FFI_TYPE_UINT16:
461
          avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 2);
462
          break;
463
        case FFI_TYPE_SINT32:
464
        case FFI_TYPE_UINT32:
465
          avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 4);
466
          break;
467
        case FFI_TYPE_SINT64:
468
        case FFI_TYPE_UINT64:
469
          avalue[i] = &stack->gp_regs[gpcount++];
470
          break;
471
        case FFI_TYPE_POINTER:
472
          avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], sizeof(void*));
473
          break;
474
 
475
        case FFI_TYPE_FLOAT:
476
          if (gpcount < 8 && fpcount < 8)
477
            {
478
              void *addr = &stack->fp_regs[fpcount++];
479
              avalue[i] = addr;
480
              *(float *)addr = ldf_fill (addr);
481
            }
482
          else
483
            avalue[i] = endian_adjust(&stack->gp_regs[gpcount], 4);
484
          gpcount++;
485
          break;
486
 
487
        case FFI_TYPE_DOUBLE:
488
          if (gpcount < 8 && fpcount < 8)
489
            {
490
              void *addr = &stack->fp_regs[fpcount++];
491
              avalue[i] = addr;
492
              *(double *)addr = ldf_fill (addr);
493
            }
494
          else
495
            avalue[i] = &stack->gp_regs[gpcount];
496
          gpcount++;
497
          break;
498
 
499
        case FFI_TYPE_LONGDOUBLE:
500
          if (gpcount & 1)
501
            gpcount++;
502
          if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
503
            {
504
              void *addr = &stack->fp_regs[fpcount++];
505
              avalue[i] = addr;
506
              *(__float80 *)addr = ldf_fill (addr);
507
            }
508
          else
509
            avalue[i] = &stack->gp_regs[gpcount];
510
          gpcount += 2;
511
          break;
512
 
513
        case FFI_TYPE_STRUCT:
514
          {
515
            size_t size = (*p_arg)->size;
516
            size_t align = (*p_arg)->alignment;
517
            int hfa_type = hfa_element_type (*p_arg, 0);
518
 
519
            FFI_ASSERT (align <= 16);
520
            if (align == 16 && (gpcount & 1))
521
              gpcount++;
522
 
523
            if (hfa_type != FFI_TYPE_VOID)
524
              {
525
                size_t hfa_size = hfa_type_size (hfa_type);
526
                size_t offset = 0;
527
                size_t gp_offset = gpcount * 8;
528
                void *addr = alloca (size);
529
 
530
                avalue[i] = addr;
531
 
532
                while (fpcount < 8
533
                       && offset < size
534
                       && gp_offset < 8 * 8)
535
                  {
536
                    hfa_type_store (hfa_type, addr + offset,
537
                                    ldf_fill (&stack->fp_regs[fpcount]));
538
                    offset += hfa_size;
539
                    gp_offset += hfa_size;
540
                    fpcount += 1;
541
                  }
542
 
543
                if (offset < size)
544
                  memcpy (addr + offset, (char *)stack->gp_regs + gp_offset,
545
                          size - offset);
546
              }
547
            else
548
              avalue[i] = &stack->gp_regs[gpcount];
549
 
550
            gpcount += (size + 7) / 8;
551
          }
552
          break;
553
 
554
        default:
555
          abort ();
556
        }
557
    }
558
 
559
  closure->fun (cif, rvalue, avalue, closure->user_data);
560
 
561
  return cif->flags;
562
}

powered by: WebSVN 2.1.0

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