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

Subversion Repositories openrisc

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

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 732 jeremybenn
/* -----------------------------------------------------------------------
2
   ffi.c - Copyright (c) 2003, 2004, 2006, 2007 Kaz Kojima
3
           Copyright (c) 2008 Anthony Green
4
 
5
   SuperH SHmedia 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
 
33
#define NGREGARG 8
34
#define NFREGARG 12
35
 
36
static int
37
return_type (ffi_type *arg)
38
{
39
 
40
  if (arg->type != FFI_TYPE_STRUCT)
41
    return arg->type;
42
 
43
  /* gcc uses r2 if the result can be packed in on register.  */
44
  if (arg->size <= sizeof (UINT8))
45
    return FFI_TYPE_UINT8;
46
  else if (arg->size <= sizeof (UINT16))
47
    return FFI_TYPE_UINT16;
48
  else if (arg->size <= sizeof (UINT32))
49
    return FFI_TYPE_UINT32;
50
  else if (arg->size <= sizeof (UINT64))
51
    return FFI_TYPE_UINT64;
52
 
53
  return FFI_TYPE_STRUCT;
54
}
55
 
56
/* ffi_prep_args is called by the assembly routine once stack space
57
   has been allocated for the function's arguments */
58
 
59
void ffi_prep_args(char *stack, extended_cif *ecif)
60
{
61
  register unsigned int i;
62
  register unsigned int avn;
63
  register void **p_argv;
64
  register char *argp;
65
  register ffi_type **p_arg;
66
 
67
  argp = stack;
68
 
69
  if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
70
    {
71
      *(void **) argp = ecif->rvalue;
72
      argp += sizeof (UINT64);
73
    }
74
 
75
  avn = ecif->cif->nargs;
76
  p_argv = ecif->avalue;
77
 
78
  for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
79
    {
80
      size_t z;
81
      int align;
82
 
83
      z = (*p_arg)->size;
84
      align = (*p_arg)->alignment;
85
      if (z < sizeof (UINT32))
86
        {
87
          switch ((*p_arg)->type)
88
            {
89
            case FFI_TYPE_SINT8:
90
              *(SINT64 *) argp = (SINT64) *(SINT8 *)(*p_argv);
91
              break;
92
 
93
            case FFI_TYPE_UINT8:
94
              *(UINT64 *) argp = (UINT64) *(UINT8 *)(*p_argv);
95
              break;
96
 
97
            case FFI_TYPE_SINT16:
98
              *(SINT64 *) argp = (SINT64) *(SINT16 *)(*p_argv);
99
              break;
100
 
101
            case FFI_TYPE_UINT16:
102
              *(UINT64 *) argp = (UINT64) *(UINT16 *)(*p_argv);
103
              break;
104
 
105
            case FFI_TYPE_STRUCT:
106
              memcpy (argp, *p_argv, z);
107
              break;
108
 
109
            default:
110
              FFI_ASSERT(0);
111
            }
112
          argp += sizeof (UINT64);
113
        }
114
      else if (z == sizeof (UINT32) && align == sizeof (UINT32))
115
        {
116
          switch ((*p_arg)->type)
117
            {
118
            case FFI_TYPE_INT:
119
            case FFI_TYPE_SINT32:
120
              *(SINT64 *) argp = (SINT64) *(SINT32 *) (*p_argv);
121
              break;
122
 
123
            case FFI_TYPE_FLOAT:
124
            case FFI_TYPE_POINTER:
125
            case FFI_TYPE_UINT32:
126
            case FFI_TYPE_STRUCT:
127
              *(UINT64 *) argp = (UINT64) *(UINT32 *) (*p_argv);
128
              break;
129
 
130
            default:
131
              FFI_ASSERT(0);
132
              break;
133
            }
134
          argp += sizeof (UINT64);
135
        }
136
      else if (z == sizeof (UINT64)
137
               && align == sizeof (UINT64)
138
               && ((int) *p_argv & (sizeof (UINT64) - 1)) == 0)
139
        {
140
          *(UINT64 *) argp = *(UINT64 *) (*p_argv);
141
          argp += sizeof (UINT64);
142
        }
143
      else
144
        {
145
          int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
146
 
147
          memcpy (argp, *p_argv, z);
148
          argp += n * sizeof (UINT64);
149
        }
150
    }
151
 
152
  return;
153
}
154
 
