Fix IA-64 problems with denorms getting clobbered by type conversions.
[official-gcc.git] / libffi / src / ia64 / ffi.c
blob77dec567284a01f2c049abed468d60426c019d3d
1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 1998 Red Hat, Inc.
3 Copyright (c) 2000 Hewlett Packard Company
5 IA64 Foreign Function Interface
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:
15 The above copyright notice and this permission notice shall be included
16 in all copies or substantial portions of the Software.
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 ----------------------------------------------------------------------- */
27 #include <ffi.h>
28 #include <ffi_common.h>
30 #include <stdlib.h>
31 #include <stdbool.h>
32 #include <float.h>
34 #include "ia64_flags.h"
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)));
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
46 UINT64 x[2] __attribute__((aligned(16)));
47 } fpreg;
50 /* The stack layout given to ffi_call_unix and ffi_closure_unix_inner. */
52 struct ia64_args
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. */
60 /* Adjust ADDR, a pointer to an 8 byte slot, to point to the low LEN bytes. */
62 static inline void *
63 endian_adjust (void *addr, size_t len)
65 #ifdef __BIG_ENDIAN__
66 return addr + (8 - len);
67 #else
68 return addr;
69 #endif
72 /* Store VALUE to ADDR in the current cpu implementation's fp spill format.
73 This is a macro instead of a function, so that it works for all 3 floating
74 point types without type conversions. Type conversion to long double breaks
75 the denorm support. */
77 #define stf_spill(addr, value) \
78 asm ("stf.spill %0 = %1%P0" : "=m" (*addr) : "f"(value));
80 /* Load a value from ADDR, which is in the current cpu implementation's
81 fp spill format. As above, this must also be a macro. */
83 #define ldf_fill(result, addr) \
84 asm ("ldf.fill %0 = %1%P1" : "=f"(result) : "m"(*addr));
86 /* Return the size of the C type associated with with TYPE. Which will
87 be one of the FFI_IA64_TYPE_HFA_* values. */
89 static size_t
90 hfa_type_size (int type)
92 switch (type)
94 case FFI_IA64_TYPE_HFA_FLOAT:
95 return sizeof(float);
96 case FFI_IA64_TYPE_HFA_DOUBLE:
97 return sizeof(double);
98 case FFI_IA64_TYPE_HFA_LDOUBLE:
99 return sizeof(__float80);
100 default:
101 abort ();
105 /* Load from ADDR a value indicated by TYPE. Which will be one of
106 the FFI_IA64_TYPE_HFA_* values. */
108 static void
109 hfa_type_load (fpreg *fpaddr, int type, void *addr)
111 switch (type)
113 case FFI_IA64_TYPE_HFA_FLOAT:
114 stf_spill (fpaddr, *(float *) addr);
115 return;
116 case FFI_IA64_TYPE_HFA_DOUBLE:
117 stf_spill (fpaddr, *(double *) addr);
118 return;
119 case FFI_IA64_TYPE_HFA_LDOUBLE:
120 stf_spill (fpaddr, *(__float80 *) addr);
121 return;
122 default:
123 abort ();
127 /* Load VALUE into ADDR as indicated by TYPE. Which will be one of
128 the FFI_IA64_TYPE_HFA_* values. */
130 static void
131 hfa_type_store (int type, void *addr, fpreg *fpaddr)
133 switch (type)
135 case FFI_IA64_TYPE_HFA_FLOAT:
137 float result;
138 ldf_fill (result, fpaddr);
139 *(float *) addr = result;
140 break;
142 case FFI_IA64_TYPE_HFA_DOUBLE:
144 double result;
145 ldf_fill (result, fpaddr);
146 *(double *) addr = result;
147 break;
149 case FFI_IA64_TYPE_HFA_LDOUBLE:
151 __float80 result;
152 ldf_fill (result, fpaddr);
153 *(__float80 *) addr = result;
154 break;
156 default:
157 abort ();
161 /* Is TYPE a struct containing floats, doubles, or extended doubles,
162 all of the same fp type? If so, return the element type. Return
163 FFI_TYPE_VOID if not. */
165 static int
166 hfa_element_type (ffi_type *type, int nested)
168 int element = FFI_TYPE_VOID;
170 switch (type->type)
172 case FFI_TYPE_FLOAT:
173 /* We want to return VOID for raw floating-point types, but the
174 synthetic HFA type if we're nested within an aggregate. */
175 if (nested)
176 element = FFI_IA64_TYPE_HFA_FLOAT;
177 break;
179 case FFI_TYPE_DOUBLE:
180 /* Similarly. */
181 if (nested)
182 element = FFI_IA64_TYPE_HFA_DOUBLE;
183 break;
185 case FFI_TYPE_LONGDOUBLE:
186 /* Similarly, except that that HFA is true for double extended,
187 but not quad precision. Both have sizeof == 16, so tell the
188 difference based on the precision. */
189 if (LDBL_MANT_DIG == 64 && nested)
190 element = FFI_IA64_TYPE_HFA_LDOUBLE;
191 break;
193 case FFI_TYPE_STRUCT:
195 ffi_type **ptr = &type->elements[0];
197 for (ptr = &type->elements[0]; *ptr ; ptr++)
199 int sub_element = hfa_element_type (*ptr, 1);
200 if (sub_element == FFI_TYPE_VOID)
201 return FFI_TYPE_VOID;
203 if (element == FFI_TYPE_VOID)
204 element = sub_element;
205 else if (element != sub_element)
206 return FFI_TYPE_VOID;
209 break;
211 default:
212 return FFI_TYPE_VOID;
215 return element;
219 /* Perform machine dependent cif processing. */
221 ffi_status
222 ffi_prep_cif_machdep(ffi_cif *cif)
224 int flags;
226 /* Adjust cif->bytes to include space for the bits of the ia64_args frame
227 that preceeds the integer register portion. The estimate that the
228 generic bits did for the argument space required is good enough for the
229 integer component. */
230 cif->bytes += offsetof(struct ia64_args, gp_regs[0]);
231 if (cif->bytes < sizeof(struct ia64_args))
232 cif->bytes = sizeof(struct ia64_args);
234 /* Set the return type flag. */
235 flags = cif->rtype->type;
236 switch (cif->rtype->type)
238 case FFI_TYPE_LONGDOUBLE:
239 /* Leave FFI_TYPE_LONGDOUBLE as meaning double extended precision,
240 and encode quad precision as a two-word integer structure. */
241 if (LDBL_MANT_DIG != 64)
242 flags = FFI_IA64_TYPE_SMALL_STRUCT | (16 << 8);
243 break;
245 case FFI_TYPE_STRUCT:
247 size_t size = cif->rtype->size;
248 int hfa_type = hfa_element_type (cif->rtype, 0);
250 if (hfa_type != FFI_TYPE_VOID)
252 size_t nelts = size / hfa_type_size (hfa_type);
253 if (nelts <= 8)
254 flags = hfa_type | (size << 8);
256 else
258 if (size <= 32)
259 flags = FFI_IA64_TYPE_SMALL_STRUCT | (size << 8);
262 break;
264 default:
265 break;
267 cif->flags = flags;
269 return FFI_OK;
272 extern int ffi_call_unix (struct ia64_args *, PTR64, void (*)(), UINT64);
274 void
275 ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
277 struct ia64_args *stack;
278 long i, avn, gpcount, fpcount;
279 ffi_type **p_arg;
281 FFI_ASSERT (cif->abi == FFI_UNIX);
283 /* If we have no spot for a return value, make one. */
284 if (rvalue == NULL && cif->rtype->type != FFI_TYPE_VOID)
285 rvalue = alloca (cif->rtype->size);
287 /* Allocate the stack frame. */
288 stack = alloca (cif->bytes);
290 gpcount = fpcount = 0;
291 avn = cif->nargs;
292 for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
294 switch ((*p_arg)->type)
296 case FFI_TYPE_SINT8:
297 stack->gp_regs[gpcount++] = *(SINT8 *)avalue[i];
298 break;
299 case FFI_TYPE_UINT8:
300 stack->gp_regs[gpcount++] = *(UINT8 *)avalue[i];
301 break;
302 case FFI_TYPE_SINT16:
303 stack->gp_regs[gpcount++] = *(SINT16 *)avalue[i];
304 break;
305 case FFI_TYPE_UINT16:
306 stack->gp_regs[gpcount++] = *(UINT16 *)avalue[i];
307 break;
308 case FFI_TYPE_SINT32:
309 stack->gp_regs[gpcount++] = *(SINT32 *)avalue[i];
310 break;
311 case FFI_TYPE_UINT32:
312 stack->gp_regs[gpcount++] = *(UINT32 *)avalue[i];
313 break;
314 case FFI_TYPE_SINT64:
315 case FFI_TYPE_UINT64:
316 stack->gp_regs[gpcount++] = *(UINT64 *)avalue[i];
317 break;
319 case FFI_TYPE_POINTER:
320 stack->gp_regs[gpcount++] = (UINT64)(PTR64) *(void **)avalue[i];
321 break;
323 case FFI_TYPE_FLOAT:
324 if (gpcount < 8 && fpcount < 8)
325 stf_spill (&stack->fp_regs[fpcount++], *(float *)avalue[i]);
326 stack->gp_regs[gpcount++] = *(UINT32 *)avalue[i];
327 break;
329 case FFI_TYPE_DOUBLE:
330 if (gpcount < 8 && fpcount < 8)
331 stf_spill (&stack->fp_regs[fpcount++], *(double *)avalue[i]);
332 stack->gp_regs[gpcount++] = *(UINT64 *)avalue[i];
333 break;
335 case FFI_TYPE_LONGDOUBLE:
336 if (gpcount & 1)
337 gpcount++;
338 if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
339 stf_spill (&stack->fp_regs[fpcount++], *(__float80 *)avalue[i]);
340 memcpy (&stack->gp_regs[gpcount], avalue[i], 16);
341 gpcount += 2;
342 break;
344 case FFI_TYPE_STRUCT:
346 size_t size = (*p_arg)->size;
347 size_t align = (*p_arg)->alignment;
348 int hfa_type = hfa_element_type (*p_arg, 0);
350 FFI_ASSERT (align <= 16);
351 if (align == 16 && (gpcount & 1))
352 gpcount++;
354 if (hfa_type != FFI_TYPE_VOID)
356 size_t hfa_size = hfa_type_size (hfa_type);
357 size_t offset = 0;
358 size_t gp_offset = gpcount * 8;
360 while (fpcount < 8
361 && offset < size
362 && gp_offset < 8 * 8)
364 hfa_type_load (&stack->fp_regs[fpcount], hfa_type,
365 avalue[i] + offset);
366 offset += hfa_size;
367 gp_offset += hfa_size;
368 fpcount += 1;
372 memcpy (&stack->gp_regs[gpcount], avalue[i], size);
373 gpcount += (size + 7) / 8;
375 break;
377 default:
378 abort ();
382 ffi_call_unix (stack, rvalue, fn, cif->flags);
385 /* Closures represent a pair consisting of a function pointer, and
386 some user data. A closure is invoked by reinterpreting the closure
387 as a function pointer, and branching to it. Thus we can make an
388 interpreted function callable as a C function: We turn the
389 interpreter itself, together with a pointer specifying the
390 interpreted procedure, into a closure.
392 For IA64, function pointer are already pairs consisting of a code
393 pointer, and a gp pointer. The latter is needed to access global
394 variables. Here we set up such a pair as the first two words of
395 the closure (in the "trampoline" area), but we replace the gp
396 pointer with a pointer to the closure itself. We also add the real
397 gp pointer to the closure. This allows the function entry code to
398 both retrieve the user data, and to restire the correct gp pointer. */
400 extern void ffi_closure_unix ();
402 ffi_status
403 ffi_prep_closure (ffi_closure* closure,
404 ffi_cif* cif,
405 void (*fun)(ffi_cif*,void*,void**,void*),
406 void *user_data)
408 /* The layout of a function descriptor. A C function pointer really
409 points to one of these. */
410 struct ia64_fd
412 UINT64 code_pointer;
413 UINT64 gp;
416 struct ffi_ia64_trampoline_struct
418 UINT64 code_pointer; /* Pointer to ffi_closure_unix. */
419 UINT64 fake_gp; /* Pointer to closure, installed as gp. */
420 UINT64 real_gp; /* Real gp value. */
423 struct ffi_ia64_trampoline_struct *tramp;
424 struct ia64_fd *fd;
426 FFI_ASSERT (cif->abi == FFI_UNIX);
428 tramp = (struct ffi_ia64_trampoline_struct *)closure->tramp;
429 fd = (struct ia64_fd *)(void *)ffi_closure_unix;
431 tramp->code_pointer = fd->code_pointer;
432 tramp->real_gp = fd->gp;
433 tramp->fake_gp = (UINT64)(PTR64)closure;
434 closure->cif = cif;
435 closure->user_data = user_data;
436 closure->fun = fun;
438 return FFI_OK;
442 UINT64
443 ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
444 void *rvalue, void *r8)
446 ffi_cif *cif;
447 void **avalue;
448 ffi_type **p_arg;
449 long i, avn, gpcount, fpcount;
451 cif = closure->cif;
452 avn = cif->nargs;
453 avalue = alloca (avn * sizeof (void *));
455 /* If the structure return value is passed in memory get that location
456 from r8 so as to pass the value directly back to the caller. */
457 if (cif->flags == FFI_TYPE_STRUCT)
458 rvalue = r8;
460 gpcount = fpcount = 0;
461 for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
463 switch ((*p_arg)->type)
465 case FFI_TYPE_SINT8:
466 case FFI_TYPE_UINT8:
467 avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 1);
468 break;
469 case FFI_TYPE_SINT16:
470 case FFI_TYPE_UINT16:
471 avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 2);
472 break;
473 case FFI_TYPE_SINT32:
474 case FFI_TYPE_UINT32:
475 avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 4);
476 break;
477 case FFI_TYPE_SINT64:
478 case FFI_TYPE_UINT64:
479 avalue[i] = &stack->gp_regs[gpcount++];
480 break;
481 case FFI_TYPE_POINTER:
482 avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], sizeof(void*));
483 break;
485 case FFI_TYPE_FLOAT:
486 if (gpcount < 8 && fpcount < 8)
488 fpreg *addr = &stack->fp_regs[fpcount++];
489 float result;
490 avalue[i] = addr;
491 ldf_fill (result, addr);
492 *(float *)addr = result;
494 else
495 avalue[i] = endian_adjust(&stack->gp_regs[gpcount], 4);
496 gpcount++;
497 break;
499 case FFI_TYPE_DOUBLE:
500 if (gpcount < 8 && fpcount < 8)
502 fpreg *addr = &stack->fp_regs[fpcount++];
503 double result;
504 avalue[i] = addr;
505 ldf_fill (result, addr);
506 *(double *)addr = result;
508 else
509 avalue[i] = &stack->gp_regs[gpcount];
510 gpcount++;
511 break;
513 case FFI_TYPE_LONGDOUBLE:
514 if (gpcount & 1)
515 gpcount++;
516 if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
518 fpreg *addr = &stack->fp_regs[fpcount++];
519 __float80 result;
520 avalue[i] = addr;
521 ldf_fill (result, addr);
522 *(__float80 *)addr = result;
524 else
525 avalue[i] = &stack->gp_regs[gpcount];
526 gpcount += 2;
527 break;
529 case FFI_TYPE_STRUCT:
531 size_t size = (*p_arg)->size;
532 size_t align = (*p_arg)->alignment;
533 int hfa_type = hfa_element_type (*p_arg, 0);
535 FFI_ASSERT (align <= 16);
536 if (align == 16 && (gpcount & 1))
537 gpcount++;
539 if (hfa_type != FFI_TYPE_VOID)
541 size_t hfa_size = hfa_type_size (hfa_type);
542 size_t offset = 0;
543 size_t gp_offset = gpcount * 8;
544 void *addr = alloca (size);
546 avalue[i] = addr;
548 while (fpcount < 8
549 && offset < size
550 && gp_offset < 8 * 8)
552 hfa_type_store (hfa_type, addr + offset,
553 &stack->fp_regs[fpcount]);
554 offset += hfa_size;
555 gp_offset += hfa_size;
556 fpcount += 1;
559 if (offset < size)
560 memcpy (addr + offset, (char *)stack->gp_regs + gp_offset,
561 size - offset);
563 else
564 avalue[i] = &stack->gp_regs[gpcount];
566 gpcount += (size + 7) / 8;
568 break;
570 default:
571 abort ();
575 closure->fun (cif, rvalue, avalue, closure->user_data);
577 return cif->flags;