1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 1998, 2007, 2008 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 *
endian_adjust(void * addr,size_t len)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
hfa_type_size(int type)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
hfa_type_load(fpreg * fpaddr,int type,void * addr)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
hfa_type_store(int type,void * addr,fpreg * fpaddr)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
hfa_element_type(ffi_type * type,int nested)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
ffi_prep_cif_machdep(ffi_cif * cif)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 preceeds 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
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)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 stack->gp_regs[gpcount++] = *(UINT32 *)avalue[i];
328 break;
329
330 case FFI_TYPE_DOUBLE:
331 if (gpcount < 8 && fpcount < 8)
332 stf_spill (&stack->fp_regs[fpcount++], *(double *)avalue[i]);
333 stack->gp_regs[gpcount++] = *(UINT64 *)avalue[i];
334 break;
335
336 case FFI_TYPE_LONGDOUBLE:
337 if (gpcount & 1)
338 gpcount++;
339 if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
340 stf_spill (&stack->fp_regs[fpcount++], *(__float80 *)avalue[i]);
341 memcpy (&stack->gp_regs[gpcount], avalue[i], 16);
342 gpcount += 2;
343 break;
344
345 case FFI_TYPE_STRUCT:
346 {
347 size_t size = (*p_arg)->size;
348 size_t align = (*p_arg)->alignment;
349 int hfa_type = hfa_element_type (*p_arg, 0);
350
351 FFI_ASSERT (align <= 16);
352 if (align == 16 && (gpcount & 1))
353 gpcount++;
354
355 if (hfa_type != FFI_TYPE_VOID)
356 {
357 size_t hfa_size = hfa_type_size (hfa_type);
358 size_t offset = 0;
359 size_t gp_offset = gpcount * 8;
360
361 while (fpcount < 8
362 && offset < size
363 && gp_offset < 8 * 8)
364 {
365 hfa_type_load (&stack->fp_regs[fpcount], hfa_type,
366 avalue[i] + offset);
367 offset += hfa_size;
368 gp_offset += hfa_size;
369 fpcount += 1;
370 }
371 }
372
373 memcpy (&stack->gp_regs[gpcount], avalue[i], size);
374 gpcount += (size + 7) / 8;
375 }
376 break;
377
378 default:
379 abort ();
380 }
381 }
382
383 ffi_call_unix (stack, rvalue, fn, cif->flags);
384 }
385
386 /* Closures represent a pair consisting of a function pointer, and
387 some user data. A closure is invoked by reinterpreting the closure
388 as a function pointer, and branching to it. Thus we can make an
389 interpreted function callable as a C function: We turn the
390 interpreter itself, together with a pointer specifying the
391 interpreted procedure, into a closure.
392
393 For IA64, function pointer are already pairs consisting of a code
394 pointer, and a gp pointer. The latter is needed to access global
395 variables. Here we set up such a pair as the first two words of
396 the closure (in the "trampoline" area), but we replace the gp
397 pointer with a pointer to the closure itself. We also add the real
398 gp pointer to the closure. This allows the function entry code to
399 both retrieve the user data, and to restire the correct gp pointer. */
400
401 extern void ffi_closure_unix ();
402
403 ffi_status
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)404 ffi_prep_closure_loc (ffi_closure* closure,
405 ffi_cif* cif,
406 void (*fun)(ffi_cif*,void*,void**,void*),
407 void *user_data,
408 void *codeloc)
409 {
410 /* The layout of a function descriptor. A C function pointer really
411 points to one of these. */
412 struct ia64_fd
413 {
414 UINT64 code_pointer;
415 UINT64 gp;
416 };
417
418 struct ffi_ia64_trampoline_struct
419 {
420 UINT64 code_pointer; /* Pointer to ffi_closure_unix. */
421 UINT64 fake_gp; /* Pointer to closure, installed as gp. */
422 UINT64 real_gp; /* Real gp value. */
423 };
424
425 struct ffi_ia64_trampoline_struct *tramp;
426 struct ia64_fd *fd;
427
428 FFI_ASSERT (cif->abi == FFI_UNIX);
429
430 tramp = (struct ffi_ia64_trampoline_struct *)closure->tramp;
431 fd = (struct ia64_fd *)(void *)ffi_closure_unix;
432
433 tramp->code_pointer = fd->code_pointer;
434 tramp->real_gp = fd->gp;
435 tramp->fake_gp = (UINT64)(PTR64)codeloc;
436 closure->cif = cif;
437 closure->user_data = user_data;
438 closure->fun = fun;
439
440 return FFI_OK;
441 }
442
443
444 UINT64
ffi_closure_unix_inner(ffi_closure * closure,struct ia64_args * stack,void * rvalue,void * r8)445 ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
446 void *rvalue, void *r8)
447 {
448 ffi_cif *cif;
449 void **avalue;
450 ffi_type **p_arg;
451 long i, avn, gpcount, fpcount;
452
453 cif = closure->cif;
454 avn = cif->nargs;
455 avalue = alloca (avn * sizeof (void *));
456
457 /* If the structure return value is passed in memory get that location
458 from r8 so as to pass the value directly back to the caller. */
459 if (cif->flags == FFI_TYPE_STRUCT)
460 rvalue = r8;
461
462 gpcount = fpcount = 0;
463 for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
464 {
465 switch ((*p_arg)->type)
466 {
467 case FFI_TYPE_SINT8:
468 case FFI_TYPE_UINT8:
469 avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 1);
470 break;
471 case FFI_TYPE_SINT16:
472 case FFI_TYPE_UINT16:
473 avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 2);
474 break;
475 case FFI_TYPE_SINT32:
476 case FFI_TYPE_UINT32:
477 avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 4);
478 break;
479 case FFI_TYPE_SINT64:
480 case FFI_TYPE_UINT64:
481 avalue[i] = &stack->gp_regs[gpcount++];
482 break;
483 case FFI_TYPE_POINTER:
484 avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], sizeof(void*));
485 break;
486
487 case FFI_TYPE_FLOAT:
488 if (gpcount < 8 && fpcount < 8)
489 {
490 fpreg *addr = &stack->fp_regs[fpcount++];
491 float result;
492 avalue[i] = addr;
493 ldf_fill (result, addr);
494 *(float *)addr = result;
495 }
496 else
497 avalue[i] = endian_adjust(&stack->gp_regs[gpcount], 4);
498 gpcount++;
499 break;
500
501 case FFI_TYPE_DOUBLE:
502 if (gpcount < 8 && fpcount < 8)
503 {
504 fpreg *addr = &stack->fp_regs[fpcount++];
505 double result;
506 avalue[i] = addr;
507 ldf_fill (result, addr);
508 *(double *)addr = result;
509 }
510 else
511 avalue[i] = &stack->gp_regs[gpcount];
512 gpcount++;
513 break;
514
515 case FFI_TYPE_LONGDOUBLE:
516 if (gpcount & 1)
517 gpcount++;
518 if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
519 {
520 fpreg *addr = &stack->fp_regs[fpcount++];
521 __float80 result;
522 avalue[i] = addr;
523 ldf_fill (result, addr);
524 *(__float80 *)addr = result;
525 }
526 else
527 avalue[i] = &stack->gp_regs[gpcount];
528 gpcount += 2;
529 break;
530
531 case FFI_TYPE_STRUCT:
532 {
533 size_t size = (*p_arg)->size;
534 size_t align = (*p_arg)->alignment;
535 int hfa_type = hfa_element_type (*p_arg, 0);
536
537 FFI_ASSERT (align <= 16);
538 if (align == 16 && (gpcount & 1))
539 gpcount++;
540
541 if (hfa_type != FFI_TYPE_VOID)
542 {
543 size_t hfa_size = hfa_type_size (hfa_type);
544 size_t offset = 0;
545 size_t gp_offset = gpcount * 8;
546 void *addr = alloca (size);
547
548 avalue[i] = addr;
549
550 while (fpcount < 8
551 && offset < size
552 && gp_offset < 8 * 8)
553 {
554 hfa_type_store (hfa_type, addr + offset,
555 &stack->fp_regs[fpcount]);
556 offset += hfa_size;
557 gp_offset += hfa_size;
558 fpcount += 1;
559 }
560
561 if (offset < size)
562 memcpy (addr + offset, (char *)stack->gp_regs + gp_offset,
563 size - offset);
564 }
565 else
566 avalue[i] = &stack->gp_regs[gpcount];
567
568 gpcount += (size + 7) / 8;
569 }
570 break;
571
572 default:
573 abort ();
574 }
575 }
576
577 closure->fun (cif, rvalue, avalue, closure->user_data);
578
579 return cif->flags;
580 }
581