Home | History | Annotate | Download | only in ia64
      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 *
     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 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
    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
    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
    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