155
/* Perform machine dependent cif processing */
156
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
157
{
158
  int i, j;
159
  int size, type;
160
  int n, m;
161
  int greg;
162
  int freg;
163
  int fpair = -1;
164
 
165
  greg = (return_type (cif->rtype) == FFI_TYPE_STRUCT ? 1 : 0);
166
  freg = 0;
167
  cif->flags2 = 0;
168
 
169
  for (i = j = 0; i < cif->nargs; i++)
170
    {
171
      type = (cif->arg_types)[i]->type;
172
      switch (type)
173
        {
174
        case FFI_TYPE_FLOAT:
175
          greg++;
176
          cif->bytes += sizeof (UINT64) - sizeof (float);
177
          if (freg >= NFREGARG - 1)
178
            continue;
179
          if (fpair < 0)
180
            {
181
              fpair = freg;
182
              freg += 2;
183
            }
184
          else
185
            fpair = -1;
186
          cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
187
          break;
188
 
189
        case FFI_TYPE_DOUBLE:
190
          if (greg++ >= NGREGARG && (freg + 1) >= NFREGARG)
191
            continue;
192
          if ((freg + 1) < NFREGARG)
193
            {
194
              freg += 2;
195
              cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
196
            }
197
          else
198
            cif->flags2 += FFI_TYPE_INT << (2 * j++);
199
          break;
200
 
201
        default:
202
          size = (cif->arg_types)[i]->size;
203
          if (size < sizeof (UINT64))
204
            cif->bytes += sizeof (UINT64) - size;
205
          n = (size + sizeof (UINT64) - 1) / sizeof (UINT64);
206
          if (greg >= NGREGARG)
207
            continue;
208
          else if (greg + n - 1 >= NGREGARG)
209
            greg = NGREGARG;
210
          else
211
            greg += n;
212
          for (m = 0; m < n; m++)
213
            cif->flags2 += FFI_TYPE_INT << (2 * j++);
214
          break;
215
        }
216
    }
217
 
218
  /* Set the return type flag */
219
  switch (cif->rtype->type)
220
    {
221
    case FFI_TYPE_STRUCT:
222
      cif->flags = return_type (cif->rtype);
223
      break;
224
 
225
    case FFI_TYPE_VOID:
226
    case FFI_TYPE_FLOAT:
227
    case FFI_TYPE_DOUBLE:
228
    case FFI_TYPE_SINT64:
229
    case FFI_TYPE_UINT64:
230
      cif->flags = cif->rtype->type;
231
      break;
232
 
233
    default:
234
      cif->flags = FFI_TYPE_INT;
235
      break;
236
    }
237
 
238
  return FFI_OK;
239
}
240
 
241
/*@-declundef@*/
242
/*@-exportheader@*/
243
extern void ffi_call_SYSV(void (*)(char *, extended_cif *),
244
                          /*@out@*/ extended_cif *,
245
                          unsigned, unsigned, long long,
246
                          /*@out@*/ unsigned *,
247
                          void (*fn)(void));
248
/*@=declundef@*/
249
/*@=exportheader@*/
250
 
251
void ffi_call(/*@dependent@*/ ffi_cif *cif,
252
              void (*fn)(void),
253
              /*@out@*/ void *rvalue,
254
              /*@dependent@*/ void **avalue)
255
{
256
  extended_cif ecif;
257
  UINT64 trvalue;
258
 
259
  ecif.cif = cif;
260
  ecif.avalue = avalue;
261
 
262
  /* If the return value is a struct and we don't have a return */
263
  /* value address then we need to make one                     */
264
 
265
  if (cif->rtype->type == FFI_TYPE_STRUCT
266
      && return_type (cif->rtype) != FFI_TYPE_STRUCT)
267
    ecif.rvalue = &trvalue;
268
  else if ((rvalue == NULL) &&
269
      (cif->rtype->type == FFI_TYPE_STRUCT))
270
    {
271
      ecif.rvalue = alloca(cif->rtype->size);
272
    }
273
  else
274
    ecif.rvalue = rvalue;
275
 
276
  switch (cif->abi)
277
    {
278
    case FFI_SYSV:
279
      ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, cif->flags2,
280
                    ecif.rvalue, fn);
281
      break;
282
    default:
283
      FFI_ASSERT(0);
284
      break;
285
    }
286
 
287
  if (rvalue
288
      && cif->rtype->type == FFI_TYPE_STRUCT
289
      && return_type (cif->rtype) != FFI_TYPE_STRUCT)
290
    memcpy (rvalue, &trvalue, cif->rtype->size);
291
}
292
 
293
extern void ffi_closure_SYSV (void);
294
extern void __ic_invalidate (void *line);
295
 
296
ffi_status
297
ffi_prep_closure_loc (ffi_closure *closure,
298
                      ffi_cif *cif,
299
                      void (*fun)(ffi_cif*, void*, void**, void*),
300
                      void *user_data,
301
                      void *codeloc)
