github.com/prattmic/llgo-embedded@v0.0.0-20150820070356-41cfecea0e1e/third_party/gofrontend/libffi/src/ia64/ffi.c (about)

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