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

Subversion Repositories openrisc

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

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

powered by: WebSVN 2.1.0

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