302
{
303
  unsigned int *tramp;
304
 
305
  FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
306
 
307
  tramp = (unsigned int *) &closure->tramp[0];
308
  /* Since ffi_closure is an aligned object, the ffi trampoline is
309
     called as an SHcompact code.  Sigh.
310
     SHcompact part:
311
     mova @(1,pc),r0; add #1,r0; jmp @r0; nop;
312
     SHmedia part:
313
     movi fnaddr >> 16,r1; shori fnaddr,r1; ptabs/l r1,tr0
314
     movi cxt >> 16,r1; shori cxt,r1; blink tr0,r63  */
315
#ifdef __LITTLE_ENDIAN__
316
  tramp[0] = 0x7001c701;
317
  tramp[1] = 0x0009402b;
318
#else
319
  tramp[0] = 0xc7017001;
320
  tramp[1] = 0x402b0009;
321
#endif
322
  tramp[2] = 0xcc000010 | (((UINT32) ffi_closure_SYSV) >> 16) << 10;
323
  tramp[3] = 0xc8000010 | (((UINT32) ffi_closure_SYSV) & 0xffff) << 10;
324
  tramp[4] = 0x6bf10600;
325
  tramp[5] = 0xcc000010 | (((UINT32) codeloc) >> 16) << 10;
326
  tramp[6] = 0xc8000010 | (((UINT32) codeloc) & 0xffff) << 10;
327
  tramp[7] = 0x4401fff0;
328
 
329
  closure->cif = cif;
330
  closure->fun = fun;
331
  closure->user_data = user_data;
332
 
333
  /* Flush the icache.  */
334
  asm volatile ("ocbwb %0,0; synco; icbi %1,0; synci" : : "r" (tramp),
335
                "r"(codeloc));
336
 
337
  return FFI_OK;
338
}
339
 
340
/* Basically the trampoline invokes ffi_closure_SYSV, and on
341
 * entry, r3 holds the address of the closure.
342
 * After storing the registers that could possibly contain
343
 * parameters to be passed into the stack frame and setting
344
 * up space for a return value, ffi_closure_SYSV invokes the
345
 * following helper function to do most of the work.
346
 */
347
 
348
int
349
ffi_closure_helper_SYSV (ffi_closure *closure, UINT64 *rvalue,
350
                         UINT64 *pgr, UINT64 *pfr, UINT64 *pst)
351
{
352
  void **avalue;
353
  ffi_type **p_arg;
354
  int i, avn;
355
  int greg, freg;
356
  ffi_cif *cif;
357
  int fpair = -1;
358
 
359
  cif = closure->cif;
360
  avalue = alloca (cif->nargs * sizeof (void *));
361
 
362
  /* Copy the caller's structure return value address so that the closure
363
     returns the data directly to the caller.  */
364
  if (return_type (cif->rtype) == FFI_TYPE_STRUCT)
365
    {
366
      rvalue = (UINT64 *) *pgr;
367
      greg = 1;
368
    }
369
  else
370
    greg = 0;
371
 
372
  freg = 0;
373
  cif = closure->cif;
374
  avn = cif->nargs;
375
 
376
  /* Grab the addresses of the arguments from the stack frame.  */
377
  for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
378
    {
379
      size_t z;
380
      void *p;
381
 
382
      z = (*p_arg)->size;
383
      if (z < sizeof (UINT32))
384
        {
385
          p = pgr + greg++;
386
 
387
          switch ((*p_arg)->type)
388
            {
389
            case FFI_TYPE_SINT8:
390
            case FFI_TYPE_UINT8:
391
            case FFI_TYPE_SINT16:
392
            case FFI_TYPE_UINT16:
393
            case FFI_TYPE_STRUCT:
394
#ifdef __LITTLE_ENDIAN__
395
              avalue[i] = p;
396
#else
397
              avalue[i] = ((char *) p) + sizeof (UINT32) - z;
398
#endif
399
              break;
400
 
401
            default:
402
              FFI_ASSERT(0);
403
            }
404
        }
405
      else if (z == sizeof (UINT32))
406
        {
407
          if ((*p_arg)->type == FFI_TYPE_FLOAT)
408
            {
409
              if (freg < NFREGARG - 1)
410
                {
411
                  if (fpair >= 0)
412
                    {
413
                      avalue[i] = (UINT32 *) pfr + fpair;
414
                      fpair = -1;
415
                    }
416
                  else
417
                    {
418
#ifdef __LITTLE_ENDIAN__
419
                      fpair = freg;
420
                      avalue[i] = (UINT32 *) pfr + (1 ^ freg);
421
#else
422
                      fpair = 1 ^ freg;
423
                      avalue[i] = (UINT32 *) pfr + freg;
424
#endif
425
                      freg += 2;
426
                    }
427
                }
428
              else
429
#ifdef __LITTLE_ENDIAN__
430
                avalue[i] = pgr + greg;
431
#else
432
                avalue[i] = (UINT32 *) (pgr + greg) + 1;
433
#endif
434
            }
435
          else
436
#ifdef __LITTLE_ENDIAN__
437
            avalue[i] = pgr + greg;
438
#else
439
            avalue[i] = (UINT32 *) (pgr + greg) + 1;
440
#endif
441
          greg++;
442
        }
443
      else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
444
        {
445
          if (freg + 1 >= NFREGARG)
446
            avalue[i] = pgr + greg;
447
          else
448
            {
449
              avalue[i] = pfr + (freg >> 1);
450
              freg += 2;
451
            }
452
          greg++;
453
        }
454
      else
455
        {
456
          int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
457
 
458
          avalue[i] = pgr + greg;
459
          greg += n;
460
        }
461
    }
462
 
463
  (closure->fun) (cif, rvalue, avalue, closure->user_data);
464
 
465
  /* Tell ffi_closure_SYSV how to perform return type promotions.  */
466
  return return_type (cif->rtype);
467
}
468
 

powered by: WebSVN 2.1.0

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